【第一部分】歷史文章:
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操作數據庫 | 數據的插入、查詢操作;數據校驗 |
引導首頁 | 封面展示+倒計時進入 | 定時器 |
首頁導航 | 共四個板塊—主頁、西瓜視頻、系統設置、我的 | 對應四個碎片 |
主頁 | 共五個板塊—推薦、國內、體育、社會、軍事 | 對應五個碎片分別顯示不同類別的新聞 |
西瓜視頻 | 播放視頻 | |
系統設置 | 我的消息、清理緩存、頭條封面、頭條熱榜等 | 通知、訪問網絡接口、數據解析 |
我的 | 掃一掃、上傳頭像、賬號管理、我的收藏、個人資料、登錄等操作 | 更改密碼、收藏新聞展示、個人資料的設置 |
發佈按鈕 | 進行拍照 | 使用多媒體 |
上傳頭像 | 選擇相冊 | |
底部彈出框 | 個人資料中使用 | 有相應的字數限制,城市選擇三級聯動等 |
權限設置 | 用戶未登錄的狀態 | 查看相關新聞、頭像框顯示未登錄、賬號管理、我的收藏、個人資料,只有登錄後纔可訪問、用戶不可評論與收藏 |
驗證碼 | 註冊的時候 | 進行判斷用戶輸入的驗證碼是否與生成的一致 |
用戶登錄成功後 | 可以進行一系列的操作 | 更改個人資料,收藏新聞、評論、查看收藏、評論等 |
二、準備工作
用到的接口:頭條新聞數據、頭條熱榜。
http://v.juhe.cn/toutiao/index?type=top&key=
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取值(正好頭部可以顯示不同類別的新聞!!!)
top 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 :列表項與列表項之間的水平橫線。
水平橫線的設計:
<View
android:layout_width="match_parent"
android:layout_height="1dp"
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、清理緩存
點擊清理緩存按鈕:
im_qinglihuancun.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try{
String size = ClearCache.getTotalCacheSize(getContext());
ClearCache.clearAllCache(getContext());
Toast.makeText(getContext(), size + "緩存清除完成", Toast.LENGTH_SHORT).show();
}catch (Exception e){
e.printStackTrace();
}
}
});
ClearCache.java
package cn.edu.hznu.com.utils;
import android.content.Context;
import android.os.Environment;
import java.io.File;
import java.math.BigDecimal;
public class ClearCache {
/**
* 獲取緩存大小
* @param context
* @return
* @throws Exception
*/
public static String getTotalCacheSize(Context context) throws Exception {
long cacheSize = getFolderSize(context.getCacheDir());
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
cacheSize += getFolderSize(context.getExternalCacheDir());
}
return getFormatSize(cacheSize);
}
/***
* 清理所有緩存
* @param context
*/
public static void clearAllCache(Context context) {
deleteDir(context.getCacheDir());
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
deleteDir(context.getExternalCacheDir());
}
}
private static boolean deleteDir(File dir) {
if (dir != null && dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
return dir.delete();
}
// 獲取文件
//Context.getExternalFilesDir() --> SDCard/Android/data/你的應用的包名/files/ 目錄,一般放一些長時間保存的數據
//Context.getExternalCacheDir() --> SDCard/Android/data/你的應用包名/cache/目錄,一般存放臨時緩存數據
public static long getFolderSize(File file) throws Exception {
long size = 0;
try {
File[] fileList = file.listFiles();
for (int i = 0; i < fileList.length; i++) {
// 如果下面還有文件
if (fileList[i].isDirectory()) {
size = size + getFolderSize(fileList[i]);
} else {
size = size + fileList[i].length();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return size;
}
/**
* 格式化單位
*
* @param size
* @return
*/
public static String getFormatSize(double size) {
double kiloByte = size / 1024;
if (kiloByte < 1) {
// return size + "Byte";
return "0K";
}
double megaByte = kiloByte / 1024;
if (megaByte < 1) {
BigDecimal result1 = new BigDecimal(Double.toString(kiloByte));
return result1.setScale(2, BigDecimal.ROUND_HALF_UP)
.toPlainString() + "KB";
}
double gigaByte = megaByte / 1024;
if (gigaByte < 1) {
BigDecimal result2 = new BigDecimal(Double.toString(megaByte));
return result2.setScale(2, BigDecimal.ROUND_HALF_UP)
.toPlainString() + "MB";
}
double teraBytes = gigaByte / 1024;
if (teraBytes < 1) {
BigDecimal result3 = new BigDecimal(Double.toString(gigaByte));
return result3.setScale(2, BigDecimal.ROUND_HALF_UP)
.toPlainString() + "GB";
}
BigDecimal result4 = new BigDecimal(teraBytes);
return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString()
+ "TB";
}
}
七、我的設計
- 頭像上傳
- 掃一掃
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.tencent.mm", "com.tencent.mm.ui.LauncherUI"));
intent.putExtra("LauncherUI.From.Scaner.Shortcut", true);
intent.setFlags(335544320);
intent.setAction("android.intent.action.VIEW");
getContext().startActivity(intent);
- 賬號管理
進行密碼更改的操作 - 我的收藏
展示收藏的新聞數據
SQLiteDatabase db = myDatabaseHelper.getReadableDatabase();
Cursor cursor = db.rawQuery("select * from coll_news_table", null);
if (cursor.getCount() != 0) {
if (cursor.moveToFirst()) {
do {
String title = cursor.getString(cursor.getColumnIndex("title"));
String date = cursor.getString(cursor.getColumnIndex("date"));
String author = cursor.getString(cursor.getColumnIndex("author"));
String imgurl = cursor.getString(cursor.getColumnIndex("imgurl"));
String url = cursor.getString(cursor.getColumnIndex("url"));
News news = new News(imgurl, title, url, date, author);
list.add(news);
} while (cursor.moveToNext());
- 個人資料
用戶名、暱稱、介紹、性別、地區。
在介紹添加了 輸入字數的限制功能(20字以內):
ed_jieshao.addTextChangedListener(new TextWatcher() {
private CharSequence wordNum;//記錄輸入的字數
private int selectionStart;
private int selectionEnd;
private int num=20;
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
wordNum= s;//實時記錄輸入的字數
}
@Override
public void afterTextChanged(Editable s) {
int number = num - s.length();
//TextView顯示剩餘字數
ed_zishu.setText("剩餘" + number+"字");
selectionStart=ed_jieshao.getSelectionStart();
selectionEnd = ed_jieshao.getSelectionEnd();
if (wordNum.length() > num) {
//刪除多餘輸入的字(不會顯示出來)
s.delete(selectionStart - 1, selectionEnd);
int tempSelection = selectionEnd;
ed_jieshao.setText(s);
ed_jieshao.setSelection(tempSelection);//設置光標在最後
}
}
});
- 版本升級
AlertDialog.Builder builder=new AlertDialog.Builder(getContext()); //創建一個AlertDialog的構造器
builder.setIcon(R.drawable.tanhao); //設置圖標
builder.setTitle("溫馨提示"); //設置標題
builder.setMessage("當前已是最新版本"); //設置消息內容
builder.create().show();
- 退出登錄
八、遇到的問題
在使用前面第二個數據接口的時候,數據解析一直報錯,出現空指針異常。得不到數據。
通過詢問老師:最終得到了解決方案😀,數據成功顯示。
九、總結
通過本學期的Android課程的學習,基本掌握了Android應用程序的開發的一般流程,對常用的控件基本掌握及用法,對其事件的監聽方法也基本掌握。學習Android不僅是對前沿開發技術的瞭解,也是對編程知識的一次提升。
十、項目效果
若文章中有錯誤的地方歡迎大家反饋或者留言,十分感謝!!!