Android:Fragment

章节中所有代码和笔记均参考、摘录自《第一行代码(第二版)》

照着书写好的Demo疯狂闪退,找两个错漏找了一个多小时,真的整个人都裂开。 Fragment和RecyclerView真的只要一段时间没看(几个月前才看过),马上就能忘干净,看来纯看书确实没什么鬼用。

好吧,Fragment一般是平板开发使用的,我理解为Activity青春版,通过Fragment分割屏幕使得内容得以充分的展示,最大化利用平板屏幕大的优点。

创建自定义的Fragment并继承Fragment,在里面重写 onCreateView() 方法,然后通过

inflater.inflate(R.layout.left_fragment, container, false);

将left_layout(这里是layout的名称)动态加载进入。

为什么重写的是 onCreateView() ?

放上网上找到的Fragment的生命周期图看一下

onAttach() 在Fragment和Activity建立关联调用,而且碎片和活动是最先绑定,最后解绑。在碎片创建之后就调用 onCreateView()创建视图了,由此重写onCreateView()载入自定义布局(记得要返回view)。至于onActivityCreated() 如其名一样,在碎片和相关活动创建完毕的时候调用。

好的,既然对自定义碎片布局需要创建一个类并继承Fragment,那么双页模式(两个碎片)就自定义两个碎片类。

上图中,

News为实体类(Java Bean,包含String类型数据Title和Context及其方法)。

NewsContentFragment除了填充布局以外,就实现了一个refresh()用来对布局中的两个TextView控件赋值。

NewsContentActivity实现了actionStart方便其他类调用intent调转向本类并传递news_title、news_content两个参数,在onCreate()方法中,获取intent传入的参数,并通过

getSupportFragmentManager().findFragmentById(R.id.news_content_fragment);

创建并获取NewsContentFragment实例,调用其refresh()刷新界面。

NewsTitleFragment是展示新闻列表的碎片,除了填充布局之外,添加了一个名为isTwoPane的布尔值,在碎片和活动都成功创建时(onActivityCreated()),判断是否为双页布局来调整这个布尔值。

NewsTitleFragment类还实现了一个NewsAdapter的内部类,用来作为RecyclerView的适配器。这个适配器和之前RecycerView部分的几乎相同,但是还是单独放出来,因为刚开始看到确实这部分是最难消化的。

class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder>{
        private List<News> mNewsList;
        class ViewHolder extends RecyclerView.ViewHolder{
            TextView newsTitleText;
            public ViewHolder(View view){
                super(view);
                newsTitleText = view.findViewById(R.id.news_title);
            }
        }
        public NewsAdapter(List<News> newsList){
            mNewsList = newsList;
        }

        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.news_item,parent,false);
            final ViewHolder holder = new ViewHolder(view);
            view.setOnClickListener(view1 -> {
                News news = mNewsList.get(holder.getAdapterPosition());
                if(isTwoPane){
                    NewsContentFragment newsContentFragment = (NewsContentFragment)
                            getFragmentManager().findFragmentById(R.id.news_content_fragment);
                    newsContentFragment.refresh(news.getTitle(),news.getContent());
                }else{
                NewsContentActivity.actionStart(getActivity(),news.getTitle(),news.getContent());
                }
            });
            return holder;
        }

        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            News news = mNewsList.get(position);
            holder.newsTitleText.setText(news.getTitle());
        }

        @Override
        public int getItemCount() {
            return mNewsList.size();
        }
    }
layout-sw600dp和两个activity_main

如上图所见,下面说一下布局文件。

MainActivity在其对应的layout文件里只有一个碎片。当然,为了手机和平板都能合适的使用此应用,在layout文件夹下新建了layout-sw600dp,并在其中创建了同样名为activity_main的布局文件,此布局是在平板打开应用时载入的布局。

news_item很好理解,就是作为RecyclerView的子布局,而new_title_frag里面也只有一个RecyclerView,这两个通过NewsAdapter组合到一起,完成点击并在news_content_frag中显示的功能。

news_content_frag就是右侧新闻内容碎片的布局。

news_content就是单页模式中点击news_title_frag所显示的布局,直接复用news_content_frag的布局。如下图所示,可以看到平板右侧和手机点击后布局是一样的。