Android 記事本2

上一篇我們實現了一個簡單的創建日記記錄的頁面,今天我們就來實現一個展示所有日記記錄的頁面。

回憶一下,activity_notes_page.xml佈局文件並沒有特別指定fragment,任何activity託管fragment的場景,都可
以使用它。下面,爲了讓該佈局更加通用,重命名它爲activity_fragment.xml。

在這裏插入圖片描述

重命名完成後,Android Studio會自動爲我們替換引用該文件的地方。

該項目大多都是採用fragment來實現,所以上篇中如下代碼可能在每個Activity中都會出現,所以我們做進一步的抽象:

  		FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        NoteCreateFragment fragment = new NoteCreateFragment();
        fragmentTransaction.add(R.id.fragment_container, fragment);
        fragmentTransaction.commit();

新建CurrencyFragmentActivity 類,讓其繼承基類BaseActivity:

package com.qiushangge.likenotes.base;

import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;


public abstract class CurrencyFragmentActivity extends BaseActivity {

    /**
     * 重寫父類initActivityView,此處用來掛載fragment
     */
    @Override
    protected void initActivityView() {
        FragmentManager fragmentManager = getSupportFragmentManager();

        Fragment fragment = fragmentManager.findFragmentById(getFragmentContainer());

        if (fragment == null) {
            fragment = createFragment();
            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
            fragmentTransaction.add(getFragmentContainer(), fragment);
            fragmentTransaction.commit();
        }
    }

    /**
     * 返回承載fragment的佈局id
     * @return
     */
    protected abstract int getFragmentContainer();


    /**
     * 如果fragment佈局沒有掛載對應的fragment,那麼創建對應的fragment
     * @return
     */
    protected abstract Fragment createFragment();

}

這裏我們重寫了initActivityView方法,如果其子類仍然需要進行組件相關的初始化工作,那麼繼續重寫即可。如NotePageActivity修改後的實現:

package com.qiushangge.likenotes.activity;


import androidx.fragment.app.Fragment;

import com.qiushangge.likenotes.R;
import com.qiushangge.likenotes.base.CurrencyFragmentActivity;
import com.qiushangge.likenotes.fragment.NoteCreateFragment;

public class NotePageActivity extends CurrencyFragmentActivity {


    @Override
    protected int getFragmentContainer() {
        return R.id.fragment_container;
    }

    @Override
    protected Fragment createFragment() {
        return new NoteCreateFragment();
    }

    @Override
    protected void initActivityData() {

    }

    @Override
    protected void initActivityListener() {

    }

    @Override
    protected int getActivityLayout() {
        return R.layout.activity_fragment;
    }

    @Override
    protected void initActivityView() {
        super.initActivityView();
    }
}


接下來我們就應該創建我們的日記列表了,不過在開始之前我們先來學習下怎麼在Android 中使用Gson庫。

Gson是Google開源的一個JSON庫,被廣泛應用在Android開發中。

在Android Studio中添加Gson庫

在這裏插入圖片描述
在這裏插入圖片描述

在這裏插入圖片描述

然後檢查build.gradle文件
在這裏插入圖片描述

接下來我們再來了解一下Android中的 SharedPreferences。

Sharedpreferences是Android平臺上一個輕量級的存儲類,用來保存應用程序的各種配置信息,其本質是一個以“鍵-值”對的方式保存數據的xml文件,其文件保存在/data/data//shared_prefs目錄下。

使用Sharedpreferences保存數據可以分爲下面幾個步驟:

1.使用Activity類的getSharedPreferences方法獲得SharedPreferences對象
2.使用SharedPreferences接口的edit獲得SharedPreferences.Editor對象
3.通過SharedPreferences.Editor接口的putXXX方法保存key-value對
4.通過SharedPreferences.Editor接口的commit方法保存key-value對

獲取數據可以通過下面的步驟:

1.使用Activity類的getSharedPreferences方法獲得SharedPreferences對象
2.通過SharedPreferences對象的getXXX方法獲取數據

其中getSharedPreferences 方法原型如下:

public abstract SharedPreferences getSharedPreferences (String name, 
                int mode)

mode的可選值爲:
MODE_PRIVATE:只能被自己的應用程序訪問

原來還有

MODE_WORLD_READABLE:除了自己訪問外還可以被其它應該程序讀取
MODE_WORLD_WRITEABLE:除了自己訪問外還可以被其它應該程序讀取和寫入

不過這兩個參數在API level 17開始就不推薦使用了。

ok,上一篇我們寫完日記後,點擊保存按鈕會提示保存成功,這裏我們利用上面提到的知識點保存日記,並且我們的重新創建一個日記列表用來展示所有的日記。

創建NoteListActivity和NoteListFragment類,並將NoteListActivity設置爲啓動類:
在這裏插入圖片描述

接下來我們實現NoteListActivity和NoteListFragment類:

public class NoteListActivity extends CurrencyFragmentActivity {
    @Override
    protected int getFragmentContainer() {
        return R.id.fragment_container;
    }

    @Override
    protected Fragment createFragment() {
        return new NoteListFragment();
    }

    @Override
    protected void initActivityData() {

    }

    @Override
    protected void initActivityListener() {

    }

    @Override
    protected int getActivityLayout() {
        return R.layout.activity_fragment;
    }
}

public class NoteListFragment extends BaseFragment {
    @Override
    protected int getFragmentLayout() {
        return R.layout.fragment_note_list;
    }

    @Override
    protected void initFragmentData() {

    }

    @Override
    protected void initFragmentListener() {

    }

    @Override
    protected void initFragmentView() {

    }
}

接下來我們還需要添加NoteListFragment 對應的佈局文件fragment_note_list:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

</androidx.constraintlayout.widget.ConstraintLayout>

ok,此時我們運行程序,界面是一片空白什麼都沒有顯示。

我們要顯示的是日記的列表,所以這裏我們推薦使用目前功能更爲齊全的recyclerview。

第一步如同添加Gson一樣,添加recyclerview的依賴,這裏選擇androids.recycleview.網上不少教程還是會推薦大家使用v7支持包,android推出的androidx我還是作爲首選項,當然了選擇v7也可以的。

在Android Studio中添加recycleview

在這裏插入圖片描述

我們不會詳細去介紹recyclerview的具體內容,這裏我們就開發中的簡單使用爲例來實現我們的項目。如果需要更爲細緻的教程,請大家自行查閱,更高級的使用如果遇到我們在做解釋。

在佈局文件中使用recycleview

在我們的fragment_note_list.xml使用recycleview很簡單:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="16dp"
    android:layout_marginBottom="16dp"
    tools:context=".fragment.NoteListFragment">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/note_recycle_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

這裏我們爲我們的RecyclerView 添加id方便後續的使用。

RecyclerView視圖與fragment 關聯

NoteListFragment.java:
定義變量:

	private RecyclerView recyclerView;
    private RecyclerView.Adapter adapter;
    private RecyclerView.LayoutManager layoutManager;

關聯RecyclerView視圖

 @Override
  @Override
    protected void initFragmentView() {
        //獲取recyclerView組件
        recyclerView = fragmentRoot.findViewById(R.id.note_recycle_view);
        //使用佈局管理器
        layoutManager = new LinearLayoutManager(getActivity());
        recyclerView.setLayoutManager(layoutManager);
        //指定適配器
        adapter = new NoteListAdapter();
        recyclerView.setAdapter(adapter);
    }

其中android爲我們提供了常見的三種佈局管理器:

1、LinearLayoutManager 線性佈局管理器,支持橫向、縱向。

2、 GridLayoutManager 網格佈局管理器

3、 StaggeredGridLayoutManager 瀑布流式佈局管理器

到這裏我們的準備工作還沒有完成,首先呢還得準備一個列表內容怎麼顯示的佈局文件note_list_item.xml:

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/tv_note_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="8dp"
        android:textStyle="bold"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv_note_content"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="8dp"
        app:layout_constraintTop_toBottomOf="@id/tv_note_title" />

    <TextView
        android:id="@+id/tv_note_create_date"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAlignment="viewEnd"
        app:layout_constraintTop_toBottomOf="@id/tv_note_content" />


</androidx.constraintlayout.widget.ConstraintLayout>

講述的有些亂,不過呢基本上按着流程走的,見諒。

爲RecyclerView準備適配器

新建NoteListAdapter類,讓這個適配器繼承RecyclerView.Adapter,併爲其指定泛型爲NoteListAdapter.ViewHolder.其中ViewHolder爲NoteListAdapter的一個內部類。

在這裏插入圖片描述


public class NoteListAdapter extends RecyclerView.Adapter<NoteListAdapter.ViewHolder> {

    private List<NoteItem> noteItemList;

    /**
     * 通過構造函數傳入數據源
     * @param noteItems 數據源
     */
    public NoteListAdapter(List<NoteItem> noteItems) {
        noteItemList = noteItems;
    }

    /**
     * 創建ViewHolder實例
     * @param parent
     * @param viewType
     * @return
     */
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.note_list_item, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    /**
     * 對RecyclerView子項進行賦值
     * @param holder
     * @param position 當前數據項索引
     */
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        NoteItem noteItem = noteItemList.get(position);
        holder.noteTitle.setText(noteItem.getNoteTitle());
        holder.noteContent.setText(noteItem.getNoteContent());
        holder.noteCreateDate.setText(noteItem.getDateCreate().toString());
    }

    /**
     * 獲取數據項大小
     * @return
     */
    @Override
    public int getItemCount() {
        return noteItemList.size();
    }

    /**
     * 構造函數需要傳入view參數,通常爲RecyclerView子項的最外層佈局,這裏就是note_list_item
     */
    static class ViewHolder extends RecyclerView.ViewHolder {
        TextView noteTitle;
        TextView noteContent;
        TextView noteCreateDate;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            noteTitle = itemView.findViewById(R.id.tv_note_title);
            noteContent = itemView.findViewById(R.id.tv_note_content);
            noteCreateDate = itemView.findViewById(R.id.tv_note_create_date);
        }
    }
}

前面我們已經將NoteListFragment.java中關聯RecyclerView的代碼在initFragmentView方法中已經寫過了,這裏在來完善下。

首先導入NoteListAdapter,然後爲適配器準備數據。

由於我們的日記列表和創建日記的頁面還沒有整合在一塊,所以這裏我們先簡單模擬下數據。

public class NoteListFragment extends BaseFragment {

    private RecyclerView recyclerView;
    private RecyclerView.Adapter adapter;
    private RecyclerView.LayoutManager layoutManager;

  

>   private List<NoteItem> noteItemList = new ArrayList<>();

    @Override
    protected int getFragmentLayout() {
        return R.layout.fragment_note_list;
    }

    @Override
  

>   protected void initFragmentData() {
> 
>         for (int i = 0; i < 20; i++) {
> 
>             NoteItem noteItem = new NoteItem();
>             noteItem.setNoteTitle("標題".concat(String.valueOf(i)));
>             noteItem.setNoteContent("內容".concat(String.valueOf(i)));
>             noteItem.setDateCreate(new Date());
>             noteItemList.add(noteItem);
>         }
>     }

    @Override
    protected void initFragmentListener() {

    }

    @Override
    protected void initFragmentView() {
        //獲取recyclerView組件
        recyclerView = fragmentRoot.findViewById(R.id.note_recycle_view);
        //使用佈局管理器
        layoutManager = new LinearLayoutManager(getActivity());
        recyclerView.setLayoutManager(layoutManager);
        //指定適配器
      

>   adapter = new NoteListAdapter(noteItemList);

        recyclerView.setAdapter(adapter);
    }
}

運行程序:
在這裏插入圖片描述
好了,到此爲止我們就實現了一個最簡單的RecyclerView展示列表。

不知道大家有沒有注意到,我們在initFragmentView中使用了noteItemList數據,但是該數據卻在initFragmentData被初始化,我們看看父類中的順序
在這裏插入圖片描述
雖然我們的列表顯示出來了,但是將一些基礎數據的初始化放在組件初始化之前更爲符合邏輯,所以我們修改一下兩者的順序,同理還有BaseActivity中的代碼。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章