如何从后台服务 post 消息到 UI 片段?
How to post a message from a background service to a UI fragment?
我对来自 Greenrobot 的 EventBus
有疑问。
我正在尝试 post 来自我的同步适配器的后台服务事件,并将其捕捉到片段中以更新 UI。
问题是,当我尝试 post 来自同步适配器的事件时,我在调试日志中得到以下信息:
No subscribers registered for event class olexiimuraviov.ua.simplerssreader.event.UpdateUIEvent
No subscribers registered for event class org.greenrobot.eventbus.NoSubscriberEvent
我在 onResume
中注册片段并在 onPause
中取消注册
@Override
public void onResume() {
super.onResume();
EventBus.getDefault().register(this);
if (mDebug) Log.d(LOG_TAG, EventBus.getDefault().isRegistered(this) + "");
}
@Override
public void onPause() {
super.onPause();
EventBus.getDefault().unregister(this);
}
onResume 中的日志语句显示片段已成功注册。
这是 onEvent 方法:
@Subscribe
public void onEvent(UpdateUIEvent event) {
if (mSwipeRefreshLayout.isRefreshing())
mSwipeRefreshLayout.setRefreshing(false);
}
我试图用背景线程模式调用 onEvent 方法,但它没有帮助。
在此之后,我尝试使用处理程序来处理 post 事件,但事件总线仍然找不到任何已注册的事件订阅者。
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
EventBus.getDefault().post(new UpdateUIEvent());
}
});
这是我的同步适配器的 onPerform 方法:
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
// Fetch data from server
} finally {
// close everything
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Log.d(LOG_TAG, "Update event");
EventBus.getDefault().post(new UpdateUIEvent());
}
});
}
}
如何使用 Greenrobot 的 EventBus
将事件从同步适配器发送到片段?
tl;dr
您永远不必担心您 post 来自哪个 线程 事件,但您确实需要担心哪个 进程 你post它来自。您的同步适配器 运行 在与您的片段不同的进程中 - EventBus 仅在创建它的进程中工作。
长版
除了您订阅事件的地方之外,您永远不需要启动不同的线程,甚至不必担心您在哪个线程上。
查看 http://greenrobot.org/eventbus/documentation/delivery-threads-threadmode/ 了解更多详细信息,但语法非常容易解释:
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void thisMethodWillBeRunInABackgroundThread(DoLoginEvent event)
{
//Run some code that makes an HTTP request
}
然后 运行 UI 上的内容:
@Subscribe(threadMode = ThreadMode.MAIN)
public void thisMethodWillBeRunOnTheUIThread(LoginSuccessfulEvent event)
{
//Run some code that touches the UI
}
当您调用 post() 来触发 DoLoginEvent
和 LoginSuccessfulEvent
时,您在哪个线程中完全没有关系。
现在解决您遇到的真正问题:似乎没有在订阅对象上捕获事件。
我怀疑这是因为您的同步适配器 运行 在不同的 进程 中。 EventBus 仅在其创建的 Process 中运行。
同步适配器,如 BroadcastReceiver 或服务 运行s 在一个单独的进程中,允许您与服务器同步数据 而无需 与您的应用程序进行任何交互本身。这个想法是,即使应用程序关闭,您也可以与服务器同步,将任何内容保存到数据库中,然后当应用程序启动时,它会检查该数据库(快速),而不必与服务器同步(慢速)。但是,如果您的应用在同步适配器 运行 时处于活动状态,那么您想要保存到数据库的同时还要告诉应用有一些新信息对吗?
因此,为了让您的同步适配器能够与您的应用程序进行通信,我建议您在 fragment/activity 中设置一个 BroadcastReceiver,然后从您的同步适配器广播一个 Intent。
这个机制和EventBus的概念很相似,你甚至可以发送sticky intents!您的片段会监听这些意图,但仅限于它处于活动状态时。如果您的同步适配器在您的应用程序关闭时发送广播,则什么也不会发生。但是当片段启动并注册这些意图时,它将获得最后一个 sticky。
public class LogFragment extends Fragment {
private LogReceiver mReceiver;
public class LogReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//you can call the EventBus from in here
}
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReceiver = new LogReceiver();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getActivity().registerReceiver(mReceiver, new IntentFilter("com.whatever.whatever"));
return view;
}
@Override
public void onDestroyView() {
getActivity().unregisterReceiver(mReceiver);
super.onDestroy();
}
}
然后从您的同步适配器
Intent sendIntent = new Intent("com.whatever.whatever");
sendIntent.putExtra("SYNC_ADAPTER_EXTRA", "Your sync adapter says hi");
context.sendBroadcast(sendIntent);
我对来自 Greenrobot 的 EventBus
有疑问。
我正在尝试 post 来自我的同步适配器的后台服务事件,并将其捕捉到片段中以更新 UI。
问题是,当我尝试 post 来自同步适配器的事件时,我在调试日志中得到以下信息:
No subscribers registered for event class olexiimuraviov.ua.simplerssreader.event.UpdateUIEvent No subscribers registered for event class org.greenrobot.eventbus.NoSubscriberEvent
我在 onResume
中注册片段并在 onPause
@Override
public void onResume() {
super.onResume();
EventBus.getDefault().register(this);
if (mDebug) Log.d(LOG_TAG, EventBus.getDefault().isRegistered(this) + "");
}
@Override
public void onPause() {
super.onPause();
EventBus.getDefault().unregister(this);
}
onResume 中的日志语句显示片段已成功注册。
这是 onEvent 方法:
@Subscribe
public void onEvent(UpdateUIEvent event) {
if (mSwipeRefreshLayout.isRefreshing())
mSwipeRefreshLayout.setRefreshing(false);
}
我试图用背景线程模式调用 onEvent 方法,但它没有帮助。
在此之后,我尝试使用处理程序来处理 post 事件,但事件总线仍然找不到任何已注册的事件订阅者。
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
EventBus.getDefault().post(new UpdateUIEvent());
}
});
这是我的同步适配器的 onPerform 方法:
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
// Fetch data from server
} finally {
// close everything
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Log.d(LOG_TAG, "Update event");
EventBus.getDefault().post(new UpdateUIEvent());
}
});
}
}
如何使用 Greenrobot 的 EventBus
将事件从同步适配器发送到片段?
tl;dr
您永远不必担心您 post 来自哪个 线程 事件,但您确实需要担心哪个 进程 你post它来自。您的同步适配器 运行 在与您的片段不同的进程中 - EventBus 仅在创建它的进程中工作。
长版
除了您订阅事件的地方之外,您永远不需要启动不同的线程,甚至不必担心您在哪个线程上。
查看 http://greenrobot.org/eventbus/documentation/delivery-threads-threadmode/ 了解更多详细信息,但语法非常容易解释:
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void thisMethodWillBeRunInABackgroundThread(DoLoginEvent event)
{
//Run some code that makes an HTTP request
}
然后 运行 UI 上的内容:
@Subscribe(threadMode = ThreadMode.MAIN)
public void thisMethodWillBeRunOnTheUIThread(LoginSuccessfulEvent event)
{
//Run some code that touches the UI
}
当您调用 post() 来触发 DoLoginEvent
和 LoginSuccessfulEvent
时,您在哪个线程中完全没有关系。
现在解决您遇到的真正问题:似乎没有在订阅对象上捕获事件。
我怀疑这是因为您的同步适配器 运行 在不同的 进程 中。 EventBus 仅在其创建的 Process 中运行。
同步适配器,如 BroadcastReceiver 或服务 运行s 在一个单独的进程中,允许您与服务器同步数据 而无需 与您的应用程序进行任何交互本身。这个想法是,即使应用程序关闭,您也可以与服务器同步,将任何内容保存到数据库中,然后当应用程序启动时,它会检查该数据库(快速),而不必与服务器同步(慢速)。但是,如果您的应用在同步适配器 运行 时处于活动状态,那么您想要保存到数据库的同时还要告诉应用有一些新信息对吗?
因此,为了让您的同步适配器能够与您的应用程序进行通信,我建议您在 fragment/activity 中设置一个 BroadcastReceiver,然后从您的同步适配器广播一个 Intent。
这个机制和EventBus的概念很相似,你甚至可以发送sticky intents!您的片段会监听这些意图,但仅限于它处于活动状态时。如果您的同步适配器在您的应用程序关闭时发送广播,则什么也不会发生。但是当片段启动并注册这些意图时,它将获得最后一个 sticky。
public class LogFragment extends Fragment {
private LogReceiver mReceiver;
public class LogReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//you can call the EventBus from in here
}
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mReceiver = new LogReceiver();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
getActivity().registerReceiver(mReceiver, new IntentFilter("com.whatever.whatever"));
return view;
}
@Override
public void onDestroyView() {
getActivity().unregisterReceiver(mReceiver);
super.onDestroy();
}
}
然后从您的同步适配器
Intent sendIntent = new Intent("com.whatever.whatever");
sendIntent.putExtra("SYNC_ADAPTER_EXTRA", "Your sync adapter says hi");
context.sendBroadcast(sendIntent);