安卓:底部导航栏中的Recyclerview用SQLite填充的片段将不会更新



我有一个包含3个片段的BottomNavigationBar。在第一个片段中,我尝试将SQLite数据放入回收视图中。它工作得很好,只是我需要在导航栏项目之间切换才能看到刷新的recyclerview。然而,当我使用带有postDelayed的处理程序时,如果我设置大约1秒的延迟,它确实会显示刷新的recyclerview。0.2秒已经不行了。

尽管这仍然是非常通用的:有什么最佳实践吗?在我看来,我需要使用AsyncTask,但它已经被弃用了。

谢谢!

Simon

主页片段

public class HomeFragment extends Fragment {

private HomeViewModel homeViewModel;
private Context context;
private CardView cardview;
private LinearLayout.LayoutParams layoutparams;
private TextView textview;
private RelativeLayout relativeLayout;
private myDbAdapter helper;
RecyclerView myView;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
homeViewModel =
new ViewModelProvider(this).get(HomeViewModel.class);
View root = inflater.inflate(R.layout.fragment_home, container, false);

helper  = new myDbAdapter(getContext());
myView = (RecyclerView) root.findViewById(R.id.recyclerview_home);
RecyclerViewAdapter3 adapter = new RecyclerViewAdapter3(new ArrayList<String>(Arrays.asList(helper.classes())));
myView.setHasFixedSize(true);
myView.setAdapter(adapter);
LinearLayoutManager llm = new LinearLayoutManager(getContext());
llm.setOrientation(LinearLayoutManager.VERTICAL);
myView.setLayoutManager(llm);

homeViewModel.getText().observe(getViewLifecycleOwner(), new Observer<String>() {
@Override
public void onChanged(@Nullable String s) {
textView.setText(s);
}
});
return root;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);

}
public void refresh(View v){
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
myView = (RecyclerView) v.findViewById(R.id.recyclerview_home);
helper  = new myDbAdapter(v.getContext());
ArrayList<String> classes = new ArrayList(Arrays.asList(helper.classes()));
ArrayList<String> subClasses = new ArrayList(Arrays.asList(helper.subClasses()));
RecyclerViewAdapter3 adapter = new RecyclerViewAdapter3(classes);
myView.setHasFixedSize(true);
myView.setAdapter(adapter);
LinearLayoutManager llm = new LinearLayoutManager(v.getContext());
llm.setOrientation(LinearLayoutManager.VERTICAL);
myView.setLayoutManager(llm);
}
}, 1000); //time in millis
}
}

RecyclerViewAdapter3

public class RecyclerViewAdapter3 extends RecyclerView.Adapter<RecyclerViewAdapter3.MyViewHolder> {
public ArrayList<String> classArrayList;
public ArrayList<String> subClassArrayList;
myDbAdapter helper;

public RecyclerViewAdapter3(ArrayList<String> classArrayList){
this.classArrayList = classArrayList;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View listItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardview, parent, false);
return new MyViewHolder(listItem);
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.class.setText(classArrayList.get(position));
holder.delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
helper = new myDbAdapter(v.getContext());
helper.delete(classArrayList.get(position));
HomeFragment homeFragment = new HomeFragment();
homeFragment.refresh(v.getRootView());
}
});
holder.selectButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

}});}
@Override
public int getItemCount() {
return classArrayList.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
private TextView class;
private Button selectButton;
private ImageView delete;
public MyViewHolder(View itemView) {
super(itemView);
class = (TextView)itemView.findViewById(R.id.name);
selectButton = (Button) itemView.findViewById(R.id.selectButton);
delete = (ImageView) itemView.findViewById(R.id.delete);
}
}
}

感谢您发布代码:(

在您的代码中,有相当多的事情可能会出错,因为现在是这样,当您使用postDelay时,我真的无法确定是什么原因导致它工作。我将列出一些,你可以查看:

从ViewHolder中的onClick()
HomeFragment homeFragment = new HomeFragment();
homeFragment.refresh(v.getRootView());

您真的不应该像这样实例化您的片段。相反,您可以将回调从片段传递到适配器(例如:View.OnClickListener(

您不断地不必要地重新实例化适配器和助手。您应该只创建一次适配器,将其设置为回收器视图适配器,并将其保存在成员变量中。

建议的解决方案

我看到您已经在使用ViewModel了,所以对于不易出错的屏幕来说,这是一条很好的道路,所以我建议您将数据库查询逻辑转移到视图模型中。如果您使用的是原始SQLite(而不是Room(,则可以扩展AndroidViewModel,这样您就可以立即访问上下文。与使用homeViewModel.getText()一样,应该将classes数组公开为活动数据,观察它,并将新列表提交给适配器。

为了将列表提交给适配器,我建议使用ListAdapter,这将为您提供一个submitList方法来提交片段中的列表,在适配器内部,您将有一个getItem(int position)方法,您可以在onBindViewHolder方法中查询该方法。

在你的碎片里,它看起来像这样:

ClassAdapter adapter = null;
View onCreateView(Bundle savedInstanceState) {
super.onCreate(savedInstanceState)
View root = inflater.inflate(R.layout.fragment_home, container, false);

adapter = new ClassAdapter(
new ClassDeleteCallback() {
@Override
void onClassDeleted(Class class) {
// inside view model we can modify db state, than refresh live data
viewModel.deleteClass(class);
}
},
new ClassSelectedCallback() {
// follows same pattern of above
}
);
RecyclerView rv = root.findViewById(R.id.my_rv);
rv.setAdapter(adapter);
rv.setLayoutManager(new LinearLayoutManager(getContext());


homeViewModel.getClasses().observe(getViewLifecycleOwner(), new Observer<List<Class>>() {
@Override
public void onChanged(@Nullable List<Class> classes) {
adapter.submitList(classes);
}
});
homeViewModel.refreshClasses();
return root;
}

我强烈建议你研究一下这个项目,因为它涵盖了很多基础知识,可以带来一个更稳定的应用程序:向日葵样本应用程序

我认为你应该多读一点关于架构组件的内容,然后浏览一些代码实验室和其他东西,然后再从第一个开始使用这个屏幕,因为这比修复当前状态更容易:(

我希望这是有帮助的,不要太令人沮丧!

最新更新