MQTT安卓客户端开发目的:
1.作为发布者测试mqtt服务器
2.作为接受者监测发布者数据
3.将接收数据图像化
安卓初学者
先简单展示一下,折线图会实时更新所订阅主题的信息
折线图部分使用MPAndroidChart
github地址:https://github.com/PhilJay/MPAndroidChart
主界面:
主界面xml文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MQTT">
<com.github.mikephil.charting.charts.LineChart
android:id="@+id/chart"
android:layout_marginTop="20dp"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#ffffff"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="服务器:"
android:textSize="25sp"
android:textStyle="bold"
android:id="@+id/fuwuqi"
android:layout_marginTop="250dp"
android:layout_marginLeft="10dp"
/>
<EditText
android:id="@+id/fuwuqi_"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textStyle="bold"
android:layout_toRightOf="@+id/fuwuqi"
android:layout_marginTop="250dp"
android:layout_marginLeft="10dp"
android:width="185dp"
android:height="40dp"
android:hint="地址"
/>
<TextView
android:id="@+id/zhuti"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="主题:"
android:textSize="25sp"
android:textStyle="bold"
android:layout_below="@+id/mima"
android:layout_marginTop="20dp"
android:layout_marginLeft="10dp"
/>
<EditText
android:id="@+id/zhuti_"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textStyle="bold"
android:layout_toRightOf="@+id/zhuti"
android:layout_alignBottom="@+id/zhuti"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:width="210dp"
android:height="40dp"
android:hint="主题"
/>
<TextView
android:id="@+id/yonghuming"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="用户名:"
android:textSize="25sp"
android:textStyle="bold"
android:layout_below="@+id/fuwuqi"
android:layout_marginTop="15dp"
android:layout_marginLeft="10dp"
/>
<EditText
android:id="@+id/yonghuming_"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textStyle="bold"
android:layout_toRightOf="@+id/yonghuming"
android:layout_alignBottom="@+id/yonghuming"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:width="185dp"
android:height="40dp"
android:hint="admin"
/>
<TextView
android:id="@+id/mima"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="密码:"
android:textSize="25sp"
android:textStyle="bold"
android:layout_below="@+id/yonghuming"
android:layout_marginTop="15dp"
android:layout_marginLeft="10dp"
/>
<EditText
android:id="@+id/mima_"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textStyle="bold"
android:layout_toRightOf="@+id/mima"
android:layout_alignBottom="@+id/mima"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:width="210dp"
android:height="40dp"
android:hint="密码"
/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="连接"
android:textSize="25sp"
android:textStyle="bold"
android:layout_marginTop="250dp"
android:layout_alignParentRight="true"
android:layout_marginRight="5dp"
android:width="20dp"
android:height="140dp"
/>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="订阅"
android:textSize="25sp"
android:textStyle="bold"
android:layout_below="@+id/button"
android:layout_marginTop="10dp"
android:layout_alignParentRight="true"
android:layout_marginRight="5dp"
/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送"
android:textSize="25sp"
android:textStyle="bold"
android:layout_below="@+id/button1"
android:layout_marginTop="10dp"
android:layout_alignParentRight="true"
android:layout_marginRight="5dp"
android:height="150dp"
/>
<TextView
android:id="@+id/xuanze"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="选择主题"
android:textSize="25sp"
android:textStyle="bold"
android:layout_below="@+id/zhuti"
android:layout_marginTop="20dp"
android:layout_marginLeft="10dp"
/>
<EditText
android:id="@+id/fa"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textStyle="bold"
android:layout_below="@+id/xuanze"
android:layout_marginLeft="10dp"
android:width="300dp"
android:height="50dp"
android:hint="发送框:"
/>
<TextView
android:id="@+id/shou"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textStyle="bold"
android:layout_below="@+id/fa"
android:layout_marginLeft="10dp"
android:width="300dp"
android:height="75dp"
android:text="接收框:"
/>
<Spinner
android:id="@+id/spinner"
android:layout_below="@+id/zhuti_"
android:layout_toRightOf="@+id/xuanze"
android:layout_width="180dp"
android:layout_marginTop="20dp"
android:layout_marginLeft="15dp"
android:layout_height="30dp"
/>
</RelativeLayout>
后端
MQTTservice,java
/**
* MQTT长连接服务
* Created by cym1497 on 2017/7/10.
*/
public class MQTTService extends Service {
public static final String TAG = MQTTService.class.getSimpleName();
private static MQTTService instance;
private static MqttAndroidClient client;
private MqttConnectOptions conOpt;
public static String mytopic;
@Override
public void onCreate() {
super.onCreate();
instance = this;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
init();
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
instance = null;
try {
client.disconnect();
client.unregisterResources();
} catch (MqttException e) {
e.printStackTrace();
}
super.onDestroy();
}
public static void publish(String myTopic,String msg){
String topic = myTopic;
Integer qos = 0;
Boolean retained = false;
try {
client.publish(topic, msg.getBytes(), qos.intValue(), retained.booleanValue());
} catch (MqttException e) {
e.printStackTrace();
}
}
// MQTT监听连接情况
private IMqttActionListener iMqttActionListener = new ActionListener();
// MQTT监听并且接受消息
private MqttCallback mqttCallback = new CallBack();
private void init() {
MQTT.clientId = MacAddressUtil.getLocalMacAddress(this);
// 服务器地址(协议+地址+端口号)
String uri = MQTT.host;
client = new MqttAndroidClient(this, uri, MQTT.clientId);
// 设置MQTT监听并且接受消息
client.setCallback(mqttCallback);
conOpt = new MqttConnectOptions();
// 清除缓存
conOpt.setCleanSession(true);
// 设置超时时间,单位:秒
conOpt.setConnectionTimeout(10);
// 心跳包发送间隔,单位:秒
conOpt.setKeepAliveInterval(20);
// 用户名
conOpt.setUserName(MQTT.userName);
// 密码
conOpt.setPassword(MQTT.passWord.toCharArray());
// last will message
boolean doConnect = true;
// String message = "{\"terminal_uid\":\"" + MQTT.clientId + "\"}";
// String topic = MQTT.myTopic;
// Integer qos = 0;
// Boolean retained = false;
// if (TextUtils.isEmpty(message) || TextUtils.isEmpty(topic)) {
// // 最后发送的消息
// try {
// conOpt.setWill(topic, message.getBytes(), qos.intValue(), retained.booleanValue());
// } catch (Exception e) {
// Log.i(TAG, "Exception Occured", e);
// doConnect = false;
// iMqttActionListener.onFailure(null, e);
// }
// }
//
if (doConnect) {
doClientConnection();
}
}
/** 连接MQTT服务器 */
private void doClientConnection() {
if (!client.isConnected() && isConnectIsNomarl()) {
try {
client.connect(conOpt, null, iMqttActionListener);
} catch (MqttException e) {
e.printStackTrace();
}
}
}
/** 判断网络是否连接 */
private boolean isConnectIsNomarl() {
ConnectivityManager connectivityManager = (ConnectivityManager) this.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = connectivityManager.getActiveNetworkInfo();
if (info != null && info.isAvailable()) {
String name = info.getTypeName();
Log.i(TAG, "MQTT当前网络名称:" + name);
return true;
} else {
Log.i(TAG, "MQTT 没有可用网络");
return false;
}
}
public static boolean isConnect(){
if (instance != null && client != null){
return instance.client.isConnected();
}
return false;
}
public static void connect(){
if (instance != null && client != null){
instance.doClientConnection();
}
}
public static void disconnect(){
if (instance != null){
try {
instance.client.disconnect();
} catch (MqttException e) {
e.printStackTrace();
}
}
}
public static class ActionListener implements IMqttActionListener {
@Override
public void onSuccess(IMqttToken arg0) {
Log.i(TAG, "连接成功 ");
// try {
// // 订阅myTopic话题
// client.subscribe(MQTT.myTopic,1);
// } catch (MqttException e) {
// e.printStackTrace();
// }
}
@Override
public void onFailure(IMqttToken arg0, Throwable arg1) {
arg1.printStackTrace();
// 连接失败,重连
Log.i("mtqq", "连接失败");
}
}
public static class CallBack implements MqttCallback {
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
mytopic = topic;
String str1 = new String(message.getPayload());
MQTTMessage msg = new MQTTMessage();
msg.setMessage(str1);
EventBus.getDefault().post(msg);
String str2 = "topic1:" + topic+ ", qos:" + message.getQos() + ", retained:" + message.isRetained();
Log.i(TAG, "messageArrived:" + str1);
Log.i(TAG, str2);
}
@Override
public void deliveryComplete(IMqttDeliveryToken arg0) {
Log.i("mtqq", "deliveryComplete");
}
@Override
public void connectionLost(Throwable arg0) {
// 失去连接,重连
String message = "null";
if (arg0 != null) {
message = arg0.getMessage();
}
Log.i("mtqq", "connectionLost:"+message);
}
}
//订阅消息
public void dingyue(String myTopic){
try {
// 订阅myTopic话题
client.subscribe(myTopic,1);
} catch (MqttException e) {
e.printStackTrace();
}
}
}
MQTT.java
public class MQTT extends AppCompatActivity implements View.OnClickListener{
public static String host ;//= "tcp://123.56.96.198:1883";
public static String userName = "admin";
public static String passWord = "password";
public static String myTopic ;
public static String clientId = "test2";
private static EditText fuwuqi;
private static EditText zhuti;
private static TextView shou;
private static TextView yonghuming;
private static TextView mima;
private static Button button;
private static EditText fa;
private static boolean linjie=false;
private static MqttAndroidClient client;
private static MQTTService mqttService = new MQTTService();
private Spinner spinner;
private List<String> data_list;
private ArrayAdapter<String> arr_adapter;
private static LineChart chart ;
private static List<Integer> a;
private static boolean aa = true;
private static boolean aaa =false;
/* private EditText fuwuqi ;
private Button button;
private Button button1;
private EditText zhuti;
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_m_q_t_t);
spinner = (Spinner) findViewById(R.id.spinner);
chart = (LineChart) findViewById(R.id.chart);
a = new ArrayList<Integer>();
//折线图
/*
chart = findViewById(R.id.chart);
ArrayList<Entry> valsComp1 = new ArrayList<Entry>();
ArrayList<Entry> valsComp2 = new ArrayList<Entry>();
Entry c1e1 = new Entry(100.000f, 0); // 0 == quarter 1
valsComp1.add(c1e1);
Entry c1e2 = new Entry(50.000f, 1); // 1 == quarter 2 ...
valsComp1.add(c1e2);
// and so on ...
Entry c2e1 = new Entry(120.000f, 0); // 0 == quarter 1
valsComp2.add(c2e1);
Entry c2e2 = new Entry(110.000f, 1); // 1 == quarter 2 ...
valsComp2.add(c2e2);
LineDataSet setComp1 = new LineDataSet(valsComp1, "Company 1");
setComp1.setAxisDependency(YAxis.AxisDependency.LEFT);
LineDataSet setComp2 = new LineDataSet(valsComp2, "Company 2");
setComp2.setAxisDependency(YAxis.AxisDependency.LEFT);
//...
ArrayList<LineDataSet> dataSets = new ArrayList<LineDataSet>();
dataSets.add(setComp1);
// dataSets.add(setComp2);
ArrayList<String> xVals = new ArrayList<String>();
xVals.add("1.Q"); xVals.add("2.Q"); xVals.add("3.Q"); xVals.add("4.Q");
LineData data = new LineData(setComp2);
chart.setData(data);
chart.invalidate();
*/
//ChartUtils c = new ChartUtils();
//c.setChartData(chart,valsComp2);
//XAxis xAxis = chart.getXAxis();
// chart.setOnChartValueSelectedListener(this);
//chart.setBackgroundColor(0xff00ff00);//设置背景颜射
//chart.invalidate();//刷新
//chart.setDescription(a);//设置右下文字
//chart.setMaxVisibleValueCount(10);//设置最大可绘制数量
//数据
data_list = new ArrayList<String>();
data_list.add("下拉选择");
//适配器
arr_adapter= new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, data_list);
//设置样式
arr_adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
//加载适配器
spinner.setAdapter(arr_adapter);
/*
button = findViewById(R.id.button);
fuwuqi = findViewById(R.id.fuwuqi_);
button1 = findViewById(R.id.button1);
zhuti = findViewById(R.id.zhuti_);
*/
shou = findViewById(R.id.shou);
fuwuqi = findViewById(R.id.fuwuqi_);
yonghuming = findViewById(R.id.yonghuming_);
mima = findViewById(R.id.mima_);
button = findViewById(R.id.button);
zhuti = findViewById(R.id.zhuti_);
fa = findViewById(R.id.fa);
EventBus.getDefault().register(this);
findViewById(R.id.button).setOnClickListener(this);
findViewById(R.id.button1).setOnClickListener(this);
findViewById(R.id.button2).setOnClickListener(this);
}
private boolean isServiceRunning() {
return ServiceUtil.isServiceWork(this, MQTTService.class.getName());
}
@Override
public void onClick(View v) {
boolean isRunning = isServiceRunning();
switch (v.getId()){
case R.id.button:
if(TextUtils.isEmpty(fuwuqi.getText())&&!linjie) {
Toast toast=Toast.makeText(getApplicationContext(), "请输入服务器地址", Toast.LENGTH_SHORT);
toast.show();
}else if(linjie){
button.setText("连接");
linjie=false;
if (!isRunning){
ToastUtil.showToast(this, "MQTT Service stopped");
} else {
ToastUtil.showToast(this, "MQTT Service stopping");
stopService(new Intent(this, MQTTService.class));
}
}else{
linjie =true;
if(!(TextUtils.isEmpty(yonghuming.getText()))) {
userName = yonghuming.getText().toString();
}
if(!(TextUtils.isEmpty(mima.getText()))) {
passWord = mima.getText().toString();
}
button.setText("断开");
host = fuwuqi.getText().toString();
System.out.println(host);
if (isRunning) {
ToastUtil.showToast(this, "MQTT Service started");
} else {
ToastUtil.showToast(this, "MQTT Service starting !");
startService(new Intent(this, MQTTService.class));
}
}
break;
/*
case R.id.stop:
if (!isRunning){
ToastUtil.showToast(this, "MQTT Service stopped");
} else {
ToastUtil.showToast(this, "MQTT Service stopping");
stopService(new Intent(this, MQTTService.class));
}
break;
*/
case R.id.button1:
if (!isRunning){
ToastUtil.showToast(this, "please start MQTT Service");
break;
}
if (MQTTService.isConnect()) {
if(TextUtils.isEmpty(zhuti.getText())) {
ToastUtil.showToast(this, "请输入主题");
break;
}else {
myTopic = zhuti.getText().toString();
for (int i = 0; i < data_list.size(); i++) {
if(data_list.get(i).equals(myTopic)){
System.out.println(data_list.get(i));
ToastUtil.showToast(this, "该主题已经订阅");
}else if (i==(data_list.size()-1)){
data_list.add(myTopic);
}
//System.out.println(data_list.get(i));
}
//data_list.add(myTopic);
System.out.println(myTopic);
mqttService.dingyue(myTopic);
ToastUtil.showToast(this, "MQTT Service connected");
MQTTService.connect();
break;
}
}
ToastUtil.showToast(this, "MQTT Service connecting");
break;
/* case R.id.disconnect:
if (!isRunning){
ToastUtil.showToast(this, "please start MQTT Service");
break;
}
if (!MQTTService.isConnect()){
ToastUtil.showToast(this, "MQTT Service disconnected");
break;
}
ToastUtil.showToast(this, "MQTT Service disconnecting");
MQTTService.disconnect();
break;*/
case R.id.button2:
if (!isRunning){
ToastUtil.showToast(this, "please start MQTT Service");
break;
}
if (!MQTTService.isConnect()){
ToastUtil.showToast(this, "please connect");
break;
}
if(!(TextUtils.isEmpty(fa.getText()))){
MQTTService.publish((String) spinner.getSelectedItem(),fa.getText().toString());
break;
}else{
ToastUtil.showToast(this, "请发送输入内容");
break;
}
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void getMqttMessage(MQTTMessage mqttMessage) {
String message = mqttMessage.getMessage();
System.out.println(MQTTService.mytopic);
System.out.println(spinner.getSelectedItem());
if (MQTTService.mytopic.toString().equals(spinner.getSelectedItem().toString())&&MQTTService.mytopic.toString().equals(data_list.get(1))) { //spinner.getSelectedItem().toString()
aaa=true;
if(aa) {
for (int i = 0; i < a.size(); i++)
{
a.remove(i);
}
aa=false;
}
a.add(Integer.parseInt(message));
initLineChart(a);
shou.setText(message);
}else if (MQTTService.mytopic.toString().equals(spinner.getSelectedItem().toString())&&MQTTService.mytopic.toString().equals(data_list.get(2))) { //spinner.getSelectedItem().toString()
aaa=true;
if(!aa) {
for (int i = 0; i < a.size(); i++)
{
a.remove(i);
}
aa=true;
}
a.add(Integer.parseInt(message));
initLineChart(a);
shou.setText(message);
}else {
Log.i(MQTTService.TAG, "get message1:" + message);
//Log.i(MQTTService.TAG,"get message1:"+mqttMessage);
Toast.makeText(this, mqttMessage.getMessage(), Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onDestroy() {
EventBus.getDefault().unregister(this);
super.onDestroy();
}
//
/**
* 初始化曲线图表
*
* @param list 数据集
*/
private void initLineChart(final List<Integer> list)
{
//显示边界
chart.setDrawBorders(false);
//设置数据
List<Entry> entries = new ArrayList<>();
for (int i = 0; i < list.size(); i++)
{
entries.add(new Entry(i, (float) list.get(i)));
}
//一个LineDataSet就是一条线
LineDataSet lineDataSet = new LineDataSet(entries, "");
//线颜色
//lineDataSet.setColor(Color.parseColor("#F15A4A"));
//线宽度
lineDataSet.setLineWidth(1.6f);
//不显示圆点
lineDataSet.setDrawCircles(false);
//线条平滑
lineDataSet.setMode(LineDataSet.Mode.HORIZONTAL_BEZIER);
//设置折线图填充
// lineDataSet.setDrawFilled(true);
LineData data = new LineData(lineDataSet);
//无数据时显示的文字
chart.setNoDataText("暂无数据");
//折线图不显示数值
data.setDrawValues(false);
//得到X轴
XAxis xAxis = chart.getXAxis();
//设置X轴的位置(默认在上方)
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
//设置X轴坐标之间的最小间隔
xAxis.setGranularity(1f);
//设置X轴的刻度数量,第二个参数为true,将会画出明确数量(带有小数点),但是可能值导致不均匀,默认(6,false)
xAxis.setLabelCount(list.size() / 6, false);
//设置X轴的值(最小值、最大值、然后会根据设置的刻度数量自动分配刻度显示)
xAxis.setAxisMinimum(0f);
xAxis.setAxisMaximum((float) list.size());
//不显示网格线
xAxis.setDrawGridLines(false);
// 标签倾斜
xAxis.setLabelRotationAngle(45);
//设置X轴值为字符串
xAxis.setValueFormatter(new IAxisValueFormatter()
{
@Override
public String getFormattedValue(float value, AxisBase axis)
{
int IValue = (int) value;
CharSequence format = DateFormat.format("MM/dd",
System.currentTimeMillis()-(long)(list.size()-IValue)*24*60*60*1000);
return format.toString();
}
});
//得到Y轴
YAxis yAxis = chart.getAxisLeft();
YAxis rightYAxis = chart.getAxisRight();
//设置Y轴是否显示
rightYAxis.setEnabled(false); //右侧Y轴不显示
//设置y轴坐标之间的最小间隔
//不显示网格线
yAxis.setDrawGridLines(false);
//设置Y轴坐标之间的最小间隔
yAxis.setGranularity(1);
//设置y轴的刻度数量
//+2:最大值n就有n+1个刻度,在加上y轴多一个单位长度,为了好看,so+2
yAxis.setLabelCount(Collections.max(list) + 2, false);
//设置从Y轴值
yAxis.setAxisMinimum(0f);
//+1:y轴多一个单位长度,为了好看
yAxis.setAxisMaximum(Collections.max(list) + 1);
//y轴
yAxis.setValueFormatter(new IAxisValueFormatter()
{
@Override
public String getFormattedValue(float value, AxisBase axis)
{
int IValue = (int) value;
return String.valueOf(IValue);
}
});
//图例:得到Lengend
Legend legend = chart.getLegend();
//隐藏Lengend
legend.setEnabled(false);
//右下添加描述
if (aa&&aaa) {
chart.getDescription().setText(data_list.get(2));
} else if(!aa&&aaa){
chart.getDescription().setText(data_list.get(1));
}
//隐藏描述
//Description description = new Description();
//description.setEnabled(false);
//chart.setDescription(description);
//折线图点的标记
//MyMarkerView mv = new MyMarkerView(this);
//chart.setMarker(mv);
//设置数据
chart.setData(data);
//图标刷新
chart.invalidate();
}
}