上一篇我们实现了一个简单的创建日记记录的页面,今天我们就来实现一个展示所有日记记录的页面。
回忆一下,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*/@Overrideprotected 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 {@Overrideprotected int getFragmentContainer() {return R.id.fragment_container;}@Overrideprotected Fragment createFragment() {return new NoteCreateFragment();}@Overrideprotected void initActivityData() {}@Overrideprotected void initActivityListener() {}@Overrideprotected int getActivityLayout() {return R.layout.activity_fragment;}@Overrideprotected 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 {@Overrideprotected int getFragmentContainer() {return R.id.fragment_container;}@Overrideprotected Fragment createFragment() {return new NoteListFragment();}@Overrideprotected void initActivityData() {}@Overrideprotected void initActivityListener() {}@Overrideprotected int getActivityLayout() {return R.layout.activity_fragment;}
}
public class NoteListFragment extends BaseFragment {@Overrideprotected int getFragmentLayout() {return R.layout.fragment_note_list;}@Overrideprotected void initFragmentData() {}@Overrideprotected void initFragmentListener() {}@Overrideprotected void initFragmentView() {}
}
接下来我们还需要添加NoteListFragment 对应的布局文件fragment_note_list:
"1.0" encoding="utf-8"?>
ok,此时我们运行程序,界面是一片空白什么都没有显示。
我们要显示的是日记的列表,所以这里我们推荐使用目前功能更为齐全的recyclerview。
第一步如同添加Gson一样,添加recyclerview的依赖,这里选择androids.recycleview.网上不少教程还是会推荐大家使用v7支持包,android推出的androidx我还是作为首选项,当然了选择v7也可以的。
在Android Studio中添加recycleview
我们不会详细去介绍recyclerview的具体内容,这里我们就开发中的简单使用为例来实现我们的项目。如果需要更为细致的教程,请大家自行查阅,更高级的使用如果遇到我们在做解释。
在布局文件中使用recycleview
在我们的fragment_note_list.xml使用recycleview很简单:
这里我们为我们的RecyclerView 添加id方便后续的使用。
RecyclerView视图与fragment 关联
NoteListFragment.java:
定义变量:
private RecyclerView recyclerView;private RecyclerView.Adapter adapter;private RecyclerView.LayoutManager layoutManager;
关联RecyclerView视图
@Override@Overrideprotected 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:
讲述的有些乱,不过呢基本上按着流程走的,见谅。
为RecyclerView准备适配器
新建NoteListAdapter类,让这个适配器继承RecyclerView.Adapter,并为其指定泛型为NoteListAdapter.ViewHolder.其中ViewHolder为NoteListAdapter的一个内部类。
public class NoteListAdapter extends RecyclerView.Adapter<NoteListAdapter.ViewHolder> {private List<NoteItem> noteItemList;/*** 通过构造函数传入数据源* &#64;param noteItems 数据源*/public NoteListAdapter(List<NoteItem> noteItems) {noteItemList &#61; noteItems;}/*** 创建ViewHolder实例* &#64;param parent* &#64;param viewType* &#64;return*/&#64;NonNull&#64;Overridepublic ViewHolder onCreateViewHolder(&#64;NonNull ViewGroup parent, int viewType) {View view &#61; LayoutInflater.from(parent.getContext()).inflate(R.layout.note_list_item, parent, false);ViewHolder holder &#61; new ViewHolder(view);return holder;}/*** 对RecyclerView子项进行赋值* &#64;param holder* &#64;param position 当前数据项索引*/&#64;Overridepublic void onBindViewHolder(&#64;NonNull ViewHolder holder, int position) {NoteItem noteItem &#61; noteItemList.get(position);holder.noteTitle.setText(noteItem.getNoteTitle());holder.noteContent.setText(noteItem.getNoteContent());holder.noteCreateDate.setText(noteItem.getDateCreate().toString());}/*** 获取数据项大小* &#64;return*/&#64;Overridepublic int getItemCount() {return noteItemList.size();}/*** 构造函数需要传入view参数&#xff0c;通常为RecyclerView子项的最外层布局&#xff0c;这里就是note_list_item*/static class ViewHolder extends RecyclerView.ViewHolder {TextView noteTitle;TextView noteContent;TextView noteCreateDate;public ViewHolder(&#64;NonNull View itemView) {super(itemView);noteTitle &#61; itemView.findViewById(R.id.tv_note_title);noteContent &#61; itemView.findViewById(R.id.tv_note_content);noteCreateDate &#61; itemView.findViewById(R.id.tv_note_create_date);}}
}
前面我们已经将NoteListFragment.java中关联RecyclerView的代码在initFragmentView方法中已经写过了&#xff0c;这里在来完善下。
首先导入NoteListAdapter&#xff0c;然后为适配器准备数据。
由于我们的日记列表和创建日记的页面还没有整合在一块&#xff0c;所以这里我们先简单模拟下数据。
public class NoteListFragment extends BaseFragment {private RecyclerView recyclerView;private RecyclerView.Adapter adapter;private RecyclerView.LayoutManager layoutManager;> private List<NoteItem> noteItemList &#61; new ArrayList<>();&#64;Overrideprotected int getFragmentLayout() {return R.layout.fragment_note_list;}&#64;Override> protected void initFragmentData() {
>
> for (int i &#61; 0; i < 20; i&#43;&#43;) {
>
> NoteItem noteItem &#61; new NoteItem();
> noteItem.setNoteTitle("标题".concat(String.valueOf(i)));
> noteItem.setNoteContent("内容".concat(String.valueOf(i)));
> noteItem.setDateCreate(new Date());
> noteItemList.add(noteItem);
> }
> }&#64;Overrideprotected void initFragmentListener() {}&#64;Overrideprotected void initFragmentView() {//获取recyclerView组件recyclerView &#61; fragmentRoot.findViewById(R.id.note_recycle_view);//使用布局管理器layoutManager &#61; new LinearLayoutManager(getActivity());recyclerView.setLayoutManager(layoutManager);//指定适配器> adapter &#61; new NoteListAdapter(noteItemList);recyclerView.setAdapter(adapter);}
}
运行程序&#xff1a;
好了&#xff0c;到此为止我们就实现了一个最简单的RecyclerView展示列表。
不知道大家有没有注意到,我们在initFragmentView中使用了noteItemList数据&#xff0c;但是该数据却在initFragmentData被初始化&#xff0c;我们看看父类中的顺序
虽然我们的列表显示出来了&#xff0c;但是将一些基础数据的初始化放在组件初始化之前更为符合逻辑&#xff0c;所以我们修改一下两者的顺序&#xff0c;同理还有BaseActivity中的代码。