編輯:關於Android編程
客戶端:
package com.example.fc.activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.provider.Settings.Secure;
import android.util.Log;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttPersistenceException;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence;
import java.util.Locale;
/**
* 推送服務
*/
public class MqttService extends Service implements MqttCallback {
public static final String DEBUG_TAG = MqttService; // Log標記
public static String MQTT_CLIENT_ID = Fangchao;
private static final String MQTT_THREAD_NAME = MqttService[ + DEBUG_TAG + ]; // Handler Thread ID
private static final String MQTT_BROKER_TEST = 192.168.0.183; //測試地址
private static final String MQTT_BROKER_ONLINE = mqtt.supumall.com; //正式地址
private static final String MQTT_BROKER = MQTT_BROKER_TEST;
private static final int MQTT_PORT = 1883; // 服務器推送端口
public static final int MQTT_QOS_0 = 0; //消息投放級別 QOS Level 0 (最多一次,有可能重復或丟失。 )
public static final int MQTT_QOS_1 = 1; //消息投放級別 QOS Level 1 (至少一次,有可能重復。 )
public static final int MQTT_QOS_2 = 2; //消息投放級別 QOS Level 2 (只有一次,確保消息只到達一次(用於比較嚴格的計費系統)。)
public static final String[] topicFilters = {Fangchao};//訂閱的主題
public static int[] qos = {MQTT_QOS_0};//訂閱級別
private static final int MQTT_KEEP_ALIVE = 4 * 60 * 1000; //心跳包時間,毫秒
private static final String MQTT_KEEP_ALIVE_TOPIC_FORAMT = /users/%s/keepalive; // Topic format for KeepAlives
private static final byte[] MQTT_KEEP_ALIVE_MESSAGE = {0}; // 心跳包發送內容
private static final int MQTT_KEEP_ALIVE_QOS = MQTT_QOS_0; //心跳包的發送級別默認最低
private static final boolean MQTT_CLEAN_SESSION = true; // Start a clean session?
private static final String MQTT_URL_FORMAT = tcp://%s:%d; // 推送url格式組裝
private static final String ACTION_START = MQTT_CLIENT_ID + .START; // Action to start 啟動
private static final String ACTION_STOP = MQTT_CLIENT_ID + .STOP; // Action to stop 停止
private static final String ACTION_KEEPALIVE = MQTT_CLIENT_ID + .KEEPALIVE; // Action to keep alive used by alarm manager保持心跳鬧鐘使用
private static final String ACTION_RECONNECT = MQTT_CLIENT_ID + .RECONNECT; // Action to reconnect 重新連接
private static final String DEVICE_ID_FORMAT = an_%s; // 設備id的前綴
// Note:設備id限制長度為23個 字符
// An NPE if you go over that limit
private boolean mStarted = false; //推送client是否啟動
private String mDeviceId; // Device ID, Secure.ANDROID_ID
private Handler mConnHandler; // Seperate Handler thread for networking
private MqttDefaultFilePersistence mDataStore; // Defaults to FileStore
// private MqttConnectOptions mOpts; //連接參數
private MqttTopic mKeepAliveTopic; // Instance Variable for Keepalive topic
private MqttClient mClient; // Mqtt Client
private AlarmManager mAlarmManager; //鬧鐘
private ConnectivityManager mConnectivityManager; //網絡改變接收器
/**
* 啟動推送服務
*
* @param ctx context to start the service with
* @return void
*/
public static void actionStart(Context ctx) {
Intent i = new Intent(ctx, MqttService.class);
i.setAction(ACTION_START);
ctx.startService(i);
}
/**
* 停止推送服務
*
* @param ctx context to start the service with
* @return void
*/
public static void actionStop(Context ctx) {
Intent i = new Intent(ctx, MqttService.class);
i.setAction(ACTION_STOP);
ctx.startService(i);
}
/**
* 發送心跳包
*
* @param ctx context to start the service with
* @return void
*/
public static void actionKeepalive(Context ctx) {
Intent i = new Intent(ctx, MqttService.class);
i.setAction(ACTION_KEEPALIVE);
ctx.startService(i);
}
/**
* Initalizes the DeviceId and most instance variables
* Including the Connection Handler, Datastore, Alarm Manager
* and ConnectivityManager.
* 初始化設備id和請求參數包含連接處理、數據存儲、鬧鐘警報、網絡接收器
*/
@Override
public void onCreate() {
super.onCreate();
Log.e(fc,oncreate);
//初始化設備id,長度不能超過23
mDeviceId = String.format(DEVICE_ID_FORMAT,
Secure.getString(getContentResolver(), Secure.ANDROID_ID));
HandlerThread thread = new HandlerThread(MQTT_THREAD_NAME);
thread.start();
mConnHandler = new Handler(thread.getLooper());
mDataStore = new MqttDefaultFilePersistence(getCacheDir().getAbsolutePath());
// mOpts = new MqttConnectOptions();
// mOpts.setCleanSession(MQTT_CLEAN_SESSION);
// Do not set keep alive interval on mOpts we keep track of it with alarm's
mAlarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
mConnectivityManager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
}
@Override
public boolean isRestricted() {
return super.isRestricted();
}
/**
* Service onStartCommand
* Handles the action passed via the Intent
* 通過意圖處理服務
*
* @return START_REDELIVER_INTENT
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
String action = intent.getAction();
Log.e(DEBUG_TAG, 推送服務接收到一個請求 + action);
if (action == null) {
Log.e(DEBUG_TAG, 推送服務接收到的請求為null!推送服務不執行任何操作);
} else {
if (action.equals(ACTION_START)) {
Log.e(DEBUG_TAG, 接收到《啟動》推送服務命令);
start();
} else if (action.equals(ACTION_STOP)) {
Log.e(DEBUG_TAG, 接收到《停止》推送服務命令);
stop();
} else if (action.equals(ACTION_KEEPALIVE)) {
Log.e(DEBUG_TAG, 接收到《發送心跳包》推送服務命令);
keepAlive();
} else if (action.equals(ACTION_RECONNECT)) {
Log.e(DEBUG_TAG, 接收到《重啟》推送服務命令);
if (isNetworkAvailable()) {
reconnectIfNecessary();
}
}
}
return START_REDELIVER_INTENT;
}
/**
* 嘗試啟動推送服務器,並注冊網絡改變接收器
*/
private synchronized void start() {
if (mStarted) {
Log.e(DEBUG_TAG, 嘗試啟動推送服務,但推送服務已經啟動);
return;
}
if (hasScheduledKeepAlives()) {
stopKeepAlives();
}
connect();
registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
/**
* 停止推送服務
*/
private synchronized void stop() {
if (!mStarted) {
Log.e(DEBUG_TAG, 試圖停止推送服務器但是推送服務並沒有運行);
return;
}
if (mClient != null) {
mConnHandler.post(new Runnable() {
@Override
public void run() {
try {
mClient.disconnect();
} catch (MqttException ex) {
ex.printStackTrace();
}
mClient = null;
mStarted = false;
stopKeepAlives();
}
});
}
unregisterReceiver(mConnectivityReceiver);
}
/**
* Connects to the broker with the appropriate datastore
* 連接到推送服務器與適當的數據存儲
*/
private synchronized void connect() {
String url = String.format(Locale.US, MQTT_URL_FORMAT, MQTT_BROKER, MQTT_PORT);
Log.e(DEBUG_TAG, 連接推送服務器 設備id: + mDeviceId + with URL: + url);
try {
mClient = new MqttClient(url, mDeviceId, mDataStore);
} catch (MqttException e) {
e.printStackTrace();
}
mConnHandler.post(new Runnable() {
@Override
public void run() {
try {
mClient.connect();
mClient.subscribe(topicFilters, qos);
mClient.setCallback(MqttService.this);
mStarted = true; // Service is now connected
Log.e(DEBUG_TAG, 成功連接推送服務器並啟動心跳包鬧鐘);
startKeepAlives();
} catch (MqttException e) {
e.printStackTrace();
}
}
});
}
/**
* 啟動心跳包鬧鐘
*/
private void startKeepAlives() {
Intent i = new Intent();
i.setClass(this, MqttService.class);
i.setAction(ACTION_KEEPALIVE);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
mAlarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + MQTT_KEEP_ALIVE,
MQTT_KEEP_ALIVE, pi);
}
/**
* 取消已經存在的鬧鐘
*/
private void stopKeepAlives() {
Intent i = new Intent();
i.setClass(this, MqttService.class);
i.setAction(ACTION_KEEPALIVE);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);
mAlarmManager.cancel(pi);
}
/**
* 發送心跳數據到服務器
*/
private synchronized void keepAlive() {
if (isConnected()) {
try {
sendKeepAlive();
return;
} catch (MqttConnectivityException ex) {
ex.printStackTrace();
reconnectIfNecessary();
} catch (MqttPersistenceException ex) {
ex.printStackTrace();
stop();
} catch (MqttException ex) {
ex.printStackTrace();
stop();
}
}
}
/**
* 重新連接如果他是必須的
*/
private synchronized void reconnectIfNecessary() {
if (mStarted && mClient == null) {
connect();
} else {
Log.e(DEBUG_TAG, 重新連接沒有啟動,mStarted: + String.valueOf(mStarted) + mClient: + mClient);
}
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
/**
* 通過ConnectivityManager查詢網絡連接狀態
*
* @return 如果網絡狀態正常則返回true反之flase
*/
private boolean isNetworkAvailable() {
NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
return (info == null) ? false : info.isConnected() && info.isAvailable();
}
/**
* 判斷推送服務是否連接
*
* @return 如果是連接的則返回true反之false
*/
private boolean isConnected() {
if (mStarted && mClient != null && !mClient.isConnected()) {
Log.e(DEBUG_TAG, 判斷推送服務已經斷開);
}
if (mClient != null) {
return (mStarted && mClient.isConnected()) ? true : false;
}
return false;
}
/**
* 網絡狀態發生變化接收器
*/
private final BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (isNetworkAvailable()) {
Log.e(DEBUG_TAG, 網絡連接發生了變化--網絡連接);
reconnectIfNecessary();
} else {
Log.e(DEBUG_TAG, 網絡連接發生了變化--網絡斷開);
stopKeepAlives();
mClient = null;
}
}
};
/**
* 發送保持連接的指定的主題
*
* @return MqttDeliveryToken specified token you can choose to wait for completion
*/
private synchronized MqttDeliveryToken sendKeepAlive()
throws MqttConnectivityException, MqttPersistenceException, MqttException {
if (!isConnected())
throw new MqttConnectivityException();
if (mKeepAliveTopic == null) {
mKeepAliveTopic = mClient.getTopic(
String.format(Locale.US, MQTT_KEEP_ALIVE_TOPIC_FORAMT, mDeviceId));
}
Log.e(DEBUG_TAG, 向服務器發送心跳包url: + MQTT_BROKER);
MqttMessage message = new MqttMessage(MQTT_KEEP_ALIVE_MESSAGE);
message.setQos(MQTT_KEEP_ALIVE_QOS);
return mKeepAliveTopic.publish(message);
}
/**
* 查詢是否已經有一個心跳包的鬧鐘
*
* @return 如果已經有一個心跳包的鬧鐘則返回true反之false
*/
private synchronized boolean hasScheduledKeepAlives() {
Intent i = new Intent();
i.setClass(this, MqttService.class);
i.setAction(ACTION_KEEPALIVE);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, PendingIntent.FLAG_NO_CREATE);
return (pi != null) ? true : false;
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
/**
* 連接丟失回調
*/
@Override
public void connectionLost(Throwable arg0) {
Log.e(DEBUG_TAG, 推送回調函數連接丟失connectionLost方法執行);
stopKeepAlives();
mClient = null;
if (isNetworkAvailable()) {
reconnectIfNecessary();
}
}
/**
* 收到推送信息
*/
@Override
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
Log.e(DEBUG_TAG, 收到推送信息如下
Topic: + topic +
Message: + new String(mqttMessage.getPayload()) +
QoS: + mqttMessage.getQos());
com.example.fc.activity.MqttNotifier.notify(this, new String(mqttMessage.getPayload()));
}
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
Log.e(DEBUG_TAG, 推送回調函數deliveryComplete方法執行);
}
/**
* MqttConnectivityException Exception class
*/
private class MqttConnectivityException extends Exception {
private static final long serialVersionUID = -7385866796799469420L;
}
}
服務端:
package com.fc;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;
import javax.swing.JScrollBar;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.ibm.mqtt.MqttClient;
import com.ibm.mqtt.MqttException;
import com.ibm.mqtt.MqttSimpleCallback;
@SuppressWarnings(unused)
public class MqttBroker {
private static final int SEND_NUMBER = 5;
static TopicConnection connection;
static TopicSession session;/*
public static void main(String[] args) throws JMSException {
// ConnectionFactory :連接工廠,JMS 用它創建連接
ConnectionFactory connectionFactory;
// Connection :JMS 客戶端到JMS Provider 的連接
Connection connection = null;
// Session: 一個發送或接收消息的線程
Session session;
// Destination :消息的目的地;消息發送給誰. ActiveMQConnectionFactory
Destination destination;
// MessageProducer:消息發送者
MessageProducer producer;
// TextMessage message;
// 構造ConnectionFactory實例對象,此處采用ActiveMq的實現jar
connectionFactory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER, ActiveMQConnection.DEFAULT_PASSWORD, tcp://192.168.0.183:61616);
try {
// 構造從工廠得到連接對象
connection = connectionFactory.createConnection();
// 啟動
connection.start();
// 獲取操作連接
session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
// 獲取session注意參數值xingbo.xu-queue是一個服務器的queue,須在在ActiveMq的console配置
destination = session.createQueue(FirstQueue);
// 得到消息生成者【發送者】
producer = session.createProducer(destination);
// 設置不持久化,此處學習,實際根據項目決定
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// 構造消息,此處寫死,項目就是參數,或者方法獲取
sendMessage(session, producer);
session.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != connection)
connection.close();
} catch (Throwable ignore) {
}
}
init();
sendMessage(client123456,11111111111111111111111111111111);
}
private static void init() throws JMSException {
// 創建鏈接工廠
TopicConnectionFactory factory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD, tcp://192.168.0.183:1883);
connection = factory.createTopicConnection();
// 啟動連接
connection.start();
System.out.println(啟動成功);
// 創建一個session會話 transacted
session = connection.createTopicSession(
Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
}
*//**
* 關閉connection和session
*
* @throws Exception
*//*
private void close() throws Exception {
// 關閉釋放資源
if (session != null) {
session.close();
session = null;
}
if (connection != null) {
connection.close();
connection = null;
}
System.out.println(斷開連接);
}
public static int sendMessage( String DESTINATION,String message)throws Exception {
for (int i = 1; i <= 1; i++) {
TextMessage message = session.createTextMessage(ActiveMq 發送的消息 + i);
// 發送消息到目的地方
System.out.println(發送消息: + ActiveMq 發送的消息 + i);
producer.send(message);
}
javax.jms.Topic topic;
try {
// 創建一個消息隊列
topic = session.createTopic(DESTINATION);
} catch (Exception e) {
init();
topic = session.createTopic(DESTINATION);
}
// 創建消息發送者
javax.jms.TopicPublisher publisher = session.createPublisher(topic);
// 設置持久化模式
publisher.setDeliveryMode(DeliveryMode.PERSISTENT);
// flag=0,表示成功;flag=1,表示失敗
int flag = 0;
System.out.println(message);
TextMessage textMessage = session.createTextMessage(message);
publisher.send(textMessage);
return flag;
} */
private final static Log logger = LogFactory.getLog(MqttBroker.class);// 日志對象
// 連接參數
private final static String CONNECTION_STRING = tcp://192.168.0.183:1883;
// private final static String CONNECTION_STRING = tcp://192.168.0.183:1883;
private final static boolean CLEAN_START = true;
private final static short KEEP_ALIVE = 30;// 低耗網絡,但是又需要及時獲取數據,心跳30s
private final static String CLIENT_ID = master;// 客戶端標識
private final static int[] QOS_VALUES = { 0, 0, 2, 0 };// 對應主題的消息級別
private final static String[] TOPICS = { Test/TestTopics/Topic1,
Test/TestTopics/Topic2, Test/TestTopics/Topic3,
client/keepalive };
private static MqttBroker instance = new MqttBroker();
private MqttClient mqttClient;
/**
* 返回實例對象
*
* @return
*/
public static MqttBroker getInstance() {
return instance;
}
/**
* 重新連接服務
*/
private void connect() throws MqttException {
logger.info(connect to mqtt broker.);
System.out.println(connect to mqtt broker.);
mqttClient = new MqttClient(CONNECTION_STRING);
logger.info(***********register Simple Handler***********);
System.out.println(***********register Simple Handler***********);
SimpleCallbackHandler simpleCallbackHandler = new SimpleCallbackHandler();
mqttClient.registerSimpleHandler(simpleCallbackHandler);// 注冊接收消息方法
mqttClient.connect(CLIENT_ID, CLEAN_START, KEEP_ALIVE);
logger.info(***********subscribe receiver topics***********);
System.out.println(***********subscribe receiver topics***********);
mqttClient.subscribe(TOPICS, QOS_VALUES);// 訂閱接主題
logger.info(***********CLIENT_ID: + CLIENT_ID);
System.out.println(***********CLIENT_ID: + CLIENT_ID);
/**
* 完成訂閱後,可以增加心跳,保持網絡通暢,也可以發布自己的消息
*/
mqttClient.publish(keepalive, keepalive.getBytes(), QOS_VALUES[0],
true);// 增加心跳,保持網絡通暢
}
/**
* 發送消息
*
* @param clientId 客戶端主題 不是id
* @param messageId
*/
public void sendMessage(String clientId, String message) {
try {
if (mqttClient == null || !mqttClient.isConnected()) {
connect();
}
System.out.println(send message to + clientId + , message is
+ message);
logger.info(send message to + clientId + , message is
+ message);
// 發布自己的消息
mqttClient.publish(clientId, message.getBytes(),
0, false);
/*mqttClient.publish(GMCC/tokudu/ + clientId, message.getBytes(),
0, false); */
System.out.println( ##################### + CLIENT_ID);
} catch (MqttException e) {
logger.error(e.getCause());
e.printStackTrace();
}
}
/**
* 簡單回調函數,處理server接收到的主題消息
*
* @author Join
*
*/
class SimpleCallbackHandler implements MqttSimpleCallback {
/**
* 當客戶機和broker意外斷開時觸發 可以再此處理重新訂閱
*/
@Override
public void connectionLost() throws Exception {
// TODO Auto-generated method stub
System.out.println(客戶機和broker已經斷開);
}
/** 和broker已
* 客戶端訂閱消息後,該方法負責回調接收處理消息
*/
@Override
public void publishArrived(String topicName, byte[] payload, int Qos,
boolean retained) throws Exception {
// TODO Auto-generated method stub
System.out.println(訂閱主題: + topicName);
System.out.println(消息數據: + new String(payload));
System.out.println(消息級別(0,1,2): + Qos);
System.out.println(是否是實時發送的消息(false=實時,true=服務器上保留的最後消息):
+ retained);
}
}
public static void main(String[] args) {
String ss={ itle: ghjklffff,content:aaaaaaaaaaaaaaaaaaa, ype:1};
new MqttBroker().sendMessage(Fangchao,ss.replace(\, ));
} //一定要用tokudu/a06e51a5f424fb70 不要用tokudu.aasdf 用反斜槓 不要用點
}
客戶端 服務器 所用到的jar 包 。只用wmqtt.jar 就可以進行發送與接收消息,但notification彈窗跳轉有問題,所以客戶端 改用org.eclipse ….jar 服務器還用wmqtt.jar 就可以.客戶端有兩個接受推送服務:第一個是pushservice 用的是wmqtt.jar 第二個是Mqttservice 用到的是org.eclipse…那個。這兩個服務可以在pushactivity中切換,去掉注釋即可。下載鏈接
可以使用該套 SDK開發適用於Android系統移動設備的地圖應用,通過調用地圖SDK接口,您可以輕松訪問百度地圖服務和數據,構建功能豐富、交互性強的LBS(地圖類)應用
1、前言Android Studio是基於IntelliJ IDEA下官方整和的一個Android應用程序開發環境。在IntelliJ強大的代碼編輯器和開發工具基礎之上,
首先上效果圖,類似於360檢測到騷擾電話頁面:布局很簡單,上面是一個RelativeLayout,下面一個Button.功能:(1)彈幕生成後自動從右側往左側滾動(Tra
搭建環境過程:1. 安裝JDK。注:實質上到該網址上下載好JDK安裝包,安裝後添加一個環境變量:JAVA_HOME,其值為:C:\Program Files\Java\j