一般我们这种socket几乎是跟app的生命周期一样长,甚至更长。不管在不在Service中去完成操作,我们都得开异步线程,虽然Service并不是异步操作,但是为了提升我们任务的优先级,我们最好是放在Service中,因为Service是由Android系统管理的,并且拥有比较高的优先级,线程是Java中的异步任务载体,可以说android系统不太认识线程。放在Service中可以很大程度上避免任务被回收或者关闭
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 WeakReferenceActivity: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); mReadThread = new ReadThread(socket); mReadThread.start(); mHandler.postDelayed(heartBeatRunnable, HEART_BEAT_RATE);// 初始化成功后,就准备发送心跳包 } // 释放socket private void releaseLastSocket(WeakReference 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 mWeakSocket; private boolean isStart = true; public ReadThread(Socket socket) { mWeakSocket = new WeakReference (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(); } } } } }
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小时在线,那么都得各自维护一个长连接,这种电量和流量的消耗是可想而知的。虽然国内也出现了各种推送平台,但是都无法达到只维护一个长连接这种消耗的级别。