編輯:關於Android編程
MQTT官網:http://mqtt.org/
MQTT介紹:http://www.ibm.com
MQTT Android github:https://github.com/eclipse/paho.mqtt.android
MQTT API:http://www.eclipse.org/paho/files/javadoc/index.html
MQTT Android API: http://www.eclipse.org/paho/files/android-javadoc/index.html
建議時間充裕的同學有順序的閱讀上文五個鏈接內容,不充裕的同學請看下面簡單的介紹(內容大多來自上面五條鏈接)。
MQTT 協議
客戶機較小並且 MQTT 協議 高效地使用網絡帶寬,在這個意義上,其為輕量級。MQTT 協議支持可靠的傳送和即發即棄的傳輸。 在此協議中,消息傳送與應用程序脫離。 脫離應用程序的程度取決於寫入 MQTT 客戶機和 MQTT 服務器的方式。脫離式傳送能夠將應用程序從任何服務器連接和等待消息中解脫出來。 交互模式與電子郵件相似,但在應用程序編程方面進行了優化。
協議具有許多不同的功能:
它是一種發布/預訂協議。 除提供一對多消息分發外,發布/預訂也脫離了應用程序。對於具有多個客戶機的應用程序來說,這些功能非常有用。 它與消息內容沒有任何關系。 它通過 TCP/IP 運行,TCP/IP 可以提供基本網絡連接。 它針對消息傳送提供三種服務質量:之後在浏覽器輸入http://127.0.0.1:61680/,查看是否安裝成功。
subscribe)同一話題(topic)的客戶端會同時收到消息推送。直接實現了“群聊”功能。 clientId:客戶身份唯一標識。 qos:服務質量。 retained:要保留最後的斷開連接信息。 MqttAndroidClient#subscribe():訂閱某個話題。 MqttAndroidClient#publish(): 向某個話題發送消息,之後服務器會推送給所有訂閱了此話題的客戶。 userName:連接到MQTT服務器的用戶名。 passWord :連接到MQTT服務器的密碼。
添加依賴
repositories {
maven {
url "https://repo.eclipse.org/content/repositories/paho-releases/"
}
}
dependencies {
compile 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0'
compile 'org.eclipse.paho:org.eclipse.paho.android.service:1.1.0'
}
添加限權
注冊Service
Android端具體實現
package com.dongyk.service;
import android.app.Service;
...
/**
* MQTT長連接服務
*
* @author 一口仨馍 聯系方式 : [email protected]
* @version 創建時間:2016/9/16 22:06
*/
public class MQTTService extends Service {
public static final String TAG = MQTTService.class.getSimpleName();
private static MqttAndroidClient client;
private MqttConnectOptions conOpt;
// private String host = "tcp://10.0.2.2:61613";
private String host = "tcp://192.168.1.103:61613";
private String userName = "admin";
private String passWord = "password";
private static String myTopic = "topic";
private String clientId = "test";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
init();
return super.onStartCommand(intent, flags, startId);
}
public static void publish(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();
}
}
private void init() {
// 服務器地址(協議+地址+端口號)
String uri = host;
client = new MqttAndroidClient(this, uri, clientId);
// 設置MQTT監聽並且接受消息
client.setCallback(mqttCallback);
conOpt = new MqttConnectOptions();
// 清除緩存
conOpt.setCleanSession(true);
// 設置超時時間,單位:秒
conOpt.setConnectionTimeout(10);
// 心跳包發送間隔,單位:秒
conOpt.setKeepAliveInterval(20);
// 用戶名
conOpt.setUserName(userName);
// 密碼
conOpt.setPassword(passWord.toCharArray());
// last will message
boolean doConnect = true;
String message = "{\"terminal_uid\":\"" + clientId + "\"}";
String topic = myTopic;
Integer qos = 0;
Boolean retained = false;
if ((!message.equals("")) || (!topic.equals(""))) {
// 最後的遺囑
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();
}
}
@Override
public void onDestroy() {
try {
client.disconnect();
} catch (MqttException e) {
e.printStackTrace();
}
super.onDestroy();
}
/** 連接MQTT服務器 */
private void doClientConnection() {
if (!client.isConnected() && isConnectIsNomarl()) {
try {
client.connect(conOpt, null, iMqttActionListener);
} catch (MqttException e) {
e.printStackTrace();
}
}
}
// MQTT是否連接成功
private IMqttActionListener iMqttActionListener = new IMqttActionListener() {
@Override
public void onSuccess(IMqttToken arg0) {
Log.i(TAG, "連接成功 ");
try {
// 訂閱myTopic話題
client.subscribe(myTopic,1);
} catch (MqttException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(IMqttToken arg0, Throwable arg1) {
arg1.printStackTrace();
// 連接失敗,重連
}
};
// MQTT監聽並且接受消息
private MqttCallback mqttCallback = new MqttCallback() {
@Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
String str1 = new String(message.getPayload());
MQTTMessage msg = new MQTTMessage();
msg.setMessage(str1);
EventBus.getDefault().post(msg);
String str2 = topic + ";qos:" + message.getQos() + ";retained:" + message.isRetained();
Log.i(TAG, "messageArrived:" + str1);
Log.i(TAG, str2);
}
@Override
public void deliveryComplete(IMqttDeliveryToken arg0) {
}
@Override
public void connectionLost(Throwable arg0) {
// 失去連接,重連
}
};
/** 判斷網絡是否連接 */
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;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
首先初始化各個參數,之後連接服務器。連接成功之後在http://127.0.0.1:61680/看到自動創建了名稱為”topic”的
topic。這裡我使用了一個真機和一個模擬器運行程序。http://127.0.0.1:61680/服務端看到的是這個樣子
這裡需要注意兩個地方
1. 模擬器運行的時候host = "tcp://10.0.2.2:61613",因為10.0.2.2 是模擬器設置的特定ip,是你電腦的別名。真機運行的時候
host = "tcp://192.168.1.103:61613"。192.168.1.103是我主機的IPv4地址,查看本機IP的cmd命令為
ipconfig/all。
2. 兩次運行時的clientId不能一樣(為了保證客戶標識的唯一性)。
這裡為了測試,在
MQTTService中暴露了一個公共方法
publish(String msg)給
MainActivity調用。代碼如下
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
EventBus.getDefault().register(this);
startService(new Intent(this, MQTTService.class));
findViewById(R.id.publishBtn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
MQTTService.publish("CSDN 一口仨馍");
}
});
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void getMqttMessage(MQTTMessage mqttMessage){
Log.i(MQTTService.TAG,"get message:"+mqttMessage.getMessage());
Toast.makeText(this,mqttMessage.getMessage(),Toast.LENGTH_SHORT).show();
}
@Override
protected void onDestroy() {
EventBus.getDefault().unregister(this);
super.onDestroy();
}
}
這裡使用了
EventBus3.0發送消息。當然,你也可以使用接口回調的方式甚至直接在Service中彈出
Toast。whatever,現在點擊一個客戶端
MainActivity中的
Button,兩個客戶端已經能同時彈出消息。已經
get到數據了。接下來,show time~
概述Android Settings模塊說簡單也簡單,說難也難,裡面涉及到的知識點也挺多的。我們知道Settings主要是用於配置一些系統選項或屬性值,通過修改設置項就能
onReceiveError是WebViewClient提供的方法,用於網頁產生錯誤時進行回調處理。1. 舊版的onReceiveError在API23之前,該方法的簽名
最近學習android時發現,很多書上都介紹了preference首選項這個東西,但是大部分的書都是直接上來講怎麼用,對其的用途和來歷都是只字不提,筆者本人對於這種做法是
①從設計的角度來講:Android的Activity的設計與Web頁面非常類似,從頁面的跳轉通過連接,以及從頁面的定位通過URL,從每個頁面的獨立封裝等方面都可以看出來,