【第一部分】历史文章: Android学习笔记(一)——创建第一个Android项目 Android学习笔记(二)android studio基本控件及布局(实现图片查看器) Android学习笔记(三)android studio中CheckBox自定义样式(更换复选框左侧的勾选图像) Android学习笔记(四)Android 中Activity页面的跳转及传值 Android学习笔记(五)——Toast提示、Dialog对话框、Menu菜单 Android学习笔记(六)——自定义ListView布局+AsyncTask异步任务 Android学习笔记(七)——数据存储(共享参数SharedPreferences) Android学习笔记(八)——数据存储(SD卡文件操作) Android学习笔记(九)——网络技术 Android学习笔记(十)——实现新闻列表案例 Android学习笔记(十一)——一些高级控件的使用 Android学习笔记(十二)——数据存储(SQLite数据库) Android学习笔记(十三)——数据存储(LitePal操作数据库) Android学习笔记(十四)——内容提供器 Android学习笔记(十五)——侧滑容器(ViewPager) 【第二部分】主要问题解决: Android Studio(存)读取不了SD卡上的文件——【已解决】 【第三部分】期末项目: Android期末项目(一)—— 解析二维数组对象 Android期末项目(二)——欢迎界面(实现倒计时+点击跳转+判断是否登录)
Android期末大作业——今日头条
一、主要的功能介绍
| 模块 | 主要功能 | 相关描述 |
|---|---|---|
| 登录、注册页面 | LitePal操作数据库 | 数据的插入、查询操作;数据校验 |
| 引导首页 | 封面展示+倒计时进入 | 定时器 |
| 首页导航 | 共四个板块—主页、西瓜视频、系统设置、我的 | 对应四个碎片 |
| 主页 | 共五个板块—推荐、国内、体育、社会、军事 | 对应五个碎片分别显示不同类别的新闻 |
| 西瓜视频 | 播放视频 | |
| 系统设置 | 我的消息、清理缓存、头条封面、头条热榜等 | 通知、访问网络接口、数据解析 |
| 我的 | 扫一扫、上传头像、账号管理、我的收藏、个人资料、登录等操作 |更改密码、收藏新闻展示、个人资料的设置 |发布按钮|进行拍照 |使用多媒体 |上传头像|选择相册| | 底部弹出框 | 个人资料中使用 |有相应的字数限制,城市选择三级联动等 |权限设置|用户未登录的状态 |查看相关新闻、头像框显示未登录、账号管理、我的收藏、个人资料,只有登录后才可访问、用户不可评论与收藏 |验证码| 注册的时候|进行判断用户输入的验证码是否与生成的一致 |用户登录成功后|可以进行一系列的操作|更改个人资料,收藏新闻、评论、查看收藏、评论等 | | |
二、准备工作
用到的接口:头条新闻数据、头条热榜。
https://api.storeapi.net/api/68/177?format=json&weibo_top=1594&appid=2307&sign=
注:接口可以到聚合数据去申请。
(一)头条新闻接口数据分析:
- uniquekey :唯一标识
- title :新闻标题
- date :时间
- category :新闻类别
- author_name :新闻名称
- url :新闻具体内容url
- thumbnail_pic_s :新闻图片url
注:type取值(正好头部可以显示不同类别的新闻!!!)
1top yule tiyu caijing guoji guonei junshi keji shehui shishang
注:下面是使用Postman测试的接口数据
(二)头条热榜接口数据分析:
- w_time:时间
- w_key:关键词
- w_hot:相关数据
- w_label:标签
注:下面是使用Postman测试的接口数据
注:对该接口数据进行数据解析:请参考Android期末项目(一)—— 解析二维数组对象
三、用到的数据存储
- 登录、注册:使用的是LitePal
- 收藏新闻:使用的是SQLite
- 记住密码:sharepreference
- 保存用户信息:sharepreference(用户显示用户名、权限的判断)
- 保存个人资料信息:使用的是LitePal
- 新闻评论:使用的是LitePal
(1)登录、注册操作。
- 注册:填入用户名、密码、确认密码、验证码,进行注册。
- 登录:判断用户名是否已经注册、没有注册的话,写入数据库。
(2)收藏新闻。
- 用户点击新闻展示页面中的收藏按钮,进行新闻的收藏。
- 进行插入数据库(新闻标题、新闻具体url、时间、新闻来源、图片的url)。
(3)保存个人资料信息。
- 插入数据库信息(用户名、昵称、介绍、性别、地区等)
四、主页设计(展示新闻列表)
4.1、使用的主要控件:
- FrameLayout (碎片,各类新闻的切换)
- ImageView (底部导航的图片)
- TextView(底部的导航标题)
发生的事情:显示新闻列表——>点每一个新闻列表中的删除图标——>对话框弹出(问你:确定删除吗?)——>确定的话(该条新闻从数据源中移出)——>点击每一条新闻——>跳到新闻详情页面——>在新闻详情页面对新闻进行收藏操作(涉及到页面之间的传值,存数据库操作)——>为后面的查看收藏做好准备!!!
4.2、推荐碎片:推荐类新闻的实现fragment_tuijian.xml
1、在fragment_tuijian.xml中添加ListView。
2、列表项使用的主要控件。(共6个)
- TextView :显示新闻标题、新闻的来源、新闻的时间。
- ImageView:显示新闻的图片、删除图标图片。
- View :列表项与列表项之间的水平横线。
1水平横线的设计: 2 <View 3 android:layout_width="match_parent" 4 android:layout_height="1dp" 5 android:background="#DCDCDC" />
3、具体实现,参考老师上课的那个(第六课)——其实没有什么区别!!!
4.3、以上用到的知识点:
- 布局的设计
- ListView列表的应用(三要素:数据源、控件、数据适配器)
- json数据解析(用的是上课时讲的那种方式)
- 活动之间的跳转及传值
- OkHttp访问网络
- AsyncTask异步任务
- FrameLayout的使用(参考老师的那个:这是财经新闻。。。的那个案例!!!)
- WebView展示新闻详情页面 等等吧!!!
4.4、点击新闻跳转到新闻详情页面
- 点击新闻列表中的每一项后,进行跳转页面;把新闻的标题、新闻具体内容url、时间、新闻来源、图片url等数据传递。
- 在新闻详情页面,进行获取到以上传过去的值,用
WebView显示新闻的具体内容。 - 在新闻详情页面中,添加收藏按钮。
4.5、新闻详情页面点击收藏图标(用户登录后)
- 当点击收藏按钮时,插入数据库,这里用的时
SQLite的方式。 - 插入数据库的目的,用户在我的板块可以查看所收藏的新闻。
4.6、新闻的评论(用户登录后)
在新闻详情页中,输入评论内容,点击发送按钮,即可评论。
4.7、点击右上角的发布按钮
- 点击后,从底部弹出页面栏,点击拍小视频,可以打开相机。
4.8、其他
对于不同的类别的新闻展示,其实具体代码与推荐类的新闻代码一样,只需要把新闻接口的type属性改下即可。

五、西瓜视频设计(展示视频列表)
部分关键代码:

六、系统设置设计
- 我的消息 :(Notification通知相关的使用)
- 清理缓存
- 夜间模式
- H5广告过滤
- 头条封面 (跳到引导页面)
- 广告设置 :
- 头条热榜 :访问网络接口进行展示
- 我的发现
6.1、清理缓存 点击清理缓存按钮:
1im_qinglihuancun.setOnClickListener(new View.OnClickListener() { 2 @Override 3 public void onClick(View v) { 4 try{ 5 String size = ClearCache.getTotalCacheSize(getContext()); 6 ClearCache.clearAllCache(getContext()); 7 Toast.makeText(getContext(), size + "缓存清除完成", Toast.LENGTH_SHORT).show(); 8 9 }catch (Exception e){ 10 e.printStackTrace(); 11 } 12 } 13 });
ClearCache.java
1package cn.edu.hznu.com.utils; 2import android.content.Context; 3import android.os.Environment; 4import java.io.File; 5import java.math.BigDecimal; 6public class ClearCache { 7 /** 8 * 获取缓存大小 9 * @param context 10 * @return 11 * @throws Exception 12 */ 13 public static String getTotalCacheSize(Context context) throws Exception { 14 long cacheSize = getFolderSize(context.getCacheDir()); 15 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 16 cacheSize += getFolderSize(context.getExternalCacheDir()); 17 } 18 return getFormatSize(cacheSize); 19 } 20 21 /*** 22 * 清理所有缓存 23 * @param context 24 */ 25 public static void clearAllCache(Context context) { 26 deleteDir(context.getCacheDir()); 27 if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { 28 deleteDir(context.getExternalCacheDir()); 29 } 30 } 31 32 private static boolean deleteDir(File dir) { 33 if (dir != null && dir.isDirectory()) { 34 String[] children = dir.list(); 35 for (int i = 0; i < children.length; i++) { 36 boolean success = deleteDir(new File(dir, children[i])); 37 if (!success) { 38 return false; 39 } 40 } 41 } 42 return dir.delete(); 43 } 44 45 // 获取文件 46 //Context.getExternalFilesDir() --> SDCard/Android/data/你的应用的包名/files/ 目录,一般放一些长时间保存的数据 47 //Context.getExternalCacheDir() --> SDCard/Android/data/你的应用包名/cache/目录,一般存放临时缓存数据 48 public static long getFolderSize(File file) throws Exception { 49 long size = 0; 50 try { 51 File[] fileList = file.listFiles(); 52 for (int i = 0; i < fileList.length; i++) { 53 // 如果下面还有文件 54 if (fileList[i].isDirectory()) { 55 size = size + getFolderSize(fileList[i]); 56 } else { 57 size = size + fileList[i].length(); 58 } 59 } 60 } catch (Exception e) { 61 e.printStackTrace(); 62 } 63 return size; 64 } 65 66 /** 67 * 格式化单位 68 * 69 * @param size 70 * @return 71 */ 72 public static String getFormatSize(double size) { 73 double kiloByte = size / 1024; 74 if (kiloByte < 1) { 75// return size + "Byte"; 76 return "0K"; 77 } 78 79 double megaByte = kiloByte / 1024; 80 if (megaByte < 1) { 81 BigDecimal result1 = new BigDecimal(Double.toString(kiloByte)); 82 return result1.setScale(2, BigDecimal.ROUND_HALF_UP) 83 .toPlainString() + "KB"; 84 } 85 86 double gigaByte = megaByte / 1024; 87 if (gigaByte < 1) { 88 BigDecimal result2 = new BigDecimal(Double.toString(megaByte)); 89 return result2.setScale(2, BigDecimal.ROUND_HALF_UP) 90 .toPlainString() + "MB"; 91 } 92 93 double teraBytes = gigaByte / 1024; 94 if (teraBytes < 1) { 95 BigDecimal result3 = new BigDecimal(Double.toString(gigaByte)); 96 return result3.setScale(2, BigDecimal.ROUND_HALF_UP) 97 .toPlainString() + "GB"; 98 } 99 BigDecimal result4 = new BigDecimal(teraBytes); 100 return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() 101 + "TB"; 102 } 103 104}
七、我的设计
- 头像上传
- 扫一扫
1Intent intent = new Intent(); 2intent.setComponent(new ComponentName("com.tencent.mm", "com.tencent.mm.ui.LauncherUI")); 3intent.putExtra("LauncherUI.From.Scaner.Shortcut", true); 4intent.setFlags(335544320); 5intent.setAction("android.intent.action.VIEW"); 6getContext().startActivity(intent);
- 账号管理 进行密码更改的操作
- 我的收藏 展示收藏的新闻数据
1 SQLiteDatabase db = myDatabaseHelper.getReadableDatabase(); 2 Cursor cursor = db.rawQuery("select * from coll_news_table", null); 3 if (cursor.getCount() != 0) { 4 if (cursor.moveToFirst()) { 5 do { 6 String title = cursor.getString(cursor.getColumnIndex("title")); 7 String date = cursor.getString(cursor.getColumnIndex("date")); 8 String author = cursor.getString(cursor.getColumnIndex("author")); 9 String imgurl = cursor.getString(cursor.getColumnIndex("imgurl")); 10 String url = cursor.getString(cursor.getColumnIndex("url")); 11 News news = new News(imgurl, title, url, date, author); 12 list.add(news); 13 } while (cursor.moveToNext());
- 个人资料 用户名、昵称、介绍、性别、地区。 在介绍添加了 输入字数的限制功能(20字以内):
1 ed_jieshao.addTextChangedListener(new TextWatcher() { 2 private CharSequence wordNum;//记录输入的字数 3 private int selectionStart; 4 private int selectionEnd; 5 private int num=20; 6 @Override 7 public void beforeTextChanged(CharSequence s, int start, int count, int after) {} 8 @Override 9 public void onTextChanged(CharSequence s, int start, int before, int count) { 10 wordNum= s;//实时记录输入的字数 11 } 12 @Override 13 public void afterTextChanged(Editable s) { 14 int number = num - s.length(); 15 //TextView显示剩余字数 16 ed_zishu.setText("剩余" + number+"字"); 17 selectionStart=ed_jieshao.getSelectionStart(); 18 selectionEnd = ed_jieshao.getSelectionEnd(); 19 if (wordNum.length() > num) { 20 //删除多余输入的字(不会显示出来) 21 s.delete(selectionStart - 1, selectionEnd); 22 int tempSelection = selectionEnd; 23 ed_jieshao.setText(s); 24 ed_jieshao.setSelection(tempSelection);//设置光标在最后 25 } 26 } 27 });
- 版本升级
1 AlertDialog.Builder builder=new AlertDialog.Builder(getContext()); //创建一个AlertDialog的构造器 2 builder.setIcon(R.drawable.tanhao); //设置图标 3 builder.setTitle("温馨提示"); //设置标题 4 builder.setMessage("当前已是最新版本"); //设置消息内容 5 builder.create().show();
- 退出登录
八、遇到的问题
在使用前面第二个数据接口的时候,数据解析一直报错,出现空指针异常。得不到数据。
通过询问老师:最终得到了解决方案😀,数据成功显示。
九、总结
通过本学期的Android课程的学习,基本掌握了Android应用程序的开发的一般流程,对常用的控件基本掌握及用法,对其事件的监听方法也基本掌握。学习Android不仅是对前沿开发技术的了解,也是对编程知识的一次提升。
十、项目效果

<hr>若文章中有错误的地方欢迎大家反馈或者留言,十分感谢!!! 源码获取:关注下方微信公众号即可获取。
个人博客:https://blog.csdn.net/weixin_43759352 微信公众号:【小小开发者】
