Android 集成 mqtt 开启关闭网络 应用崩溃
一.开发环境
Android studio kotlin
前提是你需要有一个MQTT代理服务器可以连接,这里我也写了一篇说明的文档,以供参考,链接如下:
https://blog.csdn.net/wwanglin_0/article/details/110529367
官方demo
eclipse/paho.mqtt.android: MQTT Android (github.com)
git clone https://github.com/eclipse/paho.mqtt.android.git
注:git clone 后切换到develop版本 ,master版本在最新 Android studio中不能运行
我做的demo 请参考另一篇博文 https://blog.csdn.net/wwanglin_0/article/details/110549899
以下是我的app版本,目的是让你看到我的版本有多高,不是让你改成我的一样
compileSdkVersion 30
buildToolsVersion "30.0.2"
minSdkVersion 21
targetSdkVersion 30
二.集成步骤
1.依赖
//MQTT
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
//解决Android开发中LocalBroadcastManager类无法使用的问题
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
2.权限
//MQTT
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
3.服务
<!--MqttService-->
<service android:name="org.eclipse.paho.android.service.MqttService" />
4.将mqtt集成在MyApplication中
使用代码写在MyApplication能保证程序一直活着,随时能接收订阅的消息,另外程序中设置了断开重连机制
class MyApplication : Application() {
/*全局单例 */
companion object {
private const val TAG = "MyApplication"
//全局上下文
lateinit var context: Context
// 单例不会是null 所以使用notNull委托
var instance: MyApplication by Delegates.notNull()
//MQTT
const val SUBSCRIPTION_TOPIC = "SubscriptionTopic"
const val PUBLISH_TOPIC = "PublishTopic"
const val baseURL: String="192.168.1.141"
const val MQTT_SERVER_USERNAME = "admin"
const val MQTT_SERVER_PASSWORD = "admin"
lateinit var mqttAndroidClient: MqttAndroidClient
lateinit var mqttUrl: String
var clientId = "roomAndroidClient"
}
override fun onCreate() {
super.onCreate()
instance = this
/*全局上下文*/
context = applicationContext
initMQTT()
}
private fun initMQTT() {
mqttUrl = "tcp://192.168.0.141:1883"
//创建mqtt连接
clientId += System.currentTimeMillis()
mqttAndroidClient = MqttAndroidClient(applicationContext, mqttUrl, clientId)
//设置mqtt连接状态回调
mqttAndroidClient.setCallback(object : MqttCallbackExtended {
override fun connectComplete(reconnect: Boolean, serverURI: String) {
if (reconnect) {
Log.d("mqtt", "Reconnected to : $serverURI")
// Because Clean Session is true, we need to re-subscribe
subscribeToTopic()
} else {
Log.d("mqtt", ("Connected to: $serverURI"))
}
}
override fun connectionLost(cause: Throwable) {
Log.d("mqtt", "The Connection was lost.")
}
@Throws(java.lang.Exception::class)
override fun messageArrived(topic: String, message: MqttMessage) {
Log.d("mqtt", "Incoming message: " + String(message.payload))
}
override fun deliveryComplete(token: IMqttDeliveryToken) {}
} )
//设置mqtt连接选项(自动重连)
val mqttConnectOptions = MqttConnectOptions()
mqttConnectOptions.isAutomaticReconnect = true
mqttConnectOptions.isCleanSession = false
mqttConnectOptions.userName = MQTT_SERVER_USERNAME
mqttConnectOptions.password = MQTT_SERVER_PASSWORD.toCharArray()
//连接mqtt
Log.d("mqtt", "Connecting to $mqttUrl");
mqttAndroidClient.connect(mqttConnectOptions, null, object : IMqttActionListener {
override fun onSuccess(asyncActionToken: IMqttToken) {
//断开连接的缓冲选项
val disconnectedBufferOptions = DisconnectedBufferOptions()
disconnectedBufferOptions.isBufferEnabled = true
disconnectedBufferOptions.bufferSize = 100
disconnectedBufferOptions.isPersistBuffer = false
disconnectedBufferOptions.isDeleteOldestMessages = false
mqttAndroidClient.setBufferOpts(disconnectedBufferOptions)
//订阅主题
subscribeToTopic()
}
override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) {
Log.d("mqtt", "Failed to connect to: $mqttUrl")
}
})
}
//订阅
fun subscribeToTopic() {
//订阅动作回调
mqttAndroidClient.subscribe(SUBSCRIPTION_TOPIC, 0, null, object : IMqttActionListener {
override fun onSuccess(asyncActionToken: IMqttToken) {
Log.d("mqtt", "Subscribed!")
}
override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) {
Log.d("mqtt", "Failed to subscribe")
}
})
}
//发布
fun publishMessage(publishMessage: String) {
val message = MqttMessage()
message.payload = publishMessage.toByteArray()
mqttAndroidClient.publish(PUBLISH_TOPIC, message)
Log.d("mqtt", "Message Published")
if (!mqttAndroidClient.isConnected) {
Log.d(
"mqtt",
mqttAndroidClient.bufferedMessageCount.toString() + " messages in buffer."
)
}
}
}
5.别忘记将MyApplication添加到清单文件中
<application
android:name=".MyApplication"
...>
...
</application>
三.运行,报错,解决办法
1.报错情景描述:关闭网络,app启动,启动网络,崩溃,崩溃信息如下
2020-12-03 11:04:58.554 13943-13943/com.rfzn.dirt_room E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.rfzn.dirt_room, PID: 13943
java.lang.RuntimeException: Error receiving broadcast Intent { act=android.net.conn.CONNECTIVITY_CHANGE flg=0x4000010 (has extras) } in org.eclipse.paho.android.service.MqttService$NetworkConnectionIntentReceiver@fd171f4
at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:1132)
at android.os.Handler.handleCallback(Handler.java:755)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6141)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void java.util.Timer.cancel()' on a null object reference
at org.eclipse.paho.client.mqttv3.MqttAsyncClient.stopReconnectCycle(MqttAsyncClient.java:1120)
at org.eclipse.paho.client.mqttv3.MqttAsyncClient.reconnect(MqttAsyncClient.java:1057)
at org.eclipse.paho.android.service.MqttConnection.reconnect(MqttConnection.java:1049)
at org.eclipse.paho.android.service.MqttService.reconnect(MqttService.java:342)
at org.eclipse.paho.android.service.MqttService$NetworkConnectionIntentReceiver.onReceive(MqttService.java:827)
at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:1122)
at android.os.Handler.handleCallback(Handler.java:755)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6141)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802)
2.解决报错
将mqttv3版本升级成1.2.0, clean Project
//MQTT
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.0'
implementation 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.1'
//解决Android开发中LocalBroadcastManager类无法使用的问题
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'