如何用Android studio开发一个实现基本功能的新闻app?——简闻(源码及教程)
一、系统需求分析
启动程序后,通过登陆注册进行程序,能够进行新闻资讯的实时更新,点击新闻可以查看新闻的详细内容,在详情页点击收藏,能够将新闻添加到收藏列表中,再次点击,取消收藏,并可以通过个人信息页面设置个人的信息。
功能需求:
(1) 登陆注册
(2) 获取和更新新闻
(3) 收藏新闻
(4) 修改个人信息
应用界面:
Github地址:https://github.com/LIANYCL/SimpleNews
CSDN下载地址:https://download.csdn.net/download/weixin_45636641/12654845
二、系统总体设计
2.1 系统整体结构
源代码文件结构图:
2.2 数据存储设计
2.2.1用户信息E-R图
2.2.2 新闻数据E-R图
2.2.3 收藏数据E-R图
三、系统详细设计
3.1 注册功能
用户输入用户名,邮箱和密码,遍历用户表,若是用户名已存在或邮箱已注册,提醒用户重新输入,否则注册成功,返回登陆页面
3.2 登陆功能
将用户输入的用户名和密码,与数据库存储的用户表对比,完全正确则进入新闻页面
3.3 查看新闻列表
页面初始化时,向服务器请求数据,对请求到的的json数据进行解析,并包装成List,最后展示在新闻列表页面
3.4 新闻详情页面
展示新闻详情,增加一个收藏按钮,实现收藏新闻和取消收藏的功能,同步更新数据库
3.5 个人信息页面
实现修改个人信息,包括性别、居住城市和个性签名
3.6 我的收藏页面
展示收藏的新闻,点击可以查看新闻详情,并取消收藏
四、系统实现
4.1 注册功能
通过LitePal操作数据库,遍历用户表,判断用户名和密码是否正确
users = DataSupport.findAll(User.class);
register.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
for(User user: users){
if (registerName.getText().toString().equals(user.getName())||
registerMail.getText().toString().equals(user.getMail())){
flag = false;
break;
}
}
if (flag){
User user = new User();
//开始组装数据
user.setName(registerName.getText().toString());
user.setMail(registerMail.getText().toString());
user.setPassword(registerPass.getText().toString());
//保存数据
user.save();
Toast.makeText(Register.this, "注册成功", Toast.LENGTH_SHORT).show();
finish();
}else {
Toast.makeText(Register.this, "用户名或邮箱已存在!", Toast.LENGTH_SHORT).show();
}
}
});
4.2 登陆功能
//用户名和密码
name = (EditText) findViewById(R.id.login_name);
pass = (EditText) findViewById(R.id.login_password);
//登陆验证
Button login = (Button) findViewById(R.id.login_button);
login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
List<User> users = DataSupport.select("name","password").find(User.class);
if (!(TextUtils.isEmpty(name.getText().toString()))&&
!(TextUtils.isEmpty(pass.getText().toString()))){
for (User user:users){
if (name.getText().toString().equals(user.getName())
&& pass.getText().toString().equals(user.getPassword())){
Toast.makeText(MainActivity.this, "登陆成功", Toast.LENGTH_SHORT).show();
flag = false;
Intent intent = new Intent(MainActivity.this,Index.class);
intent.putExtra("username",name.getText().toString());
startActivity(intent);
}
}
if (flag){
Toast.makeText(MainActivity.this, "账户或密码错误!", Toast.LENGTH_SHORT).show();
}
}else {
Toast.makeText(MainActivity.this, "账号密码不能为空", Toast.LENGTH_SHORT).show();
}
}
});
//注册跳转
Button main_register = (Button) findViewById(R.id.main_register_button);
main_register.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,Register.class);
startActivity(intent);
}
});
}
4.3 查看新闻列表
4.3.1新闻列表的获取
//新闻列表的获取
lvNews = (ListView)findViewById(R.id.lvNews);
dataList = new ArrayList<Data>();
adapter = new NewsAdapter(this, dataList);
lvNews.setAdapter(adapter);
//点击列表项跳转页面
lvNews.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Data data = dataList.get(position);
Intent intent = new Intent(Index.this, BrowseNewsActivity.class);
intent.putExtra("title",data.getTitle());
intent.putExtra("author_name",data.getAuthorName());
intent.putExtra("date",data.getDate());
intent.putExtra("pic_url",data.getThumbnail_pic_s());
intent.putExtra("content_url", data.getUrl());
startActivity(intent);
}
});
sendRequestWithOKHttp();
//下拉刷新
swipeRefresh = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh);
swipeRefresh.setColorSchemeResources(R.color.colorPrimary);
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
sendRequestWithOKHttp();
}
});
}
4.3.2数据的解析
private void sendRequestWithOKHttp(){
new Thread(new Runnable() {
@Override
public void run() {
try {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://v.juhe.cn/toutiao/index?type=top&key=b646373d5b1b0d7628c7ae1bfae514d0")
.build();
Response response = null;
response = client.newCall(request).execute();
String responseData = response.body().string();
Log.d("测试:", responseData);
parseJsonWithGson(responseData);
} catch (IOException e) {
e.printStackTrace();
}
//更新Adapter(务必在主线程中更新UI!!!)
runOnUiThread(new Runnable() {
@Override
public void run() {
adapter.notifyDataSetChanged();
swipeRefresh.setRefreshing(false);
}
});
}
}).start();
}
private void parseJsonWithGson(String jsonData){
Gson gson = new Gson();
News news = gson.fromJson(jsonData, News.class);
List<Data> list = news.getResult().getData();
for (int i=0; i<list.size(); i++){
String uniquekey = list.get(i).getUniqueKey();
String title = list.get(i).getTitle();
String date = list.get(i).getDate();
String category = list.get(i).getCategory();
String author_name = list.get(i).getAuthorName();
String content_url = list.get(i).getUrl();
String pic_url = list.get(i).getThumbnail_pic_s();
dataList.add(new Data(uniquekey, title, date, category, author_name, content_url, pic_url));
}
}
4.4 新闻详情页面
//接收传来的数据
title = getIntent().getStringExtra("title");
author_name = getIntent().getStringExtra("author_name");
date = getIntent().getStringExtra("date");
pic_url = getIntent().getStringExtra("pic_url");
content_url = getIntent().getStringExtra("content_url");
num = getIntent().getIntExtra("num",1);
//初始化布局
Toolbar toolbar = (Toolbar) findViewById(R.id.browse_toolbar);
setSupportActionBar(toolbar);
browseDL = (DrawerLayout) findViewById(R.id.browse_drawer);
ActionBar actionBar = getSupportActionBar();
if (actionBar!=null){
actionBar.setDisplayHomeAsUpEnabled(true);
}
webView = (WebView)findViewById(R.id.webView);
webView.loadUrl(content_url);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
4.5 个人信息页面
4.5.1设置性别
//设置性别
info_gender.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new AlertDialog.Builder(Infomation.this).setTitle("请选择你的性别")
.setItems(gender, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
info_gender.setText(gender[which].toString());
User user_gender = new User();
user_gender.setGender(gender[which].toString());
user_gender.updateAll("name = ?",info_user);
}
}).show();
}
});
4.5.2设置城市
final String[] city = new String[]{
"广州市","深圳市","清远市","韶关市","河源市","梅州市","潮州市","肇庆市",
"云浮市","佛山市","东莞市","惠州市","汕尾市","揭阳市","汕头市","湛江市",
"茂名市","阳江市","江门市","中山市","珠海市 "
};
//设置城市
info_location.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new AlertDialog.Builder(Infomation.this).setTitle("请选择你的城市")
.setItems(city, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
info_location.setText(city[which].toString());
User user_location = new User();
user_location.setLocation(city[which].toString());
user_location.updateAll("name = ?",info_user);
}
}).show();
}
});
4.5.3编辑个性签名
final EditText motto = (EditText) findViewById(R.id.new_motto);
motto.setText(getIntent().getStringExtra("motto"));
final String alter_name = getIntent().getStringExtra("alter_name");
//修改个性签名
Button alter_motto = (Button) findViewById(R.id.alter_motto);
alter_motto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
User user_motto = new User();
user_motto.setMotto(motto.getText().toString());
user_motto.updateAll("name=?",alter_name);
finish();
}
});
}
4.6 收藏功能
使用奇偶数实现对新闻是否被收藏的状态进行判断
FAB = (FloatingActionButton) findViewById(R.id.float_collection);
if (num%2==0){
ColorStateList colorStateList = ContextCompat.getColorStateList(getApplicationContext(),R.color.colorPrimary);
FAB.setBackgroundTintList(colorStateList);
}
//收藏
news = DataSupport.findAll(Colltects.class);
FAB.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (num%2==1){
ColorStateList colorStateList = ContextCompat.getColorStateList(getApplicationContext(),R.color.colorPrimary);
FAB.setBackgroundTintList(colorStateList);
num++;
for (Colltects conew:news){
if (title.equals(conew.getTitle())&&author_name.equals(conew.getAuthor_name())){
flag = false;
Toast.makeText(BrowseNewsActivity.this, "已收藏", Toast.LENGTH_SHORT).show();
}
}
if (flag){
Colltects coll = new Colltects(title,author_name,date,content_url);
coll.save();
Toast.makeText(BrowseNewsActivity.this, "已收藏", Toast.LENGTH_SHORT).show();
}
}else {
ColorStateList colorStateList = ContextCompat.getColorStateList(getApplicationContext(),R.color.colorAccent);
FAB.setBackgroundTintList(colorStateList);
num++;
DataSupport.deleteAll(Colltects.class,"title = ? and author_name = ?",title,author_name);
Toast.makeText(BrowseNewsActivity.this, "取消收藏", Toast.LENGTH_SHORT).show();
}
}
});
五、结论与心得体会
遇到的问题:
- 编辑框的样式设计
通过网上搜索,才明白需要单独设置一个样式,再让编辑框或按钮使用这个样式,通过这样,可以便捷设置样式,减少代码的重复
- Json数据的解析
新闻数据的获取是通过聚合数据提供的,前期主要时间都花费在解析数据上,参考了几个案例,才明白的
- AlertDialog解决多页面
通过百度了解它的使用方法,使用它,实现对性别,城市等简单信息的设置,但是不知道如何使它拥有编辑框,最终只能采取,使用一个Activity来实现个性签名的设置
- 用户信息的同步
百度没找到方法,只能使用最笨的不断intent传递信息,效率低下,等后续学到了别的方法,再优化了
- 收藏按钮的颜色变化
网上的方法看不懂,最后通过奇偶数,对收藏状态进行简单判断,后设置按钮颜色,以及相应数据库的操作
心得体会:
遇到的问题:
- 编辑框的样式设计
通过网上搜索,才明白需要单独设置一个样式,再让编辑框或按钮使用这个样式,通过这样,可以便捷设置样式,减少代码的重复
- Json数据的解析
新闻数据的获取是通过聚合数据提供的,前期主要时间都花费在解析数据上,参考了几个案例,才明白的
- AlertDialog解决多页面
通过百度了解它的使用方法,使用它,实现对性别,城市等简单信息的设置,但是不知道如何使它拥有编辑框,最终只能采取,使用一个Activity来实现个性签名的设置
- 用户信息的同步
百度没找到方法,只能使用最笨的不断intent传递信息,效率低下,等后续学到了别的方法,再优化了
- 收藏按钮的颜色变化
网上的方法看不懂,最后通过奇偶数,对收藏状态进行简单判断,后设置按钮颜色,以及相应数据库的操作
心得体会:
通过这次实验体会到一个功能完善的app需要注意的事情太多了,各种同步,数据库操作,直接的关系,同时也明白现在所学的知识不够的。目前自己仍然停留在学会如何使用已经有的方法,一旦找不到相对应的解决方法,自己就无从下手,只能采用最笨的方式,同时对系统的整体架构设计,已经各种类应该具备怎么样的设计,这些都是未来需要好好学习提高的。
本文地址:https://blog.csdn.net/weixin_45636641/article/details/107535558