安卓中api数据adapter填充列表及嵌套fragment遇到的闪退问题
安卓中,从api中获取数据并填充到listview、RecyclerView以及fragment的各个adapter适配器的定义以及绑定的基本步骤及相关问题。
1.列表listview
? listview是常见的列表视图。
-
定义
listview
XML
定义<listview>
activity
定义listview类- 类绑定
xml
的id
-
获得数据
-
调用
retrofit
将api中的数据存入数据类retrofit
小白使用步骤:Retrofit2 实战(一、使用详解篇) - 掘金 (juejin.cn) -
利用
rxjava
将获得网络线程获得的数据提取到主线程使用rxjava结合retrofit获得数据:Rxjava+Retrofit简单使用-CSDN博客
-
-
设置适配器
连接UI并赋予单个item数据,数据由外部传入
-
继承
ArrayAdapter<T>
- 在
getView
中定义对单个Item中组件取值并赋值
- 在
-
初始化
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; } }
-
-
定义使用适配器
在主函数中list设置适配器来获得整个列表的数据
mAdapter = new OrderAdapter(this,R.layout.item_category,Ocategories);//赋予单项的布局 listView.setAdapter(mAdapter);
2.RecyclerView
列表
? RecyclerView能实现复杂的listview,如横着滑动或者一行三个的布局。
-
定义及数据获取相同
-
适配器类定义
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); } } }
-
RecyclerView可以通过setLayoutManager实现多种布局
-
以每行三个item的布局为例
mRecyclerView = findViewById(R.id.recyclerview); mRecyclerView.setLayoutManager(new GridLayoutManager(this, 3));
-
3.fragment适配器
? viewpaper2+tablayout可以适配多个fragment,实现的就是导航栏切换页面的效果。
-
适配器类继承
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(); } }
-
使用适配器并关联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();
-
会遇到的问题
因为viewpaper2和fragment结合包含多个嵌套,会出现该fragment其实是外部的tablayout导航栏的某一页面,而其中的fragment中也包含list,所以也会进行list定义及数据获取。
-
Fragment no longer exists for key f0: index 0
错误-
实现背景:在二级fragment中(即外部导航栏的某一页中的导航栏的某一页)用retrofit获取数据,填充列表
-
错误描述:外部的导航栏切换至其他页面再切换回本页面(一级)会闪退
-
外部原因:获得fragment出错
- 解决方法:
wxPager2.setSaveEnable(false)
,参考链接viewpager2 Fragment no longer exists for key f#0:-CSDN博客 - 具体源码分析:Fragment no longer exists for key f0: index 0-CSDN博客
- 解决方法:
-
重写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
- 错误描述:闪退
- 解决方法:在
onCreateView
中定义视图,在onViewCreated
中绑定组件并配置适配器;
-
4.适配器使用
-
以上举例的adapter是执行的是一次性数据显示;
-
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("查看更多..."); //恢复按钮文字 } }
-
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!