【问题标题】:Should I persist data objects in onSaveInstanceState我应该在 onSaveInstanceState 中保留数据对象吗
【发布时间】:2016-10-28 18:55:52
【问题描述】:

我在我的安卓应用程序中使用greenDAO 来显示RecyclerView 中的对象列表。我有一个 RecyclerView.Adapter 的子类,它接受一个作为 greenDAO 实体的对象列表。

我在onCreate做的是:

  1. 为我的列表创建一个传递null 的适配器实例。这只是为了让下面的RecyclerView 知道适配器。
  2. 使用布局和适配器初始化RecyclerView
  3. 调用一个使用 greenDAO 异步查询数据的方法,并在成功后使用实际的对象列表更新适配器,以便显示它们。

这是相关代码:

protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ...

    mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
    mListAdapter = new MyRecyclerAdapter(null);
    mList.setHasFixedSize(true);
    mList.setLayoutManager(mLayoutManager);
    mList.setAdapter(mListAdapter);
    refreshItems();
}

public void refreshItems()
{
    AsyncSession asyncSession = ((App)getApplication()).getDaoSession().startAsyncSession();
    asyncSession.setListenerMainThread(new AsyncOperationListener()
    {
        @Override
        public void onAsyncOperationCompleted(final AsyncOperation operation)
        {
            if (operation.isCompletedSucessfully())
                mListAdapter.setItems((List<Item>) operation.getResult());
        }
    });

    asyncSession.loadAll(Item.class);
}

这很好用。现在我注意到,当然,每次我旋转活动或从另一个活动返回到它时,都会调用通过 greenDAO 查询数据库的方法。这很清楚,因为我是从onCreate 调用该方法的。

我的问题是:最好的做法是像我这样做(每次都重新查询 DAO)还是让我的对象可打包并将我在onSaveInstanceState 中的列表保存在onRestore 中而不是重新查询 DAO?

【问题讨论】:

  • 可能两者都不是。使用某种内存缓存。我没用过greenDAO,但是如果没有内置的,就创建一个。实例状态用于识别信息(不是Intent 的一部分)和临时信息(例如,您不想提交到持久存储的部分完成的表单)。
  • @CommonsWare 好吧,他们的文档说的是查询和会话:A side effect of this is some kind of entity “caching”. If an entity object is still around in memory (greenDAO uses weak references here), the entity is not constructed again. Also, greenDAO performs no database query to update the entity values. Instead, the object is returned “immediately” from the session cache,所以似乎已经有了某种缓存。
  • “最佳实践”值得商榷,但我支持@CommonsWare 评论。 savedInstanceState 用于特定instancestate,它可能是一些表单数据或一些状态机。数据库结果不属于该状态,不应保存在那里。我也从未使用过 greenDao,但如果它不缓存,您可以使用 LruCache 或 WeakReference。 编辑:我看到了你的评论,所以如果 greenDao 已经缓存了,就让你的代码保持原样
  • 感谢您的两位 cmets。我想我会暂时保留它们,然后再检查大量数据(这不会发生在我的应用程序中),看看性能影响是什么。
  • btw 在第 3 步中,您正在加载所有项目(因此您需要异步),为什么不使用 listLazy

标签: android state greendao screen-rotation


【解决方案1】:

您所做的是完全有效的,您不需要将查询到的数据保存在onSaveInstanceState(),使用内存缓存或任何其他优化(即使 GreenDAO 没有内部缓存)。

事实上,您完全可以,因为您异步执行查询 - GreenDAO 的创建者声称在大多数情况下查询可以在 UI 线程上执行(我很难同意)。

我还建议您在onStart()而不是onCreate()中执行数据查询。我个人认为 onCreate() 应该仅用于您将在构造函数中执行的操作(例如字段初始化)。在onStart() 中执行此查询的另一个原因是,如果用户离开您的应用程序很长时间然后又回到它,数据可能会过时(例如,由于SyncAdapter 的后台同步)并且您会想要刷新它。

您可能要添加的最后一部分是“数据更改通知”。如果您查询和显示给用户的数据可以在没有用户交互的情况下更改(例如,由于SyncAdapter 的后台同步),您将希望此机制到位。这个概念很简单 - ActivityonCreate() 中注册有关数据更改的通知,如果收到通知,您执行重新查询以确保用户看到最新数据。

我不能说以上是“最佳实践”,但它们是行之有效的良好实践。

惰性列表:

正如@pskink 在他的评论中所建议的,您也可以使用LazyList。但请注意,它并不能排除对数据异步查询的需要。 LazyList 的使用允许您像往常一样执行查询,但以按需方式将结果加载到内存中。如果您希望查询产生大量数据,这可能很有用。

然而,在我看来,只有在观察到实际性能问题时才应该优化代码。因此,除非您提前知道特定查询会产生数千个结果,否则我说您不需要LazyList

【讨论】:

  • 谢谢。由于我的应用程序的性质,没有用户交互就不可能创建新条目。为了安全起见,我要补充的是某种事件总线(Otto?)。由于我是 greenDAO 的新手,我不确定是否可以发出数据更改通知。
  • @ThorstenDittmar 据我所知,GreenDAO 不支持数据更改通知。至于事件总线,我最喜欢的是 GreenRobot 的(发布 GreenDAO 的同一家公司)。但是,如果没有用户与同一设备的交互就无法更改数据,那么,也许,您甚至不需要数据更改通知……由您决定
  • @ThorstenDittmar,我还添加了一段关于LazyList(@pskink 在 cmets 中提到)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-27
  • 1970-01-01
  • 1970-01-01
  • 2021-10-20
相关资源
最近更新 更多