Android手把手编写儿童手机远程监控App之UUID
概述
上节完成嘟宝MQTT消息的推送、订阅,以及医嘱消息的实现。至此嘟宝完成基本功能,包括:
- 响应Andorid开机消息,实现自启动
- 启动前台服务。在前台服务启动MQTT连接
- MQTT实现医嘱消息、订阅消息、推送消息功能。
嘟宝作为后台程序,没有登录、注册功能。后台服务器仅有EMQX、Coturn服务程序,无任何后台开发。如何在众多嘟宝中区别是每一个。
UUID,个人识别码。通用唯一标识符,Universally Unique Identifier。唯一标识信息由128位数字组成,32个十六进制字符组成的字符串(带连字符分隔)。它的设计目标是在无需集中管理的情况下,生成在全球范围内几乎不会重复的ID,如:3f29c9b2-9c2a-4c1f-8c7d-6e2b7a1f9a0d
。
嘟宝在建立MQTT连接之前,需要指明clientID。将clientID用uuid作为嘟宝id,就不会出现重复的嘟宝连接。如下之前用0001做测试
String url="tcp://192.168.1.20:1883";String dubaoID="0001";client=newMqttClient(url,"dubao_server"+dubaoID,newMemoryPersistence());andorid 生成uuid
- 新建一个uuid类
- uuid类中添加createUUID创建一个uuid
- 在MainActivity创建一个按钮生成uuid
类uuid源码
package com.zilong.dubao;import java.util.UUID;public classuuid{public StringcreateUUID(){String s="";s=UUID.randomUUID().toString();returns;}}MainActivity源码
package com.zilong.dubao;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.widget.Button;import android.widget.Toast;public classMainActivityextendsAppCompatActivity{@Override protected voidonCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button startbtn=findViewById(R.id.sendbtn);startbtn.setOnClickListener(v->{uuid u=newuuid();String s=u.createUUID();Toast.makeText(this,s,Toast.LENGTH_SHORT).show();});}}运行查看效果
每次生成的uuid,都是唯一值
uuid存储
uuid在嘟宝app首次启动后生成,先于MQTT连接之前。启动后检查嘟宝有没有被存储在本地。
- 若有从本地读取,返回本地uuid
- 若没有创建新uuid,存储本地
Andorid数据存储,有很多种方式,轻量级的使用SharedPreferences,对于复杂数据可以使用SQLite 数据库等 - SharedPreferences:以 键值对 (Key-Value) 形式存储轻量级的简单数据,常用于保存应用设置
- 文件存储, Android 的 openFileInput() / openFileOutput() 方法,将数据以字节流的形式写入设备的文件系统。
- SQLite 数据库:Android 内置的轻量级关系型数据库,适合存储结构化、复杂且相互关联的数据
- Content Provider:虽然常被称为四大组件之一,但它也提供了一种跨应用数据共享的存储接口
使用SharedPreferences存储uuid。
uuid类源码
package com.zilong.dubao;import static android.content.Context.MODE_PRIVATE;import android.content.Context;import android.content.SharedPreferences;import java.util.UUID;public classuuid{private StringcreateUUID(){String s="";s=UUID.randomUUID().toString();returns;}public Stringgetuuid(Context context){SharedPreferences preferences=context.getSharedPreferences("uuid",MODE_PRIVATE);String uuid=preferences.getString("id","");if(uuid.equals("")){uuid=createUUID();SharedPreferences.Editor editor=context.getSharedPreferences("uuid",MODE_PRIVATE).edit();editor.putString("id",uuid);editor.apply();returnuuid;}returnuuid;}}运行效果
生成的uuid实现mqtt连接
uuid用于mqtt连接,完成嘟宝唯一身份标识。
- 在前台服务中获取uuid
- 初始化mqtt连接时,修改connect参数,传入uuid值
前台服务代码
package com.zilong.dubao;import android.app.Notification;import android.app.NotificationChannel;import android.app.NotificationManager;import android.app.PendingIntent;import android.app.Service;import android.content.Intent;import android.os.Build;import android.os.IBinder;import android.widget.Toast;import androidx.core.app.NotificationCompat;public classMyServiceextendsService{MyMqttClient myMqttClient;publicMyService(){}@Override public voidonCreate(){super.onCreate();createNotificationChannel();uuid u=newuuid();String uuid=u.getuuid(this);myMqttClient=newMyMqttClient();myMqttClient.connect(uuid);}@Override public intonStartCommand(Intent intent,int flags,int startId){returnsuper.onStartCommand(intent,flags,startId);}@Override public voidonDestroy(){myMqttClient.colse();super.onDestroy();}@Override public IBinderonBind(Intent intent){// TODO: Return the communication channel to the service.thrownewUnsupportedOperationException("Not yet implemented");}private voidcreateNotificationChannel(){NotificationChannel channel=newNotificationChannel("DUBAO","嘟宝安心守护孩子安全",NotificationManager.IMPORTANCE_LOW);NotificationManager manager=getSystemService(NotificationManager.class);manager.createNotificationChannel(channel);Intent intent=newIntent(this,MainActivity.class);PendingIntent pendingIntent=PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_UPDATE_CURRENT|PendingIntent.FLAG_IMMUTABLE);Notification notification=newNotificationCompat.Builder(this,"DUBAO").setContentTitle("嘟宝").setContentText("嘟宝安心守护孩子安全...").setSmallIcon(android.R.drawable.ic_menu_info_details).setContentIntent(pendingIntent).setOngoing(true)// 不可滑动删除.build();startForeground(10001,notification);}}MyMqttClient代码
package com.zilong.dubao;import android.os.Handler;import android.os.HandlerThread;import android.util.Log;import android.widget.Toast;import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;import org.eclipse.paho.client.mqttv3.MqttClient;import org.eclipse.paho.client.mqttv3.MqttConnectOptions;import org.eclipse.paho.client.mqttv3.MqttException;import org.eclipse.paho.client.mqttv3.MqttMessage;import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;import java.nio.charset.StandardCharsets;public classMyMqttClient{private Handler mWorkHandler;private MqttClient client;private MqttConnectOptions connOpts;MyMqttClient(){HandlerThread handlerThread=newHandlerThread("worker");handlerThread.start();mWorkHandler=newHandler(handlerThread.getLooper());}public voidconnect(String uuid){mWorkHandler.post(()->{_connect(uuid);});}private MqttCallbackExtended callbackExtendedallback=newMqttCallbackExtended(){@Override public voidconnectComplete(boolean reconnect,String serverURI){Log.d("mqtt","connectComplete");try{client.subscribe("/duma/#");}catch(MqttException e){e.printStackTrace();}}@Override public voidconnectionLost(Throwable cause){Log.d("mqtt","connectionLost");}@Override public voidmessageArrived(String topic,MqttMessage message)throws Exception{String s=newString(message.getPayload());Log.d("mqtt","主题是:"+topic);Log.d("mqtt","内容是::"+s);}@Override public voiddeliveryComplete(IMqttDeliveryToken token){}};protected void_connect(String uuid){try{String url="tcp://"+MyConfig.mqttip+":"+MyConfig.mqttport;String dubaoID=uuid;client=newMqttClient(url,"dubao_server"+dubaoID,newMemoryPersistence());connOpts=newMqttConnectOptions();connOpts.setCleanSession(true);// 重连接是否清理会话connOpts.setConnectionTimeout(10);connOpts.setKeepAliveInterval(60);//心跳间隔(秒)connOpts.setAutomaticReconnect(true);String s="嘟宝异常掉线了";connOpts.setWill("/dubao/will",s.getBytes(StandardCharsets.UTF_8),0,false);client.setCallback(callbackExtendedallback);_connectionMQTTServer();}catch(MqttException e){e.printStackTrace();}}protected void_connectionMQTTServer(){while(true){try{client.connect(connOpts);break;}catch(MqttException e){Log.d("mqtt","连接失败");e.printStackTrace();}try{Thread.sleep(5*1000);Log.d("mqtt","准备重新连接");}catch(InterruptedException e){e.printStackTrace();}}}public voidpublish(String topic,String msg){publish(topic,msg,0,false);}public voidpublish(String topic,String msg,int qos,boolean retained){mWorkHandler.post(()->{try{MqttMessage message=newMqttMessage(msg.getBytes(StandardCharsets.UTF_8));message.setQos(qos);message.setRetained(retained);client.publish(topic,message);}catch(MqttException e){e.printStackTrace();}});}public voidcolse(){mWorkHandler.post(()->{try{client.disconnect();client.close();}catch(MqttException e){e.printStackTrace();}});}}至此完成MQTT连接,剩下的发布、订阅消息数据格式定义。
