使用Firebase数据库恢复活动时如何正确恢复数据?

时间:2017-09-18 02:09:40

标签: android firebase firebase-realtime-database

我正在开发一个显示项目列表的应用程序,并允许用户添加更多项目并检查项目的详细信息。

假设我将数据库引用保留在活动中,添加ChildEventListener个侦听器onResume()并在onPause()上删除它们:

public void onResume() {
   super.onResume();
   mItemChildEventListener = mDatabaseReference.child('items').addChildEventListener(new ChildEventListener() {
       public void onChildAdded(DataSnapshot dataSnapshot, String s) {
           mAdapter.addItem(dataSnapshot.getValue(Item.class));
       }
       ...
   };
}

public void onPause() {
    super.onPause();
    if (mItemChildEventListener != null) {
        mDatabaseReference.removeEventListener(mItemChildEventListener);
    }
}

在这些ChildEventListener中,我将逐项添加到项目列表中,并在适配器中调用notifyItemInserted(itemArray.size() - 1)

public void addItem(Item item) {
    if (mItems == null) {
        mItems = new ArrayList<>();
    }
    mItems.add(item);
    notifyItemInserted(mItems.size() - 1);
}

另外,为了使应用程序保持平稳运行,我将项目列表保留在Reteiner Fragment中,保存此值onSaveInstanceState()并在onCreate()上恢复它们​​。

protected void onCreate(@Nullable Bundle savedInstanceState) {
    if (savedInstanceState != null) {
        mItems = getState(STATE_ITEMS);
    } else {
        mItems = new ArrayList<>();
    }

    mAdapter = new ItemAdapter(mItems);
}

public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    saveState(STATE_ITEMS, mItems);
}

public <T> T getState(String key) {
    //noinspection unchecked
    return (T) mRetainedFragment.map.get(key);
}

public void saveState(String key, Object value) {
    mRetainedFragment.map.put(key, value);
}

public static class RetainedFragment extends Fragment {
    HashMap<String, Object> map = new HashMap<>();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // retain this fragment
        setRetainInstance(true);
    }
}

但是,如果我再次取消注册并注册侦听器,例如,通过任何方向更改或离开并重新注册到活动,将按预期调用onResume(),并添加ChildEventListener再次,检索相同的数据,如果未与项目列表mItems中已包含的数据进行比较,则会复制该数据。

此外,如果我不保留项目列表mItems,并且每次调用onResume()时检索数据,列表将丢失其滚动位置并闪烁,因为它需要一些时间检索数据。

问题

如何在不再次检索项目的情况下保留检索项目列表,但是继续监听已检索项目的更改以及添加的新项目?有没有比将已检索的项目与新项目进行比较更好的解决方案,例如,通过密钥?

我已尝试查看文档和其他问题,但我找不到与此情况相关的任何信息。此外,我尝试在mDatabaseReference中保留对onSaveInstanceState()的引用,就像我对项目列表mItems所做的那样,但它也没有用。

2 个答案:

答案 0 :(得分:2)

  1. 只需在Loader中进行Firebase调用,并将数据保存在静态变量或列表或任何适合您的数据结构中。
  2. 在onCreate中初始化Loader。
  3. 在Loader中,重写onStartLoading()方法,并在onStart()中调用此方法。
  4. 在onStartLoading()内部,只需检查静态变量是否为null。如果为null,则为startLoading。否则不加载,并将以前的数据设置为数据源。
  5. 使用Loaders的优点是,在方向更改的情况下,它不会像AsyncTask那样进行网络调用。

答案 1 :(得分:2)

如果您在Firebase实时数据库SDK中enable persistence,则有助于防止对已经收到的数据进行不必要的提取。 SDK将在本地缓存获取数据,并且在可用时首先使用该数据:

FirebaseDatabase.getInstance().setPersistenceEnabled(true);

请务必read the documentation了解其工作原理。

另外请记住,在onStart和onStop期间启动和停止监听器是传统的。如果应用程序暂时失去焦点(例如,它弹出一个对话框,或者其他一些透明活动出现在顶部),这将避免更多的重新获取。