【问题标题】:RecyclerView not refreshing after rotating the device with an open DialogFragment使用打开的 DialogFragment 旋转设备后 RecyclerView 不刷新
【发布时间】:2017-07-01 06:55:38
【问题描述】:

我在AppCompatActivity 中有一个RecyclerView。旋转设备后,项目插入和更改会正确显示和动画。

问题发生在您:

  1. 点击RecyclerView 中的项目。
  2. DialogFragment 会打开提示您是否要删除该项目。
  3. 旋转设备。
  4. 在对话框中确认删除。
  5. 检查阵列列表。该项目已被删除。
  6. RecyclerView 仍然显示该项目。

尝试使用notifyDataSetChanged 而不是notifyItemRemoved,但也不起作用,因为该项目仍在RecyclerView 中显示。

任何版本的 Android 都会发生这种情况。

流程处理方式的简化代码:

public class MyAppCompatActivity extends AppCompatActivity {
        int positionOfDeletedItem;
        MyObjectRecyclerViewAdapter adapter;
        ArrayList<MyObject> someTestData;
        MyItemDeletionHandler deletionHandlerRemover;

        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.my_activity_layout);

            RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
            positionOfDeletedItem = 1;
            deletionHandlerRemover = new MyItemDeletionHandler(this);

            someTestData = new ArrayList<MyObject>(3);
            someTestData.add(new MyObject("A"));
            someTestData.add(new MyObject("B"));
            someTestData.add(new MyObject("C"));

            recyclerView.setHasFixedSize(true);
            recyclerView.setLayoutManager(new LinearLayoutManager(this));

            adapter = new MyObjectRecyclerViewAdapter(new MyAdapterOnClickEvent.OnItemClick() {
                @Override
                public void onClick(int posicion, int idViaje, View view) {
                    String tag = "Some tag value";
                    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
                    Fragment prev = getSupportFragmentManager().findFragmentByTag(tag);
                    if(prev != null)
                        ft.remove(prev);
                    ft.addToBackStack(null);
                    DialogFragment newFragment = MyDeletionConfirmationDialog.newInstance(deletionHandlerRemover);
                    newFragment.show(ft, tag);
                }
            }, someTestData);
            recyclerView.setAdapter(adapter);
        }

        private final static class MyItemDeletionHandler extends Handler {
            private final WeakReference<MyAppCompatActivity> theActivity;

            private MyItemDeletionHandler(MyAppCompatActivity act) {
                theActivity = new WeakReference<MyAppCompatActivity>(act);
            }
            @Override
            public void handleMessage(Message msg) {
                MyAppCompatActivity activity = theActivity.get();
                if(activity != null) {
                    if(msg.what == 1) {
                        activity.deleteTheItem();
                    }
                }
            }
        }

        public void deleteTheItem() {
            someTestData.remove(positionOfDeletedItem);
            adapter.notifyItemRemoved(positionOfDeletedItem);
        }
}





public class MyDeletionConfirmationDialog extends DialogFragment {
    private Message handlerMessage;

    public static MyDeletionConfirmationDialog newInstance(Handler callbackHandler) {
        MyDeletionConfirmationDialog myDialog = new MyDeletionConfirmationDialog();

        Bundle args = new Bundle();
        args.putParcelable("handlerMessage", callbackHandler.obtainMessage(1, true));
        myDialog.setArguments(args);

        return myDialog;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        handlerMessage = getArguments().getParcelable("handlerMessage");
    }

    @Override
    @NonNull
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());

        alertDialogBuilder.setMessage("Some message");
        alertDialogBuilder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                final Message toSend = Message.obtain(handlerMessage);
                toSend.sendToTarget();
            }
        });
        alertDialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        Dialog dialog = alertDialogBuilder.create();
        dialog.setCanceledOnTouchOutside(true);
        return dialog;
    }
}

如何让RecyclerView 正常工作?


编辑 1:

我还有其他RecyclerViews 可以正常工作。唯一的区别是那些在Fragments 里面而不是AppCompatActivity。我怀疑这与RecyclerViewonDetachedFromWindowonAttachedToWindow 事件有关。


编辑 2:

如果对话框已关闭(第 4 步)并再次打开,它将按预期工作。


编辑 3:

如果RecyclerView 被提取为Fragment,问题就会消失并按预期工作。上述用例与AppCompatActivity 而不是Fragment 一起正常工作是不可能的。

【问题讨论】:

  • 当您单击对话框时,它应该会消失并删除列表中的项目。那么,当您更改方向并删除数据时,对话框怎么会保留?
  • @ReazMurshed 用例如下:单击一个项目将其删除。它显示带有选项(“取消”和“删除”)的确认对话框。您无需单击任何选项。你旋转设备。对话框仍然打开。然后您选择“删除”选项来删除该项目。对话框关闭。该项目已从数据库中删除。 RecyclerView 没有相应更新,它仍然显示已删除的项目。
  • 这不是一个合适的解决方案,但无论如何,这个黑客可以做你想要的伎俩。您可以在onConfigurationChange 中轻松检测到方向变化,并且可以关闭屏幕上显示的对话。屏幕上显示的对话框与活动/片段生命周期无关,这就是它保留在屏幕上的原因。
  • @ReazMurshed 但我希望对话框保留。我不希望用户不得不再次重新打开对话框。此外,我还有其他 RecyclerViews 遵循相同的用例并且工作正常。这只是让我感到困惑。我会用一些我认为可能导致问题的假设来更新我的问题。
  • @OneEyeQuestion 这是您的实际代码吗? MyItemDeletionHandler 不应按书面形式编译。它是一个静态内部类,因此它不应访问MyAppCompatActivity 的实例成员。

标签: android android-recyclerview notifydatasetchanged orientation-changes


【解决方案1】:

我在使用 RecyclerView 时遇到了类似的问题。 当我向左滑动以删除一个项目然后旋转屏幕时,该项目已从我的数据集中删除,但屏幕并没有像我们在不旋转的情况下执行相同操作时那样正常刷新。似乎adaptar.notifyItemRemoved() 根本没有刷新屏幕。

我使用Nemanja Kovacevic 源代码作为起点,但我对其进行了一些更改(例如添加项目单击、使用对话框编辑、数据库支持等)。

所以我读了这个post,它给了我一个关于可能出了什么问题的提示。 似乎 adapter.notify 仍然指向旋转前的前一个适配器引用。每次我们旋转时,都会在 Activity:OnCreate 处创建一个新的适配器

public class MainActivity extends AppCompatActivity
    implements NavigationView.OnNavigationItemSelectedListener,
    AddAlertDialog.OnAlertSavedListener,
    AlertListAdapter.OnItemDeletedListener {

  static ListAdapter mListAdapter;
  RecyclerView mRecyclerView;
  ... 

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...
    mRecyclerView = (RecyclerView) findViewById(R.id.mainListView);
    mDB = new DatabaseTable(this);

    // Reading all alerts
    ArrayList<Alert> alerts = mDB.getAllAlerts();

    if (mListAdapter == null)
        mListAdapter = new ListAdapter(this, alerts);
  }
}

也许它并不理想(创建静态对象不是一个好主意),但它解决了问题。

希望对你也有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-21
    • 2013-06-04
    • 2017-10-09
    • 2020-09-24
    • 1970-01-01
    相关资源
    最近更新 更多