在Views
同步Fragments
之后,是否有任何优雅的解决方案可以在FragmentActivity's
ViewPager
中刷新Service
中的SyncAdapter
运行?
我尝试在我的适配器上调用notifyDataSetChanged()
和notifyDataSetInvalidated()
,以及在我的观看(refreshDrawableState()
)上调用GridViews
,但无济于事。也许我一直在错误的地方调用它们 - 我已经尝试在setUserVisibleHint
isVisible
= true时进行调用,希望每当片段进入视图时触发它,但它不会工作
我也一直在使用对SQLite数据库的ASync调用来满足我的数据需求,而不是Content Provider
,我认为这会让这更容易。 1}}我可以想到几种方法,但两者都不是很好。
有什么想法吗?如果愿意,我可以提供代码。感谢。
答案 0 :(得分:4)
我假设您只是为了解释而使用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的activity / fragment开始,你将会听到这样的广播:
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中显示,因为它非常受欢迎(但我真的相信你和每个开发者都在世界应该使用装载机模式。)
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或广播选项。
答案 1 :(得分:1)
在您拥有的片段及其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);
优点是您不需要关心何时显示片段,因为接收器在片段视图的整个生命周期中都存在。
答案 2 :(得分:0)
使用新数据从头开始重新创建适配器,并将其重新分配给ListView(或您拥有的任何视图)。