如何将消息从后台服务发布到UI片段?

Ole*_*iov 4 android event-bus android-syncadapter android-fragments greenrobot-eventbus

我和EventBusGreenrobot 有问题.

我试图从我的同步适配器的后台服务发布事件,并在片段中捕获它以更新UI.

问题是当我尝试从同步适配器发布事件时,我在调试日志中得到以下内容:

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);
}
Run Code Online (Sandbox Code Playgroud)

onResume中的日志语句显示片段已成功注册.

这是onEvent方法:

@Subscribe
public void onEvent(UpdateUIEvent event) {
    if (mSwipeRefreshLayout.isRefreshing())
        mSwipeRefreshLayout.setRefreshing(false);
}
Run Code Online (Sandbox Code Playgroud)

我试图用Background threadmode调用onEvent方法,但它没有帮助.

在此之后,我试图使用处理程序发布事件,但eventbus仍然找不到任何注册订阅者的事件.

 new Handler(Looper.getMainLooper()).post(new Runnable() {
     @Override
     public void run() {
         EventBus.getDefault().post(new UpdateUIEvent());
     }
 });
Run Code Online (Sandbox Code Playgroud)

这是我的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());
           }
       });
    }
}
Run Code Online (Sandbox Code Playgroud)

如何使用Greenrobot将事件从同步适配器发送到片段EventBus

shr*_*der 7

TL;博士

你永远不用担心哪个线程你从后一个事件,但你不必担心它处理你张贴.您的同步适配器在与您的片段不同的进程中运行 - 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
}
Run Code Online (Sandbox Code Playgroud)

并在UI上运行一些东西:

@Subscribe(threadMode = ThreadMode.MAIN)
public void thisMethodWillBeRunOnTheUIThread(LoginSuccessfulEvent event)
{
    //Run some code that touches the UI
}
Run Code Online (Sandbox Code Playgroud)

当你调用后()火同时关闭DoLoginEventLoginSuccessfulEvent它绝对不会不管你是在哪一个线程.

现在你遇到了真正的问题:似乎没有在订阅对象上捕获事件.

我怀疑这是因为您的同步适配器在不同的进程中运行.EventBus仅在创建过程中运行.

同步适配器(如BroadcastReceiver或Service)在单独的进程中运行,以允许您与服务器同步数据,而无需与应用程序本身进行任何交互.我的想法是,即使应用程序关闭,您也可以与服务器同步,将数据保存到数据库,然后当应用程序启动时,它会检查该数据库(快速)而不必与服务器同步(慢速).但是,如果同步适配器运行时您的应用程序处于活动状态,那么您希望保存到数据库,还要告诉应用程序有一些新信息吗?

因此,为了让您的同步适配器与您的应用程序通信,我建议您在片段/活动中设置BroadcastReceiver,然后从同步适配器广播意图.

这个机制与EventBus的概念非常相似,你甚至可以发送粘性意图!你的片段会监听这些意图,但只有在它活着的时候.如果您的同步适配器在您的应用程序关闭时发送广播,则没有任何反应.但是当片段启动并注册这些意图时,它将获得最后一个粘性.

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后从同步适配器

Intent sendIntent = new Intent("com.whatever.whatever");
sendIntent.putExtra("SYNC_ADAPTER_EXTRA", "Your sync adapter says hi");
context.sendBroadcast(sendIntent);
Run Code Online (Sandbox Code Playgroud)