安卓中api数据adapter填充列表及嵌套fragment遇到的闪退问题

2024-01-10 11:36:39

安卓中,从api中获取数据并填充到listview、RecyclerView以及fragment的各个adapter适配器的定义以及绑定的基本步骤及相关问题。

1.列表listview

? listview是常见的列表视图。

  1. 定义listview

    • XML定义<listview>
    • activity定义listview类
    • 类绑定xml的id
  2. 获得数据

  3. 设置适配器

    连接UI并赋予单个item数据,数据由外部传入

    1. 继承ArrayAdapter<T>

      • getView中定义对单个Item中组件取值并赋值
    2. 初始化

      public class OrderAdapter extends ArrayAdapter<OrderCategories> {
          public OrderAdapter(@NonNull Context context, int resource, @NonNull List<T> objects) {
              super(context, resource, objects);
          }
          public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
              OrderCategories categorie=getItem(position);//得到当前项的Article实例
              //为每一个子项加载设定的布局
              View view= LayoutInflater.from(getContext()).inflate(R.layout.item_category,parent,false);//传入单个item的布局
              //定义视图类并绑定组件
              ImageView image =view.findViewById(R.id.category_image);
              TextView name=view.findViewById(R.id.category_text);
              //提取数据并赋值到视图类
              String imgurl = categorie.getPicture();
              Uri uri = Uri.parse(imgurl);
              Glide.with(getContext())
                      .load(uri)
                      .apply(options2)
                      .into(image);
              return view;
          }
      }
      
  4. 定义使用适配器

    在主函数中list设置适配器来获得整个列表的数据

    mAdapter = new OrderAdapter(this,R.layout.item_category,Ocategories);//赋予单项的布局
    listView.setAdapter(mAdapter);
    
2.RecyclerView列表

? RecyclerView能实现复杂的listview,如横着滑动或者一行三个的布局。

  1. 定义及数据获取相同

  2. 适配器类定义

    public class FoodAdapter extends RecyclerView.Adapter<FoodAdapter.ViewHolder> {
        //1.适配器初始化,传入list数据
        public FoodAdapter(List<Food> cardList) {
            this.cardList = cardList;
        }
    	//2.初始化view,获得view
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_order, parent, false);
            //将view和上下文变为全局变量
            mview=view;
            mContext = parent.getContext();
            return new ViewHolder(view);
        }
    
        @Override
        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
            //获得列表中的数据
            Food card = cardList.get(position);
            //从数据源中提取数据
            /*以card为例*/
            String imgurl = card.getPicture();
            String name = card.getName();
            String price = card.getPrice();
           //将数据赋值到视图变量
            Glide.with(mContext)
                .load(uri)
                .apply(options)
                .into(holder.FoodImage);
        }
    
        @Override
        public int getItemCount() {
            return cardList.size();
        }
     //3.定义视图类并绑定xml组件
        public class ViewHolder extends RecyclerView.ViewHolder {
            ImageView FoodImage;
            public ViewHolder(@NonNull View itemView) {
                super(itemView);
                FoodImage = itemView.findViewById(R.id.food_imageView);
            }
        } 
    }
    
  3. RecyclerView可以通过setLayoutManager实现多种布局

3.fragment适配器

? viewpaper2+tablayout可以适配多个fragment,实现的就是导航栏切换页面的效果。

  1. 适配器类继承FragmentStateAdapter

    public class ProjectItemDataAdapter extends FragmentStateAdapter {
        List<PItemDataFragment> fragments;
        //初始化
        public ProjectItemDataAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle, List<PItemDataFragment> fragments) {
            super(fragmentManager, lifecycle);
            this.fragments = fragments;
        }
    
        @NonNull
        @Override
        public Fragment createFragment(int position) {
            return fragments.get(position);
        }
    
        @Override
        public int getItemCount() {
            return fragments.size();
        }
    }
    
  2. 使用适配器并关联TabLayout和Viewpaper2

    //实例化适配器
    myAdapter=new KnowItemAdapter(fm,lc,chFragments);
    //viewpaper类设置适配器
    wxPager2.setAdapter(myAdapter);
    //TabLayout和Viewpager2进行关联
    new TabLayoutMediator(wxTab, wxPager2, new TabLayoutMediator.TabConfigurationStrategy() {
        @Override
        public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
            //可进行对标题栏各单项进行操作
            tab.setText(titles.get(position));
        }
    }).attach();
    
  3. 会遇到的问题

    因为viewpaper2和fragment结合包含多个嵌套,会出现该fragment其实是外部的tablayout导航栏的某一页面,而其中的fragment中也包含list,所以也会进行list定义及数据获取。

    • Fragment no longer exists for key f0: index 0错误

      • 实现背景:在二级fragment中(即外部导航栏的某一页中的导航栏的某一页)用retrofit获取数据,填充列表

      • 错误描述:外部的导航栏切换至其他页面再切换回本页面(一级)会闪退

      • 外部原因:获得fragment出错

      • 重写fragment的生命周期函数,输出各全局变量的值

            @Override
            public void onCreate(@Nullable Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                Log.v(TAG,"KnowChapterFragment创建");
                Log.v(TAG,"此时的cid为"+id);
                Log.v(TAG,"此时的page为"+page);
            }
        

        发现,虽然切换到其他页面(外部导航栏),该fragment已经销毁(执行onDestory),但是全局变量的数据仍然还在,也就是说,retrofit获得的数据仍然存在全局变量list中。

        • 因此,在退出时需要对全局变量执行清零操作
        @Override
        public void onDestroy() {
            Articledatas.clear();
            page=1;
            super.onDestroy();
        }
        

      当多个组件嵌套无从下手时,可以在形成过程中重写调试输出来获得变量值以求解。

    • Fragment has not been attached yet

4.适配器使用
  1. 以上举例的adapter是执行的是一次性数据显示;

  2. api获得数据常常会传入页数来分批次获得大量的数据,所以对应的adapter也可以通过adapter.notifyDataSetChanged();来实现列表数据更新

    • 会达到一个数据闪现更新的效果

    • 注:不需要重新new一个adapter和重写绑定数据列表,更新只需要在原本已经绑定以及数据列表数据更新的基础上,执行上诉语句即可。

    • 如果多次new,可能会报错

      • 所以就像上述第三点中的闪退问题,需要在退出时将page置为1,否则多次new会报错。
      if(page==1)	//api网址传入的界面
      {
          if(getActivity()!=null)
          {
              adapter = new KnowledgeAdapter(getContext(),R.layout.item_acticle,Articledatas);
          }
          listView.setAdapter(adapter);
          setAdapterClick();
      }
      else
      {
          if(setOverText())
          {
              adapter.notifyDataSetChanged();	//更新
              loadMoreButton.setText("查看更多...");  //恢复按钮文字
          }
      }
      

文章来源:https://blog.csdn.net/qq_56611561/article/details/135484865
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。