安卓开发-用Fragment加载RecyclerView

内容纲要

用Fragment加载RecyclerView

Fragment(碎片、片段)

  1. 依赖于Activity,不能独立存在
  2. 一个Activity里可以有多个Fragmentaa
  3. 一个Fragment可以被多个Activity重用
  4. Fragment有自己的生命周期,并能接收输入事件
  5. 我们能在Activity运行时动态地添加或删除Fragment,方便切换

新建FrameLayout布局

在相关Activity的布局文件中添加FrameLayout布局,用于显示Fragment

<FrameLayout
    android:id="@+id/frame_home"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</FrameLayout>

添加Fragment

新建一个带xml文件的Fragment

定义相关全局变量

设定两个全局变量用于解决下列问题

  1. Fragment中无法使用findViewById方法(需要View)

    getView()方法只能在Fragment的生命周期相关函数中使用,若在其它自定义函数使用会指示空指针

  2. Fragment中希望弹出诸如消息框、对话框等(需要Context)

    getActivity()方法只能在Fragment的生命周期相关函数中使用,若在其它自定义函数使用会指示空指针

定义全局变量

//保存Fragment的View对象
View fragmentView;
//记录当前Fragment的环境
private Context mContext;

初始化上述变量

  1. 初始化fragmentView

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                Bundle savedInstanceState) {
        //为这个Fragment填充布局,初始化fragmentView对象
        fragmentView = inflater.inflate(R.layout.fragment_home, container, false);
        return fragmentView;
    }
  2. 初始化mContext

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        //在Fragment激活时初始化为当前环境
        mContext = context;
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        //在释放时初始化初始化环境为空
        mContext = null;
    }

用Adapter绑定数据到RecyclerView

具体的已经在这篇博客写好了

注意事项

在OnCreateView中获取xml转换后的View对象,即可在其它方法中使用
那么就可以不必将所有需要View对象的函数写入OnCreateView对象,如下

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                            Bundle savedInstanceState) {
    //为这个Fragment填充布局,初始化fragmentView对象
    fragmentView = inflater.inflate(R.layout.fragment_home, container, false);
    //初始化相关数据
    initData();
    //初始化界面
    initView();
    //设置下拉刷新功能和上拉加载更多功能
    initRefreshLayout();
    return fragmentView;
}

那么Fragment的其它方法就可以直接使用fragmentView对象
RefreshLayout refreshLayout = (RefreshLayout) fragmentView.findViewById

//下拉刷新、上拉显示更多框架
public void initRefreshLayout(){
    //通过View找到SmartRefreshLayout对象
    RefreshLayout refreshLayout = (RefreshLayout) fragmentView.findViewById(R.id.smatrRefreshLayout);
    //设置下拉刷新
    refreshLayout.setOnRefreshListener(new OnRefreshListener() {
        @Override
        public void onRefresh(RefreshLayout refreshlayout) {
            refreshlayout.finishRefresh(2000/*,false*/);    //传入false表示刷新失败
        }
    });
    //设置上拉显示更多
    refreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
        @Override
        public void onLoadMore(RefreshLayout refreshlayout) {
            refreshlayout.finishLoadMore(2000/*,false*/);   //传入false表示加载失败
        }
    });

附(程序源码)

HomeFragment.java

public class HomeFragment extends Fragment {
    View fragmentView;
    //记录当前Fragment的环境
    private Context mContext;
    private static final int CHANGE_UI = 1;
    private static final int ERROR = 2;

    //接口地址
    String url_path;
    //倒数日,用于获取历史数据
    int watchDate = 0;

    //保存接口获取的Data数据
    List<PostsInfo.StoriesBean> postsData;

    //RecyclerView显示列表
    RecyclerView recyclerView_home;
    //适配器,绑定数据到RecyclerView
    PostsAdapter postsAdapter;
    //Recycler的布局管理器
    RecyclerView.LayoutManager layoutManager;

    public HomeFragment() {

    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        //为这个Fragment填充布局,初始化fragmentView对象
        fragmentView = inflater.inflate(R.layout.fragment_home, container, false);
        //初始化相关数据
        initData();
        //初始化界面
        initView();
        //设置下拉刷新功能和上拉加载更多功能
        initRefreshLayout();
        return fragmentView;
    }
    //主线程创建消息处理机制
    @SuppressLint("HandlerLeak")
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(android.os.Message msg) {
            if(msg.what == CHANGE_UI){
                //为了确保加载视图所需数据都已经获取
                //收到更新视图消息,才开始加载视图
                postsData = (List<PostsInfo.StoriesBean>) msg.obj;
                initView();
            }else if(msg.what == ERROR){
                //如果数据获取失败
                ToastUtil.showToast(getContext(),"请求数据错误");
            }
        }
    };
    //下拉刷新、上拉显示更多框架
    public void initRefreshLayout(){
        //通过View找到SmartRefreshLayout对象
        RefreshLayout refreshLayout = (RefreshLayout) fragmentView.findViewById(R.id.smatrRefreshLayout);
        //设置下拉刷新
        refreshLayout.setOnRefreshListener(new OnRefreshListener() {
            @Override
            public void onRefresh(RefreshLayout refreshlayout) {
                refreshlayout.finishRefresh(2000/*,false*/);    //传入false表示刷新失败
            }
        });
        //设置上拉显示更多
        refreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() {
            @Override
            public void onLoadMore(RefreshLayout refreshlayout) {
                refreshlayout.finishLoadMore(2000/*,false*/);   //传入false表示加载失败
            }
        });
    }

    private void initData() {
        //设定接口地址
        //大谷哥技术文档提供的新闻接口
        //url_path = "https://www.jsanai.com/api/selfnews/newslist";

//        //聚合提供的"历史上的今天"接口地址
//        NowDate nowDate = new NowDate();
//        //为了提高数据更新频率,对参数进行自定义
//        final int month = nowDate.getHour()%12+1;
//        final int day = nowDate.getMinute()%28+1;
//        url_path = "http://api.juheapi.com/japi/toh?v=1.0&month=" + month + "&day=" + day + "&key=53e5094ed67d88c3a9ec5e01f28e26a3";

        //知乎日报接口地址
        url_path = "http://news-at.zhihu.com/api/4/news/latest";
        if (watchDate == 0){    //倒数日为0,即今天
            url_path ="http://news-at.zhihu.com/api/4/news/latest";
        }else{                  //返回watchDate天前的数据
            url_path = "http://news.at.zhihu.com/api/4/news/before/" + NowDate.getDate(watchDate);
        }
        //创建List数组对象,用于保存网络请求的数据
        postsData = new ArrayList<>();
        //发起Http请求,获取数据
        getNewsInfo(url_path);
    }
    private void initView() {
        //将接口数据转换为RecyclerView的列表
        recyclerView_home = fragmentView.findViewById(R.id.recyclerView_home);
        recyclerView_home.setHasFixedSize(true);
        //设置布局管理器
        layoutManager = new LinearLayoutManager(mContext);
        recyclerView_home.setLayoutManager(layoutManager);
        //设置Adapter的传入数据
        postsAdapter = new PostsAdapter(postsData);
        recyclerView_home.setAdapter(postsAdapter);
    }
    private void getNewsInfo(String url_path){
        //创建一个新AsyncHttpClient实例并发出请求
        AsyncHttpClient client = new AsyncHttpClient();
        //AsyncHttpClient中有get和post两种方法
        //第一个参数是所要获取接口,第二个参数是所发出的请求
        client.get(url_path, new AsyncHttpResponseHandler() {
            @Override
            public void onSuccess(int i, Header[] headers, byte[] bytes) {
                try {
                    String json = new String(bytes,"utf-8");
                    Gson gson = new Gson();
                    PostsInfo postsInfo = gson.fromJson(json,PostsInfo.class);

                    //将更改主界面的消息发给主线程
                    Message msg = new Message();
                    msg.what = CHANGE_UI;
                    //保存所需的数据,传递回主线程
                    msg.obj = postsInfo.getStories();
                    handler.sendMessage(msg);

                    Log.d("JSON","http get() succeed");
                }catch (Exception e){
                    Log.d("JSON","catch e");
                    e.printStackTrace();
                }
            }
            @Override
            public void onFailure(int i, Header[] headers, byte[] bytes, Throwable throwable) {
                ToastUtil.showToast(mContext,"fail to resolve");
                Message msg = new Message();
                msg.what = ERROR;
                handler.sendMessage(msg);
            }
        });
    }
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mContext = context; //设定环境
    }

    @Override
    public void onDetach() {
        super.onDetach();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mContext = null;
    }
}

发表评论