更新時間:2022-07-28 11:49:55 來源:動力節點 瀏覽1995次
大家在Java教程中會學到關于Java消息推送的知識,那么,Java消息推送框架的代碼是什么?動力節點小編來為大家解答。
(1)pull:輪詢,輪詢時間短:耗電,耗流量。時間長,不能保證消息及時。
輪詢:
Timer:WakeLock 讓CPU 保持喚醒,耗電量很大
AlarmManager:管理獨立的硬件時鐘RTC,可以在CPU休眠的時候正常運行。在預設的時間到達之后,喚醒CPU。這樣CPU可以正常休眠,只需要任務到達之后醒來一段很短的時間。極光推送就是基于此實現的。
(2)push:SMS、長連接。
(1)GCM:google的Gcm,容易被國內廠商閹割,而且NAT(Network AddressTranslation)容易超時,長連接無法保持,造成消息推送延遲。
(2)第三方推送:友盟、極光,騰訊信鴿
(3)自定義長連接:長連接、心跳和推送及時率。
保持長連接,是消息及時的重要保證。發送心跳包,如果前臺檢測發送失敗,則重新初始化一個socket。
一般我們這種socket幾乎是跟app的生命周期一樣長,甚至更長。不管在不在Service中去完成操作,我們都得開異步線程,雖然Service并不是異步操作,但是為了提升我們任務的優先級,我們最好是放在Service中,因為Service是由Android系統管理的,并且擁有比較高的優先級,線程是Java中的異步任務載體,可以說android系統不太認識線程。放在Service中可以很大程度上避免任務被回收或者關閉
BackSevice服務:
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();
}
// 發送心跳包
private Handler mHandler = new Handler();
private Runnable heartBeatRunnable = new Runnable() {
@Override
public void run() {
if (System.currentTimeMillis() - sendTime >= HEART_BEAT_RATE) {
boolean isSuccess = sendMsg("");// 就發送一個\r\n過去, 如果發送失敗,就重新初始化一個socket
if (!isSuccess) {
mHandler.removeCallbacks(heartBeatRunnable);
mReadThread.release();
releaseLastSocket(mSocket);
new InitSocketThread().start();
Log.d("ztf"," 發送失敗,就重新初始化一個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();// 每次發送成功數據,就改一下最后成功發送的時間,節省心跳間隔時間
Log.i(TAG, "發送成功的時間:" + 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);// 初始化成功后,就準備發送心跳包
}
// 釋放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, "收到服務器發送來的消息:"+message);
// 收到服務器過來的消息,就通過Broadcast發送出去
if (message.equals("ok")) {// 處理心跳回復
Intent intent = new Intent(HEART_BEAT_ACTION);
sendBroadcast(intent);
} else {
// 其他消息回復
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(),
"沒有連接,可能是服務器已斷開", 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);
// 開始服務
registerReceiver();
}
@Override
protected void onResume() {
super.onResume();
// 注冊廣播 最好在onResume中注冊
// registerReceiver();
}
@Override
protected void onPause() {
super.onPause();
// 注銷廣播 最好在onPause上注銷
unregisterReceiver(mReceiver);
// 注銷服務
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);
}
首先我們必須知道,所有的推送功能必須有一個客戶端和服務器的長連接,因為推送是由服務器主動向客戶端發送消息,如果客戶端和服務器之間不存在一個長連接那么服務器是無法來主動連接客戶端的。因而推送功能都是基于長連接的基礎是上的。
IOS長連接是由系統來維護的,也就是說蘋果的IOS系統在系統級別維護了一個客戶端和蘋果服務器的長鏈接,IOS上的所有應用上的推送都是先將消息推送到蘋果的服務器然后將蘋果服務器通過這個系統級別的長連接推送到手機終端上,這樣的的幾個好處為:
在手機終端始終只要維護一個長連接即可,而且由于這個長連接是系統級別的不會出現被殺死而無法推送的情況。
省電,不會出現每個應用都各自維護一個自己的長連接。
安全,只有在蘋果注冊的開發者才能夠進行推送,等等。
android的長連接是由每個應用各自維護的,但是google也推出了和蘋果技術架構相似的推送框架,C2DM,云端推送功能,但是由于google的服務器不在中國境內,其他的原因你懂的。所以導致這個推送無法使用,android的開發者不得不自己去維護一個長鏈接,于是每個應用如果都24小時在線,那么都得各自維護一個長連接,這種電量和流量的消耗是可想而知的。雖然國內也出現了各種推送平臺,但是都無法達到只維護一個長連接這種消耗的級別。
以上就是關于“Java消息推送框架的代碼”介紹,大家如果想了解更多相關知識,可以關注一下動力節點的Java視頻教程,里面的課程內容從入門到精通,細致全面,通俗易懂,很適合沒有基礎的小白學習,希望對大家能夠有所幫助。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習