中級實訓Android學習記錄——RecyclerView、Android儲存
阿新 • • 發佈:2020-11-28
學習記錄 2020/11/26
RecyclerView
- RecyclerView
RecyclerView在之前就學習過,但用的時候才發現沒有學習記錄,所以在這裡自行總結。
使用RecyclerView建立列表檢視的步驟:
建立一個activity(Android studio會幫你順便宣告並建立layout),在activity的xml檔案中建立一個RecyclerView
// 我們在activity_linear_recycler.xml中宣告一個RecyclerView <androidx.recyclerview.widget.RecyclerView android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" android:id="@+id/rv_main" android:background="@color/purple_700"/>
建立一個列表的一個小項所用的layout
// 這裡我們建立的是layout_linear_item.xml,裡面只有一個簡單的TextView <TextView android:id="@+id/tv_title" android:layout_width="match_parent" android:layout_height="50dp" android:textColor="#000" android:textSize="20sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
建立使用小項layout的RecyclerViewAdapter
public class LinearAdapter extends RecyclerView.Adapter<LinearAdapter.LinearViewHolder> { // 自己建立一個ViewHolder並將它傳入Adapter的模板引數中 private Context mContext; public LinearAdapter(Context context) { this.mContext = context; } // 注意這裡的返回值也要改成自己的ViewHolder @NonNull @Override public LinearAdapter.LinearViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return new LinearViewHolder(LayoutInflater.from(mContext).inflate(R.layout.layout_linear_item, parent, false)); } // 注意這裡傳入的引數也要改成自己的ViewHolder @Override public void onBindViewHolder(@NonNull LinearAdapter.LinearViewHolder holder, int position) { holder.textView.setText("Hello World!"); } // 自定義一個列表的小項的個數,一般我們可以使用一個列表來宣告 @Override public int getItemCount() { return 30; } // 建立一個ViewHolder來自定義小項 class LinearViewHolder extends RecyclerView.ViewHolder { private TextView textView; public LinearViewHolder(@NonNull View itemView) { super(itemView); textView = itemView.findViewById(R.id.tv_title); } } }
最後就可以在Activity中直接使用RecyclerView
// 先宣告一個變數 private RecyclerView mRvMain; mRvMain = findViewById(R.id.rv_main); mRvMain.setLayoutManager(new LinearLayoutManager(LinearRecyclerActivity.this)); mRvMain.setAdapter(new LinearAdapter(LinearRecyclerActivity.this));
加每個小項之間的分隔線的方法
在Activity.java中自定義一個類並繼承ItemDecoration
class myDecoration extends RecyclerView.ItemDecoration { @Override public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); outRect.set(0, 0, 0, getResources().getDimensionPixelOffset(R.dimen.dividerHeight)); } } // 這裡的set函式的四個引數代表的方向依次是左、上、右、下 // 所以我們的效果其實是在每個item的下方加一個R.dimen.dividerHeight大小的橫線
呼叫RecyclerView的addItemDecoration方法即可
mRvMain.addItemDecoration(new myDecoration());
Android 儲存
-
SharedPreferences 輕量級資料儲存
- 一般儲存形式表現為以Key-Value的形式,儲存在XML檔案中
- 用SharedPreferences來讀取xml檔案
- 用SharedPreferences.Editor來更改xml檔案
-
SharedPreferences 用法
-
獲取資料
-
private SharedPreferences mSharedPreferences; mSharedPreferences = getSharedPreferences("data", MODE_PRIVATE); // 這裡第一個引數表示檔名,第二個引數表示檔案開啟的模式,一般使用MODE_PRIVATE // 假設已經使用Editor輸入資料,key="name" String data = mSharedPreferences.getString("name", "");
-
輸入資料
-
private SharedPreferences.Editor mEditor; mEditor = mSharedPreferences.edit(); //呼叫put型別的方法來輸入key-value資料 mEditor.putString("name", "haha") // 呼叫apply或者commit進行資料更新 // apply是非同步 // commit是同步 mEditor.apply();
-
SharedPreferences的儲存目錄
- /data/data/
/shared_prefs
- /data/data/
-
SharedPreferences的儲存目錄的檢視方式
-
命令列下
-
// 使用android的shell adb shell // 呼叫run-as 後面加上自己的完整applicaiton的名稱 run-as com.skypan.helloworld // 進入目錄shared_prefs cd shared_prefs // 在命令列中列出data.xml的內容 cat data.xml
-
-
儲存概念
- Android儲存分為
- 內部儲存(Internal Storage)
- 內部儲存會隨應用的解除安裝而刪除,如
- /data/data/
/shared_prefs - /data/data/
/databases - /data/data/
/files - /data/data/
/cache
- /data/data/
- 利用的方法可以是
- context.getFilesDir()獲得目錄/data/data/
/files - context.getCacheDir()獲得目錄/data/data/
/cache
- context.getFilesDir()獲得目錄/data/data/
- 內部儲存會隨應用的解除安裝而刪除,如
- 外部儲存(External Storage)
- 公有目錄
- 公有目錄的獲取
- Environment.getExternalStoragePublicDirectory(int type)
- type可以是Environment下的已經定義好的變數
- 公有目錄的獲取
- 私有目錄,隨應用的解除安裝而刪除,如
- /mnt/sdcard/Anroid/data/data/
/cache - /mnt/sdcard/Anroid/data/data/
/files
- /mnt/sdcard/Anroid/data/data/
- 公有目錄
- 內部儲存(Internal Storage)
- Android儲存分為
-
File內部儲存
-
使用的類
-
FileOutputStream,FileInputStream
-
儲存資料
private void save(String content) { try { FileOutputStream fileOutputStream = openFileOutput("test.txt", MODE_PRIVATE); // 第一個引數代表檔名,第二個引數是檔案讀寫方式 fileOutputStream.write(content.getBytes()); // 這裡呼叫的write函式接受的是byte[],所以需要將String物件轉換成byte } catch (IOException e) { // 注意,此時其實丟出的不止是IOException,還有FileNotFoundException,不過這個錯誤繼承了IOException,所以都可以被IOException catch到 e.printStackTrace(); } finally { // 無論如何,我們都需要關閉一開始開啟的檔案 if (fileOutputStream != null) { // 如果已經打開了,就關閉 try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
讀取資料
private String read() { FileInputStream fileInputStream = null; try { FileInputStream fileInputStream = openFileInput("test.txt"); byte[] buff = new byte[1024]; StringBuilder sb = new StringBuilder(""); int len = 0; while((len = fileInputStream.read(buff)) > 0) { sb.append(new String(buff, 0, len)); // 從buff的0開始,將len長度的byte做成String加到sb的後面 } return sb.toString(); } catch (IOException e) { e.printStackTrace(); // 預設可能發生錯誤,直接返回空 return null; }
-
-
File外部儲存
-
使用的類
-
FileOutputStream,FileInputStream,Environment
-
儲存資料
private void save(String content) { try { File dir = new File(Environment.getExternalStorageDirectory(), "skypan"); // 第一個是找到外部儲存目錄,第二個引數是資料夾的名字 if (!dir.exists()) { dir.mkdirs(); // 使用mkdirs而非mkdir是因為他會幫我們建立一系列的資料夾(當我們的資料夾路徑很複雜的時候) } File file = new File(dir, "test.txt"); if (!file.exists()) { file.createNewFile(); } FileOutputStream fileOutputStream = new FileOutputStream(file); fileOutputStream.write(content.getBytes()); // 這裡呼叫的write函式接受的是byte[],所以需要將String物件轉換成byte } catch (IOException e) { // 注意,此時其實丟出的不止是IOException,還有FileNotFoundException,不過這個錯誤繼承了IOException,所以都可以被IOException catch到 e.printStackTrace(); } finally { // 無論如何,我們都需要關閉一開始開啟的檔案 if (fileOutputStream != null) { // 如果已經打開了,就關閉 try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
讀取資料
private String read() { FileInputStream fileInputStream = null; try { File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+File.separator+"skypan", "test.txt"); // 第一個引數是我們的資料夾的絕對路徑,其中File.separator的值="/",第二個引數是我們的檔名 fileInputStream = new FileInputStream(file); byte[] buff = new byte[1024]; StringBuilder sb = new StringBuilder(""); int len = 0; while((len = fileInputStream.read(buff)) > 0) { sb.append(new String(buff, 0, len)); // 從buff的0開始,將len長度的byte做成String加到sb的後面 } return sb.toString(); } catch (IOException e) { e.printStackTrace(); // 預設可能發生錯誤,直接返回空 return null; }
注意,並不能直接使用以上程式碼,在使用外部儲存之前,我們需要先獲取外部儲存的讀寫許可權:
-
在AndroidManifest.xml中宣告以下語句
<user-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
如果在build.gradle中,我們的sdk版本超過了23,我們還需要動態申請許可權
在build.gradle中檢視sdk版本
compileSdkVersion n
如果$n\geq 23$,就需要動態申請許可權,在使用外部儲存之前:
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WIRTE_EXTERNAL_STORAGE}, 1); // 第一個引數是呼叫這個函式的activity(context),第二個引數是申請的是什麼許可權,第三個是許可權返回結果的識別碼,如果我們需要得到使用者是否確認給予許可權,我們需要額外呼叫方法進行判斷
在申請了許可權之後,就可以正常的執行之前說的使用外部儲存的程式碼了。
-
-