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中的代码。

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