V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
doublemark
V2EX  ›  Android

Android 线程里发送广播必须等线程结束才能收到广播?

  •  
  •   doublemark · 2019-02-01 16:08:07 +08:00 · 11490 次点击
    这是一个创建于 2141 天前的主题,其中的信息可能已经有所发展或是发生改变。

    原谅我是一个硬件工程师,最近在做一个和硬件相关的测试软件,大部分功能都已实现,目前问题是: 在 C++里可以在线程里发送指令,然后 sleep 一段时间用以等待返回的数据,而 android 里想用同样的思路: 1、通讯封装在了一个 Service 里保持后台运行; 2、在按钮点击事件里按下按钮后新建 Thread,线程里发送广播到 Service,Service 里根据广播里的参数去执行相应的发送命令,并在 Service 里做接收解析,若解析正确则置一标志位。 3、2 里提到的线程在发送完广播后,sleep 一段时间等待该标志位,若标志位成立则继续往下执行,以此类推。 目前问题就在于: 2 里在 Thread 里发送广播,根据调试以及 log 看,并不是在 sendbraodcast 方法执行后再 receiver 里收到,而是该 Thread 执行完之后才会收到,这样是正常的吗?

    对于这种需要执行多个步骤的耗时和等待操作,在 Android 里有没有好的方案?

    感谢各位,很荣幸能来到这里。

    17 条回复    2019-02-02 15:21:38 +08:00
    momocraft
        1
    momocraft  
       2019-02-01 16:21:12 +08:00
    (在正确实现的时候)不是

    Java 有比较齐全的线程和同步 API,简单的比如 CountDownLatch / Future
    yippees
        2
    yippees  
       2019-02-01 17:30:09 +08:00
    1、activity 收发测试是 sendbraodcast 方法执行后 receiver 里收到,再等待结束。
    2、加个接收广播
    doublemark
        3
    doublemark  
    OP
       2019-02-01 17:42:43 +08:00
    @yippees 实际使用中确实是在 sendbroadcast 之后在 receiver 里能收到,但是一放到 thread 里
    {
    sendbroadcast(intent);
    try {
    sleep(100);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    dosomethingA();
    dosomethingB();
    dosomethingC();
    }
    在这里,sendbroadcast 方法执行后并没有收到,反而是 dosomethingC 之后才收到。奇怪啊。
    fuckshiter
        4
    fuckshiter  
       2019-02-01 17:45:57 +08:00 via iPhone
    发送广播后。接收到广播做一个回调,或者用 eventbus 第三方库
    tempdban
        5
    tempdban  
       2019-02-01 17:46:33 +08:00 via Android
    我跟你说其实安卓的 activity 和 service 默认是跑在一个线程里的
    想这么干你要给 service 新建个线程
    这就是已经熟悉 Unix 变成的人必定踩坑点。
    yukiww233
        6
    yukiww233  
       2019-02-01 17:50:19 +08:00
    上 eventbus
    fuckshiter
        7
    fuckshiter  
       2019-02-01 17:58:52 +08:00 via iPhone
    class FooBroadcastReceiver(var callback: () -> Unit) : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
    when (intent?.action) {
    "XXXXACTION" -> {
    callback();
    }
    }
    }
    }

    var fooBroadcastReceiver: FooBroadcastReceiver? = null
    fun sendCommand(callback: () -> Unit) {
    fooBroadcastReceiver = fooBroadcastReceiver ?: FooBroadcastReceiver(callback)
    fooBroadcastReceiver?.callback = callback
    mContext.sendBroadcast(Intent("XXXXACTION"))
    }
    fuckshiter
        8
    fuckshiter  
       2019-02-01 18:01:24 +08:00 via iPhone
    @fuckshiter
    使用
    fun send() {
    sendCommand {
    doSomething1();
    doSomething2();
    doSomething3();
    }
    }
    yippees
        9
    yippees  
       2019-02-01 19:40:51 +08:00
    @doublemark
    我的代码也是 new thread 的
    只是接收也在 activity 就是。

    先打发日志,再打收日志,最后 sleep 结束日志
    richard1122
        10
    richard1122  
       2019-02-01 22:53:09 +08:00
    首先确认一下是真的开了新线程,是 thread.start() 而不是 thread.run() 了,后者会在当前线程直接执行这段代码。
    pagxir
        11
    pagxir  
       2019-02-01 23:17:31 +08:00
    你还是找个搞软件的来弄吧。你这是根本没有理解线程的概念。线程都 sleep 了,自然是不可能在去接收广播。
    receiver 的线程是运行在 handler 所在的线程。
    zpxshl
        12
    zpxshl  
       2019-02-02 09:38:35 +08:00 via Android
    不应该出现这种结果。我猜 10 楼说得对,你写成 new thread.run 。(应该调用 start 方法)
    至于楼上一堆说不能 sleep 的人是认真的吗。。。。
    SuperNovaSonic
        13
    SuperNovaSonic  
       2019-02-02 11:21:35 +08:00
    同意楼上,11 楼上来就乱说,楼主说的是 sleep 又不是让主线程 sleep
    SuperNovaSonic
        14
    SuperNovaSonic  
       2019-02-02 11:22:27 +08:00
    另外自己亲测了下,没有问题
    2019-02-02 11:19:11.790 14951-15076/com.example.glidetest D/BroadcastReceive Test: new thread sendBroadcast
    2019-02-02 11:19:11.791 14951-15076/com.example.glidetest D/BroadcastReceive Test: new thread try to sleep
    2019-02-02 11:19:11.805 14951-14951/com.example.glidetest D/ BroadcastReceive Test: BroadcastReceiver onReceive
    2019-02-02 11:19:14.793 14951-15076/com.example.glidetest D/BroadcastReceive Test: new thread after sleep
    siyehua
        15
    siyehua  
       2019-02-02 13:48:49 +08:00
    发送广播不要建立线程。广播本身具有跨进程、线程的能力。直接根据需求发送与接收广播即可。使用到线程就必须用到线程消息同步的技术。
    RikkaW
        16
    RikkaW  
       2019-02-02 14:20:44 +08:00
    sendBroadcast 实际是“自己的应用进程到 system_server 进程,再到目标进程”这样一个比较重的过程(因为本来就是设计用来跨进程广播的),用在这里就过于夸张了。(所以可能是 sleep 时间太短了正好就看起来更晚收到?)另外发广播并不需要建立线程,因为只有把 intent 发给 system_server 的过程。
    这里的情况看起来只要用 LocalbroadcastManager EventBus 这样的或是绑定服务( https://developer.android.com/guide/components/bound-services )就够了。
    ksssdh123
        17
    ksssdh123  
       2019-02-02 15:21:38 +08:00
    广播是一个很神奇的组件,跨线程,还跨进程
    如需求是需要跨进程,那就用起来吧
    如果用了 Rxjava,那么 Rxbus 用起来(也可以跨线程),如果没用 Rxjava 就 EventBus 应该满足你的需求了吧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   878 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 20:38 · PVG 04:38 · LAX 12:38 · JFK 15:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.