更新時間:2022-07-28 11:49:55 來源:動力節(jié)點 瀏覽1890次
大家在Java教程中會學(xué)到關(guān)于Java消息推送的知識,那么,Java消息推送框架的代碼是什么?動力節(jié)點小編來為大家解答。
(1)pull:輪詢,輪詢時間短:耗電,耗流量。時間長,不能保證消息及時。
輪詢:
Timer:WakeLock 讓CPU 保持喚醒,耗電量很大
AlarmManager:管理獨立的硬件時鐘RTC,可以在CPU休眠的時候正常運行。在預(yù)設(shè)的時間到達之后,喚醒CPU。這樣CPU可以正常休眠,只需要任務(wù)到達之后醒來一段很短的時間。極光推送就是基于此實現(xiàn)的。
(2)push:SMS、長連接。
(1)GCM:google的Gcm,容易被國內(nèi)廠商閹割,而且NAT(Network AddressTranslation)容易超時,長連接無法保持,造成消息推送延遲。
(2)第三方推送:友盟、極光,騰訊信鴿
(3)自定義長連接:長連接、心跳和推送及時率。
保持長連接,是消息及時的重要保證。發(fā)送心跳包,如果前臺檢測發(fā)送失敗,則重新初始化一個socket。
一般我們這種socket幾乎是跟app的生命周期一樣長,甚至更長。不管在不在Service中去完成操作,我們都得開異步線程,雖然Service并不是異步操作,但是為了提升我們?nèi)蝿?wù)的優(yōu)先級,我們最好是放在Service中,因為Service是由Android系統(tǒng)管理的,并且擁有比較高的優(yōu)先級,線程是Java中的異步任務(wù)載體,可以說android系統(tǒng)不太認識線程。放在Service中可以很大程度上避免任務(wù)被回收或者關(guān)閉
BackSevice服務(wù):
import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Arrays;
public class BackService extends Service {
private static final String TAG = "BackService";
/** 心跳檢測時間 */
private static final long HEART_BEAT_RATE = 3 * 1000;
/** 主機IP地址 */
private static final String HOST = "192.168.1.104";
/** 端口號 */
public static final int PORT = 9800;
/** 消息廣播 */
public static final String MESSAGE_ACTION = "org.feng.message_ACTION";
/** 心跳廣播 */
public static final String HEART_BEAT_ACTION = "org.feng.heart_beat_ACTION";
private long sendTime = 0L;
/** 弱引用 在引用對象的同時允許對垃圾對象進行回收 */
private WeakReference<Socket> mSocket;
private ReadThread mReadThread;
private IBackService.Stub iBackService = new IBackService.Stub() {
@Override
public boolean sendMessage(String message) throws RemoteException {
return sendMsg(message);
}
};
@Override
public IBinder onBind(Intent arg0) {
return (IBinder) iBackService;
}
@Override
public void onCreate() {
super.onCreate();
new InitSocketThread().start();
}
// 發(fā)送心跳包
private Handler mHandler = new Handler();
private Runnable heartBeatRunnable = new Runnable() {
@Override
public void run() {
if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) {
boolean isSuccess = sendMsg("");// 就發(fā)送一個\r\n過去, 如果發(fā)送失敗,就重新初始化一個socket
if (!isSuccess) {
mHandler.removeCallbacks(heartBeatRunnable);
mReadThread.release();
releaseLastSocket(mSocket);
new InitSocketThread().start();
Log.d("ztf"," 發(fā)送失敗,就重新初始化一個socket" );
}
}
mHandler.postDelayed(this, HEART_BEAT_RATE);
}
};
public boolean sendMsg(String msg) {
if (null == mSocket || null == mSocket.get()) {
return false;
}
Socket soc = mSocket.get();
try {
if (!soc.isClosed() && !soc.isOutputShutdown()) {
OutputStream os = soc.getOutputStream();
String message = msg + "\r\n";
os.write(message.getBytes());
os.flush();
sendTime = System.currentTimeMillis();// 每次發(fā)送成功數(shù)據(jù),就改一下最后成功發(fā)送的時間,節(jié)省心跳間隔時間
Log.i(TAG, "發(fā)送成功的時間:" + sendTime);
} else {
return false;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
// 初始化socket
private void initSocket() throws UnknownHostException, IOException {
Socket socket = new Socket(HOST, PORT);
mSocket = new WeakReference<Socket>(socket);
mReadThread = new ReadThread(socket);
mReadThread.start();
mHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);// 初始化成功后,就準備發(fā)送心跳包
}
// 釋放socket
private void releaseLastSocket(WeakReference<Socket> mSocket) {
try {
if (null != mSocket) {
Socket sk = mSocket.get();
if (!sk.isClosed()) {
sk.close();
}
sk = null;
mSocket = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
class InitSocketThread extends Thread {
@Override
public void run() {
super.run();
try {
initSocket();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ReadThread extends Thread {
private WeakReference<Socket> mWeakSocket;
private boolean isStart = true;
public ReadThread(Socket socket) {
mWeakSocket = new WeakReference<Socket>(socket);
}
public void release() {
isStart = false;
releaseLastSocket(mWeakSocket);
}
@SuppressLint("NewApi")
@Override
public void run() {
super.run();
Socket socket = mWeakSocket.get();
if (null != socket) {
try {
InputStream is = socket.getInputStream();
byte[] buffer = new byte[1024 * 4];
int length = 0;
while (!socket.isClosed() && !socket.isInputShutdown()
&& isStart && ((length = is.read(buffer)) != -1)) {
if (length > 0) {
String message = new String(Arrays.copyOf(buffer,
length)).trim();
Log.i(TAG, "收到服務(wù)器發(fā)送來的消息:"+message);
// 收到服務(wù)器過來的消息,就通過Broadcast發(fā)送出去
if (message.equals("ok")) {// 處理心跳回復(fù)
Intent intent = new Intent(HEART_BEAT_ACTION);
sendBroadcast(intent);
} else {
// 其他消息回復(fù)
Intent intent = new Intent(MESSAGE_ACTION);
intent.putExtra("message", message);
sendBroadcast(intent);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Activity:
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private Intent mServiceIntent;
private IBackService iBackService;
private TextView tv;
private EditText et;
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
initData();
}
private void initViews() {
tv = (TextView) findViewById(R.id.resule_text);
et = (EditText) findViewById(R.id.content_edit);
btn = (Button) findViewById(R.id.send);
}
private void initData() {
mServiceIntent = new Intent(this, BackService.class);
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String string = et.getText().toString().trim();
Log.i(TAG, string);
try {
Log.i(TAG, "是否為空:" + iBackService);
if (iBackService == null) {
Toast.makeText(getApplicationContext(),
"沒有連接,可能是服務(wù)器已斷開", Toast.LENGTH_SHORT).show();
} else {
boolean isSend = iBackService.sendMessage(string);
Toast.makeText(MainActivity.this,
isSend ? "success" : "fail", Toast.LENGTH_SHORT)
.show();
et.setText("");
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
@Override
protected void onStart() {
super.onStart();
bindService(mServiceIntent, conn, BIND_AUTO_CREATE);
// 開始服務(wù)
registerReceiver();
}
@Override
protected void onResume() {
super.onResume();
// 注冊廣播 最好在onResume中注冊
// registerReceiver();
}
@Override
protected void onPause() {
super.onPause();
// 注銷廣播 最好在onPause上注銷
unregisterReceiver(mReceiver);
// 注銷服務(wù)
unbindService(conn);
}
// 注冊廣播
private void registerReceiver() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BackService.HEART_BEAT_ACTION);
intentFilter.addAction(BackService.MESSAGE_ACTION);
registerReceiver(mReceiver, intentFilter);
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// 消息廣播
if (action.equals(BackService.MESSAGE_ACTION)) {
String stringExtra = intent.getStringExtra("message");
tv.setText(stringExtra);
} else if (action.equals(BackService.HEART_BEAT_ACTION)) {// 心跳廣播
tv.setText("正常心跳");
}
}
};
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// 未連接為空
iBackService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 已連接
iBackService = IBackService.Stub.asInterface(service);
}
};
}
aidl文件:
interface IBackService{
boolean sendMessage(String message);
}
首先我們必須知道,所有的推送功能必須有一個客戶端和服務(wù)器的長連接,因為推送是由服務(wù)器主動向客戶端發(fā)送消息,如果客戶端和服務(wù)器之間不存在一個長連接那么服務(wù)器是無法來主動連接客戶端的。因而推送功能都是基于長連接的基礎(chǔ)是上的。
IOS長連接是由系統(tǒng)來維護的,也就是說蘋果的IOS系統(tǒng)在系統(tǒng)級別維護了一個客戶端和蘋果服務(wù)器的長鏈接,IOS上的所有應(yīng)用上的推送都是先將消息推送到蘋果的服務(wù)器然后將蘋果服務(wù)器通過這個系統(tǒng)級別的長連接推送到手機終端上,這樣的的幾個好處為:
在手機終端始終只要維護一個長連接即可,而且由于這個長連接是系統(tǒng)級別的不會出現(xiàn)被殺死而無法推送的情況。
省電,不會出現(xiàn)每個應(yīng)用都各自維護一個自己的長連接。
安全,只有在蘋果注冊的開發(fā)者才能夠進行推送,等等。
android的長連接是由每個應(yīng)用各自維護的,但是google也推出了和蘋果技術(shù)架構(gòu)相似的推送框架,C2DM,云端推送功能,但是由于google的服務(wù)器不在中國境內(nèi),其他的原因你懂的。所以導(dǎo)致這個推送無法使用,android的開發(fā)者不得不自己去維護一個長鏈接,于是每個應(yīng)用如果都24小時在線,那么都得各自維護一個長連接,這種電量和流量的消耗是可想而知的。雖然國內(nèi)也出現(xiàn)了各種推送平臺,但是都無法達到只維護一個長連接這種消耗的級別。
以上就是關(guān)于“Java消息推送框架的代碼”介紹,大家如果想了解更多相關(guān)知識,可以關(guān)注一下動力節(jié)點的Java視頻教程,里面的課程內(nèi)容從入門到精通,細致全面,通俗易懂,很適合沒有基礎(chǔ)的小白學(xué)習,希望對大家能夠有所幫助。
相關(guān)閱讀
初級 202925
初級 203221
初級 202629
初級 203743