Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/212.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android RecyclerView无法平滑滚动_Android_Listview_Android Asynctask_Android Recyclerview - Fatal编程技术网

Android RecyclerView无法平滑滚动

Android RecyclerView无法平滑滚动,android,listview,android-asynctask,android-recyclerview,Android,Listview,Android Asynctask,Android Recyclerview,我有一个应用程序,其中我有几个视图(不同类型的列表项)在一个RecyclerView内。从数据库中获取数据后,每个项目都会更新。在我的RecyclerView中滚动项目时,我面临着粘性滚动的问题。我确信这是由于数据库访问操作造成的,我试图解决这个问题。我参考了关于StackOverflow的几个答案,并通读了官方的android post()。正如android帖子中所建议的那样,我使用AsyncTask将所有数据库访问操作移动到后台线程,但仍然没有找到任何运气。 下面是我在onBindView

我有一个应用程序,其中我有几个视图(不同类型的列表项)在一个RecyclerView内。从数据库中获取数据后,每个项目都会更新。在我的RecyclerView中滚动项目时,我面临着粘性滚动的问题。我确信这是由于数据库访问操作造成的,我试图解决这个问题。我参考了关于StackOverflow的几个答案,并通读了官方的android post()。正如android帖子中所建议的那样,我使用AsyncTask将所有数据库访问操作移动到后台线程,但仍然没有找到任何运气。 下面是我在
onBindViewHolder
中编写的代码,用于更新其中一个项目。

new AsyncTask<RecyclerView.ViewHolder, Void, TaskPhysicalActivity>(){
                private RecyclerView.ViewHolder v;
                PhysicalActivityItemHolder pAItemHolder;
                DBHelper mDbHelper;
                User mUser;
                @Override
                protected TaskPhysicalActivity doInBackground(RecyclerView.ViewHolder... params) {
                    pAItemHolder = (PhysicalActivityItemHolder)params[0];
                    Calendar cal = Calendar.getInstance();
                    Calendar today = Calendar.getInstance();
                    Calendar earlier = Calendar.getInstance();
                    earlier.add(Calendar.DATE, -6);
                    mDbHelper = DBHelper.getInstance(mContext);
                    mUser = User.getDefaultUser(mContext);
                    try {
                        List<PhysicalActivity> physicalActivities = mDbHelper.getPhysicalActivityInRange(mUser, cal, cal);
                        PhysicalActivityReport physicalActivityReport = new PhysicalActivityReport(earlier.getTime(), today.getTime());
                        physicalActivityReport.makeReport(mContext, mUser);
                        int userStepGoal = PhysicalActivity.getDailyStepsGoal(mContext);
                        return new TaskPhysicalActivity(userStepGoal, physicalActivityReport.getPhysicalActivityList(), physicalActivities,physicalActivityReport);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    return null;
                }


                @Override
                protected void onPostExecute(TaskPhysicalActivity taskPhysicalActivity) {
                    int stepsCount = 0;
                    Calendar cal = Calendar.getInstance();
                    TaskPhysicalActivity taskPhysicalActivityObject = taskPhysicalActivity;
                    List<PhysicalActivity> physicalActivities = taskPhysicalActivityObject.getPhysicalActivities();
                    List<PhysicalActivity> activityList = taskPhysicalActivityObject.getActivityList();
                    PhysicalActivityReport physicalActivityReport = taskPhysicalActivityObject.getPhysicalActivityReport();

                    pAItemHolder.tvActivityEmptyText.setVisibility(View.GONE);

                    if (physicalActivities.size() > 0) {
                        for (int i = 0; i < physicalActivities.size(); i++) {
                            stepsCount = stepsCount
                                    + physicalActivities.get(i).getValue();
                        }

                        final int finalStepsCount = stepsCount > 0 ? stepsCount : 0;
                        pAItemHolder.tvActivityValue.setText(String.valueOf(finalStepsCount));
                        pAItemHolder.tvActivityValueText.setText(mContext.getResources().getString(R.string.steps_unit));
                        pAItemHolder.tvActivityEmptyText.setText("");
                        pAItemHolder.vActivityCardEmptyView.setVisibility(View.GONE);
                        pAItemHolder.vActivityCardView.setVisibility(View.VISIBLE);

                    } else {

                        pAItemHolder.tvActivityValue.setText("--");
                        pAItemHolder.tvActivityValueText.setText(mContext.getResources().getString(R.string.steps_unit));
                        pAItemHolder.tvActivityEmptyText.setText("");
                        pAItemHolder.vActivityCardEmptyView.setVisibility(View.VISIBLE);
                        pAItemHolder.vActivityCardView.setVisibility(View.GONE);

                    }

                    pAItemHolder.tvActivityGoal.setText(String.format(mContext.getResources().getString(R.string.activity_goal_display_string),
                            taskPhysicalActivityObject.getUserStepsGoal(), mContext.getResources().getString(R.string.steps_unit), mContext.getResources().getString(R.string.per_day)));
                    pAItemHolder.vActivityGraph.setActivityValues(activityList);

                    if (physicalActivityReport.getPhysicalActivityAverage() > 0) {
                        pAItemHolder.tvPercentInRange.setText("Average steps " + physicalActivityReport.getPhysicalActivityAverage());
                    }
                    if (activityList.size() == 0) {
                        pAItemHolder.vActivityCardEmptyView.setVisibility(View.VISIBLE);
                        pAItemHolder.vActivityCardView.setVisibility(View.GONE);
                    } else {
                        pAItemHolder.vActivityCardEmptyView.setVisibility(View.GONE);
                        pAItemHolder.vActivityCardView.setVisibility(View.VISIBLE);
                    }
                }
            }.execute(holder);
我使用这些操作的结果更新
onPostExecute
方法中的UI。

我使用AsyncTask的方式是否有问题?我遗漏了什么吗?

问题是,您在
onBindViewHolder
中调用了此代码。这意味着,此代码将针对
RecyclerView
中新显示的每一行执行(并在滚动时对同一行执行多次!!)

将此代码移动到
活动
片段
(列表中的任何内容)如何?这样,代码将执行一次。然后将此处解析的数据包装到自定义POJO对象中:

public class POJO {
    String activityValue;
    String activityValueText;
    String activityEmptyText;
    boolean activityCardEmptyViewVisibility;
    boolean activityCardViewVisibility;
}
将此类类作为传递给
RecyclerView
的对象。然后,在
onBindViewHolder
内部使用
getItem(position)
并将数据从
POJO
传递到
Holder


执行
活动
中的所有逻辑(或任何控制器,按Enter键,任何用于业务逻辑的操作)。这就是它的目的<代码>适配器仅用于显示结果,而不是为应用程序创建业务逻辑。

感谢@Rafal和@r-zagórski提供的宝贵建议。我尝试了保持数据准备就绪并将其传递给onBindViewHolder的方法,但由于某些原因,没有起到任何作用。 然后,我将onBindViewHolder中的所有代码移动到onCreateViewHolder,并将一个对象传递给适配器构造函数,其中包含已在该对象中计算和打包的所有必需参数。因此,请列出以下步骤:

  • 创建一个类(比如DataClass)来保存所有必需的值及其getter,以便在更新期间稍后在recyclerView适配器中使用
  • 由于数据库访问是内存密集型的,所以使用AsyncTask在
    doInBackground
    方法中执行所有数据库访问操作,并使其返回DataClass的对象

     protected DataClass doInBackground(Params... params) {
     //perform database or other operations here
     // Let's say DataClass constructor takes in 3 parameters which are later used to update recycler view 
        return new DataClass(data1, data2, data3);
     }
    
  • 现在在
    doInBackground
    完成执行后调用的
    onPostExecute
    方法中更新recyclerView。我确信这不是最佳实践,但每次我想更新适配器时,我都必须重新初始化适配器,因为我需要将DataClass对象传递给它

    protected void onPostExecute(DataClass dataObject) {
     mRecyclerViewAdapter = new RecyclerViewAdapter(dataObject, .....);
     mRecylerView.setAdapter(mRecyclerViewAdapter);
     //Notify Data set or Item changed if required
    }
    
  • 不要忘记为您的RecycleServiceAdapter编写自定义构造函数,以便将dataObject传递给它

  • protected void onPostExecute(DataClass dataObject) {
     mRecyclerViewAdapter = new RecyclerViewAdapter(dataObject, .....);
     mRecylerView.setAdapter(mRecyclerViewAdapter);
     //Notify Data set or Item changed if required
    }
    

    我这样解决了我的问题。除了第一次创建片段时,滚动是平滑的。

    onbindToViewHolder方法用于快速获取对象、加载其内容并将此内容加载到视图,而不是执行逻辑。AcyncTask或线程应位于fragment或Activity中。唯一的结果应该传递给适配器,所以当绑定到视图持有者时,你们应该准备好你们的数据。@Rafal你们的答案听起来很棒!您是否有任何示例片段可以演示相同的功能?就连我也面临着FirebaseRecyclerAdapter中的一个粘性和滞后的卷轴的问题。非常感谢您的帮助。谢谢