android - 无法从我的模型类更新 RecyclerView?

标签 android android-recyclerview notifydatasetchanged

我正在开发一个 RecyclerView,它必须是可拖动和可滑动的。一切都很完美。

数据在一个名为 ExerciseDataProvider 的类中获取,RV 代码是另一个 fragment RecyclerListViewFragment

问题是我无法在 postExecute 方法上通知从 FetchExercise 更改的数据。因此数据不会填充到 RV 中。

请指引我正确的方向。

Activity

    public class DraggableSwipeableExampleActivity extends AppCompatActivity {
        private static final String FRAGMENT_TAG_DATA_PROVIDER = "data provider";
        private static final String FRAGMENT_LIST_VIEW = "list view";
        private static final String FRAGMENT_TAG_ITEM_PINNED_DIALOG = "item pinned dialog";

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_demo);

            if (savedInstanceState == null) {
                getSupportFragmentManager().beginTransaction()
                        .add(new ExampleDataProviderFragment(), FRAGMENT_TAG_DATA_PROVIDER)
                        .commit();
                getSupportFragmentManager().beginTransaction()
                        .add(R.id.container, new RecyclerListViewFragment(), FRAGMENT_LIST_VIEW)
                        .commit();
            }
        }

 public AbstractDataProvider getDataProvider() {
        final Fragment fragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG_DATA_PROVIDER);
        return ((ExampleDataProviderFragment) fragment).getDataProvider();
    }

数据提供者

public class ExerciseDataProvider extends AbstractDataProvider {
    private List<ConcreteData> mData;
    private ConcreteData mLastRemovedData;
    private int mLastRemovedPosition = -1;

    public ExerciseDataProvider() {
        new FetchExercise().execute();
        mData = new LinkedList<>();
    }

    class FetchExercise extends AsyncTask<Void,Void,Void> {

        @Override
        protected Void doInBackground(Void... params) {
            final int viewType = 0;
            final int swipeReaction = RecyclerViewSwipeManager.REACTION_CAN_SWIPE_UP | RecyclerViewSwipeManager.REACTION_CAN_SWIPE_DOWN;

            String url = "https://gist.githubusercontent.com/fake/cb9aa5494e7ee36ac3ca/raw/a4abfd19368063/exercise.JSON";
            Log.d("Path", url);
            try {
                OkHttpClient client = new OkHttpClient();
                Request request = new Request.Builder().url(url).build();
                Response response = client.newCall(request).execute();
                String jsonData = response.body().string();
                try {
                    JSONArray jsonArray = new JSONArray(jsonData);
                    for (int i = 0; i < jsonArray.length(); i++) {
                        final long id = i;
                        JSONObject jsonObject = jsonArray.getJSONObject(i);
                        String exercise_name = jsonObject.getString("name");
                        int exercise_duration = jsonObject.getInt("duration");

                        mData.add(new ConcreteData(id, viewType, exercise_name, exercise_duration, swipeReaction));
                        Log.d("exercise_name", exercise_name);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
        }
    }


    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public Data getItem(int index) {
        if (index < 0 || index >= getCount()) {
            throw new IndexOutOfBoundsException("index = " + index);
        }

        return mData.get(index);
    }

    @Override
    public int undoLastRemoval() {
        if (mLastRemovedData != null) {
            int insertedPosition;
            if (mLastRemovedPosition >= 0 && mLastRemovedPosition < mData.size()) {
                insertedPosition = mLastRemovedPosition;
            } else {
                insertedPosition = mData.size();
            }

            mData.add(insertedPosition, mLastRemovedData);

            mLastRemovedData = null;
            mLastRemovedPosition = -1;

            return insertedPosition;
        } else {
            return -1;
        }
    }

    @Override
    public void moveItem(int fromPosition, int toPosition) {
        if (fromPosition == toPosition) {
            return;
        }

        final ConcreteData item = mData.remove(fromPosition);
        mData.add(toPosition, item);
        mLastRemovedPosition = -1;
    }

    @Override
    public void removeItem(int position) {
        //noinspection UnnecessaryLocalVariable
        final ConcreteData removedItem = mData.remove(position);

        mLastRemovedData = removedItem;
        mLastRemovedPosition = position;
    }

    public static final class ConcreteData extends Data {

        private final long mId;
        private final String mText;
        private final int mViewType;
        private final int mDuration;
        private boolean mPinned;

        ConcreteData(long id, int viewType, String text, int duration, int swipeReaction) {
            mId = id;
            mViewType = viewType;
            mText = text;
            mDuration = duration;
        }

        @Override
        public int getViewType() {
            return mViewType;
        }

        @Override
        public int getDuration() {
            return mDuration;
        }

        @Override
        public long getId() {
            return mId;
        }

        @Override
        public String toString() {
            return mText;
        }

        @Override
        public String getText() {
            return mText;
        }

        @Override
        public boolean isPinned() {
            return mPinned;
        }

        @Override
        public void setPinned(boolean pinned) {
            mPinned = pinned;
        }

    }
}

RecyclerListViewFragment

public class RecyclerListViewFragment extends Fragment {
    private RecyclerView mRecyclerView;
    private RecyclerView.LayoutManager mLayoutManager;
    private RecyclerView.Adapter mAdapter;
    private RecyclerView.Adapter mWrappedAdapter;
    private RecyclerViewDragDropManager mRecyclerViewDragDropManager;
    private RecyclerViewSwipeManager mRecyclerViewSwipeManager;
    private RecyclerViewTouchActionGuardManager mRecyclerViewTouchActionGuardManager;

    public RecyclerListViewFragment() {
        super();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_recycler_list_view, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        //noinspection ConstantConditions
        mRecyclerView = (RecyclerView) getView().findViewById(R.id.recycler_view);
        mLayoutManager = new LinearLayoutManager(getContext());

        // touch guard manager  (this class is required to suppress scrolling while swipe-dismiss animation is running)
        mRecyclerViewTouchActionGuardManager = new RecyclerViewTouchActionGuardManager();
        mRecyclerViewTouchActionGuardManager.setInterceptVerticalScrollingWhileAnimationRunning(true);
        mRecyclerViewTouchActionGuardManager.setEnabled(true);

        // drag & drop manager
        mRecyclerViewDragDropManager = new RecyclerViewDragDropManager();
        mRecyclerViewDragDropManager.setDraggingItemShadowDrawable(
                (NinePatchDrawable) ContextCompat.getDrawable(getContext(), R.drawable.material_shadow_z3));

        // swipe manager
        mRecyclerViewSwipeManager = new RecyclerViewSwipeManager();

        //adapter
        final MyDraggableSwipeableItemAdapter myItemAdapter = new MyDraggableSwipeableItemAdapter(getDataProvider());
        myItemAdapter.setEventListener(new MyDraggableSwipeableItemAdapter.EventListener() {
            @Override
            public void onItemRemoved(int position) {
                ((DraggableSwipeableExampleActivity) getActivity()).onItemRemoved(position);
            }

            @Override
            public void onItemViewClicked(View v, boolean pinned) {
                onItemViewClick(v, pinned);
            }
        });

        mAdapter = myItemAdapter;

        mWrappedAdapter = mRecyclerViewDragDropManager.createWrappedAdapter(myItemAdapter);      // wrap for dragging
        mWrappedAdapter = mRecyclerViewSwipeManager.createWrappedAdapter(mWrappedAdapter);      // wrap for swiping

        final GeneralItemAnimator animator = new SwipeDismissItemAnimator();
        animator.setSupportsChangeAnimations(false);

        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.setAdapter(mWrappedAdapter);  // requires *wrapped* adapter
        mRecyclerView.setItemAnimator(animator);

        // additional decorations
        //noinspection StatementWithEmptyBody
        if (supportsViewElevation()) {
            // Lollipop or later has native drop shadow feature. ItemShadowDecorator is not required.
        } else {
            mRecyclerView.addItemDecoration(new ItemShadowDecorator((NinePatchDrawable) ContextCompat.getDrawable(getContext(), R.drawable.material_shadow_z1)));
        }
        mRecyclerView.addItemDecoration(new SimpleListDividerDecorator(ContextCompat.getDrawable(getContext(), R.drawable.list_divider_h), true));
        mRecyclerViewTouchActionGuardManager.attachRecyclerView(mRecyclerView);
        mRecyclerViewSwipeManager.attachRecyclerView(mRecyclerView);
        mRecyclerViewDragDropManager.attachRecyclerView(mRecyclerView);
    }

    @Override
    public void onPause() {
        mRecyclerViewDragDropManager.cancelDrag();
        super.onPause();
    }

    @Override
    public void onDestroyView() {
        if (mRecyclerViewDragDropManager != null) {
            mRecyclerViewDragDropManager.release();
            mRecyclerViewDragDropManager = null;
        }

        if (mRecyclerViewSwipeManager != null) {
            mRecyclerViewSwipeManager.release();
            mRecyclerViewSwipeManager = null;
        }

        if (mRecyclerViewTouchActionGuardManager != null) {
            mRecyclerViewTouchActionGuardManager.release();
            mRecyclerViewTouchActionGuardManager = null;
        }

        if (mRecyclerView != null) {
            mRecyclerView.setItemAnimator(null);
            mRecyclerView.setAdapter(null);
            mRecyclerView = null;
        }

        if (mWrappedAdapter != null) {
            WrapperAdapterUtils.releaseAll(mWrappedAdapter);
            mWrappedAdapter = null;
        }
        mAdapter = null;
        mLayoutManager = null;

        super.onDestroyView();
    }

    private void onItemViewClick(View v, boolean pinned) {
        int position = mRecyclerView.getChildAdapterPosition(v);
        if (position != RecyclerView.NO_POSITION) {
            ((DraggableSwipeableExampleActivity) getActivity()).onItemClicked(position);
        }
    }

    public AbstractDataProvider getDataProvider() {
        return ((DraggableSwipeableExampleActivity) getActivity()).getDataProvider();
    }

    public void notifyItemChanged(int position) {
        mAdapter.notifyItemChanged(position);
    }

    public void notifyItemInserted(int position) {
        mAdapter.notifyItemInserted(position);
        mRecyclerView.scrollToPosition(position);
    }
}

最佳答案

要在数据提供程序类中从 onPostExecute 更新 recyclerView,您的 onPostExecute 应该可以访问 context,其中您的 recyclerView 已定义。

由于您的 FetchExercise 异步任务是在 ExerciseDataProvider 类中定义的,请尝试将 activity context 传递给 ExerciseDataProvider 的构造函数,然后将其传递给 FetchExercise 异步任务,如下所述:getting context in AsyncTask

public class MyCustomTask extends AsyncTask<Void, Void, Long> {
    private Context mContext;
        public MyCustomTask (Context context){
           mContext = context;
        }
        protected void onPostExecute(Long result) {
           //use mContext to update recycler view
        }
    }
}

使用context更新recyclerView


更新

第一步

定义一个接口(interface),它会通知您的activity数据集在初始化您的data provider class的类中发生变化并传递 Activity 上下文数据提供者类的构造函数。

public class ExampleDataProviderFragment extends Fragment {
    private AbstractDataProvider mDataProvider;

    //Define an interface that will notify your activity of data set change
    public interface EventListener {
        void onNotifyDataSetChanged();
    }

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

        setRetainInstance(true); 

        //Pass activity context to ExerciseDataProvider
        mDataProvider = new ExerciseDataProvider(getActivity());
    }

    public AbstractDataProvider getDataProvider() {
        return mDataProvider;
    }
}

第 2 步

context 参数添加到ExerciseDataProvider 的构造函数,并使用它来通知实现您的接口(interface)的 Activity 以通知数据集更改。

public class ExerciseDataProvider extends AbstractDataProvider {
    private List<ConcreteData> mData;
    private ConcreteData mLastRemovedData;
    private int mLastRemovedPosition = -1;

    //Add context parameter to constructor
    public ExerciseDataProvider(Context context) {

        //Pass context to async task

        new FetchExercise(context).execute();
        mData = new LinkedList<>();
    }

    class FetchExercise extends AsyncTask<Void,Void,Integer> {
        Context mContext;

        public FetchExercise(Context context) {
            mContext = context;
        }

        @Override
        protected Integer doInBackground(Void... params) {
            ...
            return 1;
        }

        @Override
        protected void onPostExecute(Integer result) {
            super.onPostExecute(result);

            //Typecast context to interface defined above 
            //and notify dataset changes by calling its method

            ExampleDataProviderFragment.EventListener eventListener = (ExampleDataProviderFragment.EventListener)mContext;
            eventListener.onNotifyDataSetChanged();

        }
    }
}

第 3 步

在你的activity class中实现上面定义的interface,并通知里面的recyclerviewadapter

public class DraggableSwipeableExampleActivity extends AppCompatActivity 
    implements ExampleDataProviderFragment.EventListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
    }

    //implement interface method and notify recyclerview of changes
    @Override
    public void onNotifyDataSetChanged() {
        Fragment fragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_LIST_VIEW);

        // you might need to change visibility of `mWrappedAdapter` in the fragment that defines it or create a getter for it so that you can access it here
        ((RecyclerListViewFragment) fragment).mWrappedAdapter.notifyDataSetChanged(); 

    }
 ...
}

关于android - 无法从我的模型类更新 RecyclerView?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35954641/

相关文章:

php - 需要 php 代码才能使用 ACS 在 Android 设备上发送推送通知

java - Android Studio 无法读取 Mega .so 库

java - 在 Android 中使用 MediaPlayer 播放 mp3 文件列表

Android Studio Recyclerview 使用 Retrofit

安卓适配器 "java.lang.IndexOutOfBoundsException: Invalid index 4, size is 4"

android - 用户输入日期的最佳方式是什么

java - 当我的 recyclerview 中的所有复选框都未选中时,如何显示 toast ?

java - 在回收 View 中执行过滤时,屏幕上的数据显示不正确

android - 来自不同 fragment 的 notifyDataSetChanged()

java - 从 onActivityResult() 调用时,notifyDataSetChanged() 不适用于我的 RecyclerView.Adapter