8.1Android编程权威指南(第3版)————使用RecyclerView显示列表

8.1Android编程权威指南(第3版)————使用RecyclerView显示列表
定义抽象类

public abstract class SinglesFragmentActivity extends AppCompatActivity {

    public abstract Fragment createFramgnet();
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fragment);

        //创建一个新的fragment事务,执行一个fragment添加操作,然后提交该事务
        FragmentManager fm = getSupportFragmentManager();
        Fragment fragment = fm.findFragmentById(R.id.fragment_container);
        /**
         * 为什么要获取的fragment可能有了呢?设备旋转或回收内存时,Android系统会销
         毁CrimeActivity,而后重建时,会调用CrimeActivity.onCreate(Bundle)方法。activity被
         销毁时,它的FragmentManager会将fragment队列保存下来。这样,activity重建时,新的
         FragmentManager会首先获取保存的队列,然后重建fragment队列,从而恢复到原来的状态。
         */
        if (fragment == null) {
            fragment = createFramgnet();
            fm.beginTransaction()
                    //参数一:容器视图资源ID 参数二:创建的fragment
                    .add(R.id.fragment_container, fragment)
                    .commit();
        }
    }
}

recyclerview xml文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/crime_recycler_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</android.support.v7.widget.RecyclerView>
public class CrimeListFragment extends Fragment {
    private RecyclerView mCrimeRecyclerView;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_crime_list, container, false);

        mCrimeRecyclerView = view.findViewById(R.id.crime_recycler_view);
        /**
         * 注意:没有LayoutManager的支持,不仅RecyclerView无法工作,还会导致应用崩溃
         摆放的任务被委托给了LayoutManager。除了在屏幕上摆放列表项,LayoutManager还
         负责定义屏幕滚动行为
         */
        mCrimeRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        updateUI();
        return view;
    }

    private void updateUI() {
        CrimeLab crimeLab = CrimeLab.get(this);
        List<Crime> crimes = crimeLab.getCrimes();
        CrimeAdapter crimeAdapter = new CrimeAdapter(getActivity(), crimes);
        mCrimeRecyclerView.setAdapter(crimeAdapter);
    }

}

适配器

public class CrimeAdapter extends RecyclerView.Adapter<CrimeViewHolder> {
    private Context mContext;
    private List<Crime> mCrimes;

    public CrimeAdapter(Context context, List<Crime> crimes) {
        this.mContext = context;
        this.mCrimes = crimes;
    }

    @Override
    public CrimeViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater layoutInflater = LayoutInflater.from(mContext);
        CrimeViewHolder crimeViewHolder = new CrimeViewHolder(layoutInflater, parent, mContext);
        return crimeViewHolder;
    }

    @Override
    public void onBindViewHolder(CrimeViewHolder holder, int position) {//主要作用是起显示的功能
        Crime crime = mCrimes.get(position);
        holder.bind(crime);
    }

    @Override
    public int getItemCount() {
        return mCrimes.size();
    }

}

//容纳View视图
class CrimeViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    Crime mCrime;
    private TextView mTitleTextView;
    private TextView mDateTextView;
    Context mContext;

    /**
     * onCreateViewHolder(ViewGroup, int)方
     * 法的调用并不频繁。一旦有了够用的ViewHolder,RecyclerView就会停止调用onCreate-
     * ViewHolder(...)方法。随后,它会回收利用旧的ViewHolder以节约时间和内存
     */
    public CrimeViewHolder(LayoutInflater inflater, ViewGroup parent, Context context) {
        super(inflater.inflate(R.layout.list_item_crime, parent, false));
        this.mContext = context;
        mTitleTextView = (TextView) itemView.findViewById(R.id.crime_title);
        mDateTextView = (TextView) itemView.findViewById(R.id.crime_data);
        itemView.setOnClickListener(this);
    }

    public void bind(Crime crime) {
        mCrime = crime;
        mTitleTextView.setText(mCrime.getTitle());
        mDateTextView.setText(mCrime.getDate().toString());
    }

    @Override
    public void onClick(View view) {
        Toast.makeText(mContext,
                mCrime.getTitle() + " clicked!", Toast.LENGTH_SHORT)
                .show();
    }
}

Demo下载地址:
https://download.csdn.net/download/weixin_43953649/10864739

ListView 和GridView
Android操作系统核心库包含ListView、GridView和Adapter这3个类。Android 5.0之前,创建列表项或网格项都应该优先使用这些类。
这些类的API与RecyclerView的API非常相似。ListView和GridView不关心具体的展示项,只负责展示项的滚动。Adapter负责创建列表项的所有视图。不过,使用ListView和GridView时不一定非要使用ViewHolder模式(虽然可以并且应该使用)。
过去传统的实现方式现已被RecyclerView的实现方式取代,因此不用再费力地调整ListView和GridView的工作行为了。举例来说,ListView API不支持创建水平滚动的ListView,因此需要许多额外的定制工作。使用RecyclerView时,虽然创建定制布局和滚动行为也需要额外的工作,但RecyclerView天生支持拓展,所以使用体验还不错。此外RecyclerView还有支持列表项动画效果的优点。如果要让ListView和GridView支持添加和删除列表项的动画效果,实现起来既复杂又容易出错;而对于天生支持动画特效的RecyclerView来说,对付这些任务简直是小菜一碟。。例如,如果crime列表项要从位置0移动到位置5,下面这段代码就可以做到。mRecyclerView.getAdapter().notifyItemMoved(0, 5);

单例
Android开发实践中,经常会用到CrimeLab中使用过的单例模式。然而,单例若使用不当,会导致应用难以维护,因此它也常遭人诟病。Android开发常用到单例的一大原因是,它们比fragment或activity活得久。例如,在设备旋转或是在fragment和activity间跳转的场景下,单例不会受到影响,而旧的fragment或activity已经不复存在了。
单例能方便地存储和控制模型对象。假设有一个比CriminalIntent更为复杂的应用,它的许多个activity和fragment会修改crime数据。某个控制单元修改了crime数据之后,怎么保证发送给其他控制单元的是最新数据呢?如果CrimeLab掌控数据对象,所有的修改都由它来处理,是不是控制数据的一致性就容易多了?而且,在控制单元间流转时,你还以给每个crime添加ID标识,让控制单元使用ID标识从CrimeLab获取完整的crime数据。再来谈谈单例的缺点。举个例子,虽然单例能存储数据,活得也比控制单元长,但这并不代表它能永存。在我们切换至其他应用,或逢Android回收内存时,单例连同那些实例变量也就不复存在了。结论很明显:单例无法做到持久存储。(将文件写入磁盘或是发送到Web服务器是不错的数据持久化存储方案。)单例还不利于单元测试。例如,如果应用代码直接调用CrimeLab对象的静态方法,测试时以模拟版本的CrimeLab代替实际CrimeLab实例就不太现实。实践中,Android开发人员会使用依赖注入工具解决这个问题。这个工具允许以单例模式使用对象,对象也可以按需替换。使用单例很方便,因而它很容易被滥用。在想用就用、想存就存之前,希望你能深思熟虑:
数据究竟用在哪里?用在哪里能真正解决问题?假如不慎重对待这个问题,很可能后来人在查看你的单例代码时,就像打开了一个乱糟糟的
废品抽屉,里面堆满了废电池、拉链扣、旧照片,等等。它们有什么存在的意义?再强调一次:请确保有充足的理由使用单例模式存储你的共享数据!若使用得当,单例就是架构优秀的Android应用中的关键部件。