在同步服务运行后刷新FragmentActivity中的碎片



SyncAdapter的同步Service运行后,有人有任何优雅的解决方案来刷新FragmentActivity's ViewPagerFragments中的Views吗?

我试着在适配器上调用notifyDataSetChanged()notifyDataSetInvalidated(),在视图(GridViews)上调用refreshDrawableState(),但都没有用。也许我从错误的地方调用了它们——我试着在setUserVisibleHint上调用,其中isVisible=true,希望在片段出现时触发它,但它不起作用。

我也一直在使用对SQLite数据库的ASync调用来满足我的数据需求,而不是Content Provider,我认为这会让这件事变得更容易。我可以想出几种不用Content Provider的方法,但都不太好。

有什么想法吗?如果愿意,我可以提供代码。谢谢

为了解释起见,我假设您使用AsyncTask加载光标,但如果您使用Loader、ThreadPool或其他什么,它也会起作用。

从服务中,一旦新数据发生更改,我就会发送一个LocalBroadcast。活动可能存在,也可能不存在,所以广播是让它知道有新数据的好方法。因此,从你要做的服务:

    // that's an example, let's say your SyncAdapter updated the album with this ID
    // but you could create a simply "mybroadcast", up to you.
    Intent i = new Intent("albumId_" + albumId);
    LocalBroadcastManager.getInstance(this).sendBroadcast(i);

然后从具有Cursor的活动/片段中,您将听到这样的广播:

    public void onResume(){
        // the filter matches the broadcast
        IntentFilter filter = new IntentFilter("albumId_" + albumId); 
        LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver, filter);
    }
    public void onPause(){
        LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver);
    }
    // and of course you have to create a BroadcastReceiver
    private BroadcastReceiver myReceiver = new BroadcastReceiver(){
       @Override
       public void onReceive(Context context, Intent intent){
           // here you know that your data have changed, so it's time to reload it
           reloadData = new ReloadData().execute(); // you should cancel this task onPause()
       }
    };

正如我所说,下一部分取决于您用来加载Cursor的线程方法,对于这个例子,我将在AsyncTask中展示,因为它非常流行(但我真的相信您和世界上的每个开发人员都应该使用Loaders模式)。

private class ReloadData extends AsyncTask<Void, Void, Cursor> {
 protected Cursor doInBackground(Void... void) {
     // here you query your data base and return the new cursor
     ... query ...
     return cursor;
 }
 protected void onPostExecute(Cursor result) {
     // you said you're using a subclass of CursorAdater
     // so you have the method changeCursor, that changes the cursor and closes the old one
     myAdapter.changeCursor(result);
 }

}

我以前测试和使用过上述方法,我知道它是有效的。有一种方法可以使用标志FLAG_REGISTER_CONTENT_OBSERVER并覆盖onContentChanged()来重新执行查询并交换光标,但我从未测试过它

使用构造函数CursorAdapter(Context context, Cursor c, int flags)初始化适配器,传递标志FLAG_REGISTER_CONTENT_OBSERVER并覆盖onContentChanged()。在onContentChanged中,您将像上面一样执行AsyncTask。这样,您就不必使用LocalBroadcastManager,因为数据库会发出警报。这个方法不是我的主要答案,因为我从来没有测试过它

请注意,autoRequery已被弃用,并且由于它在UI线程中执行数据加载,因此不推荐使用它。

编辑:

我刚刚注意到内容观察者是一个API 11的东西。您有两种选择:1使用支持库:https://developer.android.com/reference/android/support/v4/widget/CursorAdapter.html或广播选项。

在您拥有的片段中注册一个BroadcastReceiver,并在其onReceive调用refresh中注册-该方法应该根据您拥有的内容更新UI。为了使代码易于使用,可以有一个基本的Fragment类,并在那里进行注册/注销,同时还有一个将由子片段实现的抽象refresh方法。类似于:

public abstract class BaseRefreshableFragment extends Fragment {
    private BroadcastReceiver refreshReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if ("package_name.REFRESH_ACTION".equals(intent)) {
                refresh();
            }
        }
    };
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        IntentFilter filter = new IntentFilter("package_name.REFRESH_ACTION");
        LocalBroadcastManager.getInstance(getActivity()).registerReceiver(refreshReceiver, filter);
    }
    @Override
    public void onDestroyView() {
        LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(refreshReceiver);
        super.onDestroyView();
    }
    protected abstract void refresh();
}

在你的Service中,当你的工作完成时,广播一个带有上述动作的意图。因此,如果有片段显示更新的数据,它们的接收器将被通知,并在每个片段上调用refresh。类似于您的服务:

Intent intent = new Intent("package_name.REFRESH_ACTION");
LocalBroadcastManager.getInstance(MySyncService.this).sendBroadcast(intent);

优点是,您不需要关心片段何时显示或不显示,因为接收器在片段视图的整个生命周期内都在那里。

使用新数据从头开始重新创建适配器,并将其重新分配给ListView(或您拥有的任何视图)。

相关内容

  • 没有找到相关文章

最新更新