【问题标题】:Nearby Messages using an IntentService使用 IntentService 的附近消息
【发布时间】:2019-05-07 07:28:17
【问题描述】:

最初我设置了一个BroadcastReceiver 来接收来自Nearby Messages API 的意图。

class BeaconMessageReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        Nearby.getMessagesClient(context).handleIntent(intent, object : MessageListener() {
            override fun onFound(message: Message) {
                val id = IBeaconId.from(message)
                Timber.i("Found iBeacon=$id")
                sendNotification(context, "Found iBeacon=$id")
            }

            override fun onLost(message: Message) {
                val id = IBeaconId.from(message)
                Timber.i("Lost iBeacon=$id")
                sendNotification(context, "Lost iBeacon=$id")
            }
        })
    }

    private fun sendNotification(context: Context, text: String) {
        Timber.d("Send notification.")
        val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        val notification = NotificationCompat.Builder(context, Notifications.CHANNEL_GENERAL)
                .setContentTitle("Beacons")
                .setContentText(text)
                .setSmallIcon(R.drawable.ic_notification_white)
                .build()

        manager.notify(NotificationIdGenerator.nextID(), notification)
    }

}

然后在授予位置权限后在我的MainActivity 中注册此接收器。

class MainActivity : AppCompatActivity() {

    // ...

    private fun onLocationPermissionsGranted() {
        val filter = MessageFilter.Builder()
                .includeIBeaconIds(UUID.fromString("B9407F30-F5F8-466E-AFF9-25556B57FEED"), null, null)
                .build()

        val options = SubscribeOptions.Builder().setStrategy(Strategy.BLE_ONLY).setFilter(filter).build()

        Nearby.getMessagesClient(context).subscribe(getPendingIntent(), options)
    }

    private fun getPendingIntent(): PendingIntent = PendingIntent.getBroadcast(
            this, 0, Intent(context, BeaconMessageReceiver::class.java), PendingIntent.FLAG_UPDATE_CURRENT)

}

这在应用程序打开时运行良好,但在应用程序关闭时不起作用。所以我找到了this example,它演示了如何设置IntentService 以在应用程序处于后台时接收消息。

该示例确实使用了Nearby.Messages 类,该类已被弃用,取而代之的是MessagesClient。所以我用MessagesClient 实现替换了不推荐使用的代码。

class MainActivity : AppCompatActivity() {

    // ...

    private fun onLocationPermissionsGranted() {
        val filter = MessageFilter.Builder()
                .includeIBeaconIds(UUID.fromString("B9407F30-F5F8-466E-AFF9-25556B57FEED"), null, null)
                .build()

        val options = SubscribeOptions.Builder().setStrategy(Strategy.BLE_ONLY).setFilter(filter).build()

        Nearby.getMessagesClient(context).subscribe(getPendingIntent(), options)
            .addOnSuccessListener {
                Timber.i("Subscribed successfully.")
                startService(Intent(this, BeaconMessageIntentService::class.java))
            }.addOnFailureListener {
                Timber.e(exception, "Subscription failed.")
            }
    }

    private fun getPendingIntent(): PendingIntent = PendingIntent.getBroadcast(
            this, 0, Intent(context, BeaconMessageIntentService::class.java), PendingIntent.FLAG_UPDATE_CURRENT)

}

这是IntentService(和我的BroadcastReceiver几乎一模一样)。

class BeaconMessageIntentService : IntentService("BeaconMessageIntentService") {

    override fun onHandleIntent(intent: Intent?) {
        intent?.let {
            Nearby.getMessagesClient(this)
                    .handleIntent(it, object : MessageListener() {
                        override fun onFound(message: Message) {
                            val id = IBeaconId.from(message)
                            Timber.i("Found iBeacon=$id")
                            sendNotification("Found iBeacon=$id")
                        }

                        override fun onLost(message: Message) {
                            val id = IBeaconId.from(message)
                            Timber.i("Lost iBeacon=$id")
                            sendNotification("Lost iBeacon=$id")
                        }
                    })
        }
    }

    private fun sendNotification(text: String) {
        Timber.d("Send notification.")
        val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        val notification = NotificationCompat.Builder(this, Notifications.CHANNEL_GENERAL)
                .setContentTitle("Beacons")
                .setContentText(text)
                .setSmallIcon(R.drawable.ic_notification_white)
                .build()

        manager.notify(NotificationIdGenerator.nextID(), notification)
    }

}

onHandleIntent被调用,Intent不是null;但由于某种原因,onFound()onLost() 从未被调用过。为什么会这样?

【问题讨论】:

    标签: android beacon android-intentservice google-nearby android-ble


    【解决方案1】:

    这不是真正的解决方案,但我发现的是这个 (credit to this answer):
    我尝试了一些配置,包括BroadcastReceiver 和添加JobIntentService 以在后台运行代码,但每次我得到这个onExpired 回调,您可以将其设置为SubscribeOptions

    options.setCallback(new SubscribeCallback() {
        @Override
        public void onExpired() {
            super.onExpired();
            Toast.makeText(context.get(), "No longer Subscribing!", Toast.LENGTH_SHORT).show();
        }
    }
    

    当订阅发生在后台时,它被延迟了,但它仍然被调用。

    注意事项:
    1. 当我使用Strategy.BLE_ONLY 进行测试时,我没有收到onFound 回调。
    2.来自谷歌的documentation

    后台订阅比前台消耗更少的电量 订阅,但具有更高的延迟和更低的可靠性

    在测试时,我发现“可靠性较低”是一种轻描淡写的说法:onFound 很少被调用,我从未得到onLost

    【讨论】:

      【解决方案2】:

      我知道这是一个迟到的回复,但我遇到了同样的问题,通过调试发现这是与此错误相关的问题:“尝试从非活动上下文执行高功率操作”。这可以在调用 Nearby.getMessagesClient(this) 时通过传入活动上下文而不是 this 来解决。

      在我的例子中,我添加了一个扩展应用程序的类,它有助于返回这个上下文(下面是在 java 中,但应该很容易翻译成 kotlin)

      public class MyApplication extends Application {
          private Activity currentActivity = null;
      
          public Activity getCurrentActivity(){
              return currentActivity;
          }
          public void setCurrentActivity(Activity mCurrentActivity){
              this.currentActivity = mCurrentActivity;
          }
      }
      

      在我的基础活动中,所有活动都从该活动扩展而来,我通过在构造函数中调用 ((MyApplication) this.getApplicationContext()).setCurrentActivity(this); 来设置当前活动。

      然后我的服务可以使用正确的上下文调用 getMessagesClient,如下所示:

      final Activity context = ((MyApplication)getApplicationContext()).getCurrentActivity();
      Nearby.getMessagesClient(context).[...]
      

      不要忘记在 AndroidManifest 中注册您的 Application 类:

      <application
      android:name="com.example.xxx.MyApplication"`
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多