【问题标题】:RecyclerView Adapter not updating views after device rotationRecyclerView 适配器在设备旋转后不更新视图
【发布时间】:2020-01-14 11:38:09
【问题描述】:

我有一个聊天应用程序,它打开一个 Websocket 到服务器。该应用程序有 2 个模块 -

  1. chat sdk:处理连接加来回 消息传递。
  2. ui:处理适配器和视图

聊天 UI 位于 Activity 托管的片段上。

一切正常,但是当我决定对设备旋转使用持久性时,我遇到了问题。 当我旋转设备时,websocket 重新连接(这是正常的),活动被重新创建,片段也是如此。

在设备旋转和一些调试之后,我看到我的 messageList 正确填充了任何添加的项目(即消息文本),但不是 UI。当我从 EditText 键入文本并按发送时,该项目会正确显示在 UI 中,但是当我收到来自服务器的响应时,即使将消息添加到 messageList,UI 也不会更新。

我在类似的帖子中读到 RecyclerView 适配器在旋转后更新旧片段。是这样吗?如果是这种情况,为什么当我从 EditText 发送消息时它会正确显示,但从我的 WebSocket 的 onMessage 时却没有?

我试过"android:configChanges="screenSize|orientation|screenLayout" 没有任何结果。 我覆盖了 onConfigurationChanged 并强制适配器更新视图,但没有结果

@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {

    super.onConfigurationChanged(newConfig);

    if(messagesAdapter!=null){
        messagesAdapter.notifyDataSetChanged();
    }
}

我保存片段以在我的活动中恢复它

public class MessageActivity extends AppCompatActivity {
private MessageFragment fragment;

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_message);


    if (savedInstanceState == null) {
        fragment = MessageFragment.newInstance();

        getSupportFragmentManager().beginTransaction()
                .replace(R.id.container, fragment)
                .commitNow();
    }else{
        fragment = (MessageFragment) getSupportFragmentManager().getFragment(savedInstanceState, "messageFragment");
    }

}

@Override
public void onBackPressed() {

    finishAffinity();
}


@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    //Save the fragment's instance
    getSupportFragmentManager().putFragment(outState, "messageFragment", fragment);
}}

我还保存和检索我的消息列表

 @Override
public void onSaveInstanceState(@NonNull Bundle outState) {

    super.onSaveInstanceState(outState);
    //saving the state of the chat
    outState.putParcelableArrayList("messages", messageArrayList);
    try {
        Log.d(TAG, "messagelist in save instance " + messageArrayList.size());
    }catch (NullPointerException e){
        e.printStackTrace();
    }
    outState.putString("dialogId", messageArrayList.get(0).getDialogId());
}

来自 websocket 的 onMessage

@Override
public void onMessage(ArrayList<Message> data) {

    if (!messageArrayList.isEmpty() && messageArrayList.get(messageArrayList.size() - 1).getServerMessageType() == Constants.TYPE_TYPING_ON) {
        messageArrayList.remove(messageArrayList.size() - 1);
    }
    this.messageArrayList.addAll(data);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && isFragmentAttached) {

        mActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {

                if (omiliaClient != null) {
                    updateUi(messageArrayList, omiliaClient.user2);

                }
            }
        });
    }
}

【问题讨论】:

  • 既然您提到您的 UI 在屏幕旋转后更新/恢复。我需要了解从附加到 Api/websocket 的回调中接收新数据的代码 sn-p。您是否正确更新了数据集的同一实例,即messageArrayList
  • 添加了 sn-p 供您查看。但调试后我看到消息已正确添加到列表中
  • @sud007 你发给我的线程上选择的答案不是这样,但第二个答案是。但是下面的文基早点回答了。非常感谢。

标签: android android-recyclerview rotation fragment adapter


【解决方案1】:

onCreate()onCreateView()onActivityCreated() 方法中调用setRetainInstance(true)

【讨论】:

  • 当我旋转时,视图会按预期完美恢复。当我在轮换后开始接收消息时,问题就开始了。
  • 这是一个不好的行为。这可能是一种解决方法,但不建议这样做,因为您永远不会知道您的 RecyclerView 会不必要地刷新整个 adpater。 notifyDataSetChanged 是重量级操作,应谨慎对待具有大/未知数据集大小的适配器。由于这个简单的冰山式问题,个人修复了生产应用程序中的一个巨大问题。
  • @iliasPs 但是您存储片段实例的方式确实是错误的。
  • 请详细说明?
  • 同意@Venky 这不是你存储片段实例的方式。
猜你喜欢
  • 2017-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-24
  • 1970-01-01
  • 2018-11-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多