Android Instant Message Processing Mechanism

Source: Internet
Author: User

Android Instant Message Processing Mechanism
How to ensure instant messaging without consuming power when making instant messages on android. Why? The reason is that to ensure the instant messaging, there are usually two mechanisms pull or push. The pull regular polling mechanism is a waste of server resources. The push server needs to maintain persistent connections, and both the client and server have high requirements (network environment, number of server connections, etc ), their detailed advantages and disadvantages are not described. Both of the above mechanisms require the client to be active for a long time on the premise that the cpu is in the wake-up state, while the android end has a sleep mechanism to ensure that the mobile phone is in sleep for most of the time, reducing power consumption, extend the host time. After the mobile phone is sleep, the thread processes the pause State. In this way, the two methods described above are all paused, resulting in failure to receive messages after sleep. Some people may say that there is a wake-up mechanism on the mobile phone. If the wake-up mechanism persists, the software will consume a lot of power, and the power of the mobile phone will not be exhausted in a day. Think about the half grid of electricity before going to bed, in the morning, the battery power was shut down, and the depressed mood suddenly emerged. Therefore, this operation would not work and would directly cause the software to be uninstalled. What should I do if there is a conflict between real-time and power consumption? The solution is to balance and ensure the real-time performance while minimizing power consumption. I. Wake-up mechanism the mobile phone has a sleep mechanism, which also provides a wake-up mechanism, so that we can wake up our program to continue working while sleeping. There are two types of wake-up: AlarmManager and WakeLock: The alarm mechanism of the AlarmManager mobile phone. The clock mechanism is different, so that sleep can also be timed accurately and wake up the program. The specific usage will not be mentioned, alarmManager can wake up the cpu and program, but its wake-up time only ensures that the intent object receiving method it wakes up is executed completely. It does not guarantee that other asynchronous processing is called in the method, therefore, it usually takes a short time to wake up. If you want to ensure that everything outside of the asynchronous mode is complete, you have to apply for WakeLock to ensure that the mobile phone is not sleeping. Otherwise, if you do half of the work, the mobile phone will sleep. Here we use the combination of AlarmManager and WakeLock to put the received messages in asynchronous mode. Let's look at the details later. Let's talk about the wake-up cycle of the alarm. To ensure instant messaging, the shorter the message, the better. But to ensure power saving, it cannot be too frequent. Policy 1: Water Wave policies can be used to reset the alarm: Intensive scheduling is started and the traffic increases gradually. For example, starting from 30 seconds, increasing every 5 seconds until 25 minutes is fixed. Policy 2: You can adopt the idle-time and busy-time strategy. The busy-time periods are busy during the day, and the time periods are intensive. Policy 3: Adjust the alert policy to ensure that messages are received in real time. When a message is received, the alert time will be re-initialized, starting from the shortest cycle to ensure that the chat status is in real time. Policy 4. Wake-Up With WakeLock: Check whether the screen of the mobile phone is on, determine whether to obtain the wake-up lock, and reduce the number of wake-up times. 1. set an alarm.

am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, (triggerAtTime + time), pi);
2. Alarm Time Optimization
Public class AlarmTime {public static final AtomicLong alarmTime = new AtomicLong (0);/*** initialize the alarm time, reconnect to the system, or initialize the received message */public static long initAlarmTime () {alarmTime. set (Global. ALARM_TRIGGER_TIME); return alarmTime. get ();}/*** optimized the alert time. The number of reconnection errors exceeds a certain number of times. optimized the alert time and then tried to reconnect to the error count * 10 minutes, 30 seconds, 30 seconds,; number of arrived errors, 10 minutes; * @ return */public static long optimizeAlarmTime () {alarmTime. set (Global. ALARM_TRIGGER_OPTIMIZE_TIME); // return alarmTime in 10 minutes. get ();} public static long incrementTime () {long time = alarmTime. get (); if (time = 0) return alarmTime. addAndGet (Global. ALARM_TRIGGER_TIME); // else if (time
 
  
3. Wake-Up Mechanism
  
Public final class IMWakeLock {private static final String TAG = IMWakeLock. class. getSimpleName (); private WakeLock wakeLock = null; private String tag = ""; private PowerManager pm; public IMWakeLock (Context paramContext, String tag) {this. tag = tag; pm = (PowerManager) paramContext. getSystemService (Context. POWER_SERVICE); wakeLock = pm. newWakeLock (PowerManager. PARTIAL_WAKE_LOCK, tag);}/*** get Power lock to keep the Service Running */public synchronized void acquireWakeLock () {if (! Pm. isScreenOn () {if (null! = WakeLock &&! WakeLock. isHeld () {ImLog. d (TAG, tag + "==> get sleep lock"); wakeLock. acquire () ;}}/ *** release device power lock */public synchronized void releaseWakeLock () {if (null! = WakeLock & wakeLock. isHeld () {ImLog. d (TAG, tag + "==> release wake-up sleep lock"); wakeLock. release () ;}} public synchronized void finalize () {if (null! = WakeLock & wakeLock. isHeld () {ImLog. d (TAG, tag + "==> release wake-up sleep lock"); wakeLock. release () ;} wakeLock = null;} public boolean isScreenOn () {return pm. isScreenOn ();}}
4. wakeup time
Private void startApNotify () {if (this. sessionID = 0 | this. ticket = null) return; if (wakeLock. isScreenOn () {ImLog. d (TAG, "NotifyService ==> start empty request"); apNotifyThread = new ApNotifyThread (this, false);} else {wakeLock. acquireWakeLock (); apNotifyThread = new ApNotifyThread (this, true);} exec = Executors. newSingleThreadExecutor (); exec.exe cute (apNotifyThread); exec. shutdown ();}

The wake-up mechanism is ready, but it won't work if the wake-up lock is not released for a long time after the wake-up, so we have to consider the message receiving mechanism here.
2. Why are push and pull combined to receive messages? Let's take a look at the feature push: instant, persistent connection, and time-consuming. Pull: passive, persistent connection, and short processing time. Based on the wake-up and sleep mechanisms of the mobile phone, we can find that push is suitable for the phone when it is in sleep state, and does not sleep, so it maintains a persistent connection and ensures that messages are received instantly. Pull is suitable for phone sleep status (sleep status cannot be determined, but can only be determined based on whether the screen is on or not, and the curve saves the country). That is, after sleep, wake up with the wake-up mechanism, and there is no message under pull, no message release sleep lock. If a message is received, the sleep lock is released after the message is collected to minimize the wake-up time and reduce power consumption. Push logic flowchart: pull logic flowchart:
Code processing:
Public class ApNotifyThread extends Thread {private static final String TAG = ApNotifyThread. class. getSimpleName (); protected volatile boolean isRunning = false; protected volatile APHold. client client; protected volatile effecthc; protected volatile TProtocol; protected volatile long sessionID; protected volatile String ticket; protected final long ERRORNUM = 15; protected policyser Vice service; protected boolean isOld = false; protected boolean isDoShortRequest = false; public ApNotifyThread (policyservice service, boolean isDoShortRequest) {this. sessionID = service. getSessionID (); this. ticket = service. getTicket (); this. service = service; this. isDoShortRequest = isDoShortRequest;} @ Override public void run () {ImLog. d (TAG, "ApNotifyThread ==> empty request starts to process threadID =" + Thread. currentThread (). g EtId (); this. isRunning = true; if (this. isDoShortRequest) {if (shortEmptyRequest () & this. isRunning) longEmptyRequest (); // enable the long and empty request} else {longEmptyRequest ();} ImLog. d (TAG, "ApNotifyThread ==>" + (this. isOld? "Previous": "") + "null request to terminate threadID =" + Thread. currentThread (). getId (); this. isRunning = false;}/*** initialization * @ param isLongTimeOut * @ throws Exception */private void init (boolean isLongTimeOut) throws Exception {thc = policyhttpclientutil. getVRVTHttpClient (isLongTimeOut); protocol = new TBinaryProtocol (thc);}/*** long blank Request */private void longEmptyRequest () {try {this. init (true); client = new APHold. client (protoco L); for (;) {if (! NetStatusUtil. havActiveNet (IMApp. getApp () {ImLog. d (TAG, "longEmptyRequest ===> no available network"); break;} try {if (! HandleMessage () break;} catch (TException e) {if (! This. isRunning) break; ImLog. d (TAG, "longEmptyRequest ==> sending request exception:" + e. getMessage (); if (exceptionHandler (e) {throw new IMException ("too many connection failures", MessageCode. IM_EXCEPTION_CONNECT);} continue;} ImLog. d (TAG, "longEmptyRequest ==>" + (this. isOld? "Previous": "") + "normal exit of empty request");} catch (Exception e) {ImLog. d (TAG, "longEmptyRequest ==>" + (this. isOld? "Previous": "") + "null request exited abnormally" + e. getMessage (); if (exceptionHandler (e) {// call to reconnect ImLog. d (TAG, "longEmptyRequest ==> call reconnection"); this. service. getDataSyncer (). setValue (UserProfile. RECONNECT, "0") ;}} finally {close () ;}/ *** short and empty Request * @ return */private boolean shortEmptyRequest () {boolean isDoLongRequest = true; try {long messageNum = 0; if (! NetStatusUtil. havActiveNet (IMApp. getApp () {ImLog. d (TAG, "shortEmptyRequest ==> no available network"); return false;} this. init (false); // get the number of messages APService. client apclient = new APService. client (protocol); this. service. getDataSyncer (). setValue (UserProfile. LASTREQUESTTIME, String. valueOf (SystemClock. elapsedRealtime (); ImLog. d (TAG, "shortEmptyRequest ==> policyid:" + policyid. policyid. get (); messageNum = apclien T. getpolicymsgsize (sessionID, ticket, policyid. policyid. get (); policyerror. policyerrornum. set (0); ImLog. d (TAG, "shortEmptyRequest ==> get the number of messages:" + messageNum); if (messageNum =-1) throw new IMException ("session failure", MessageCode. IM_BIZTIPS_SESSIONINVAILD); // if a message is received, if (messageNum> 0 & this. isRunning) {long receiveMessageNum = 0; client = new APHold. client (protocol); for (;) {if (! NetStatusUtil. havActiveNet (IMApp. getApp () {ImLog. d (TAG, "shortEmptyRequest ==> no available network"); break;} if (! HandleMessage () break; receiveMessageNum ++; if (receiveMessageNum = messageNum) // exit break after receiving the short connection;} ImLog. d (TAG, "shortEmptyRequest ==>" + (this. isOld? "Previous": "") + "normal exit of empty request");} catch (Exception e) {ImLog. d (TAG, "shortEmptyRequest ==>" + (this. isOld? "Previous": "") + "null request exited abnormally" + e. getMessage (); if (exceptionHandler (e) {isDoLongRequest = false; // call to reconnect ImLog. d (TAG, "shortEmptyRequest ==> call reconnection"); this. service. getDataSyncer (). setValue (UserProfile. RECONNECT, "0") ;}} finally {close (); this. service. releaseWakeLock ();} return isDoLongRequest;}/*** Exception handling to determine whether to reconnect * @ param e * @ return */private boolean exceptionHandler (Exception e) {boolean isReconnect = false; If (e instanceof IMException) {isReconnect = true;} else if (! (E instanceof SocketTimeoutException )&&! (E instanceof NoHttpResponseException) {policyerror. policyerrornum. incrementAndGet (); if (policyerror. policyerrornum. get ()> this. ERRORNUM) {isReconnect = true; policyerror. policyerrornum. set (0) ;}} else policyerror. policyerrornum. set (0); e. printStackTrace (); return isReconnect;}/*** empty request to send and receive data processing * @ throws TException */private boolean handleMessage () throws TException {if (! This. isRunning) return false; ImLog. d (TAG, "handleMessage ==> sessionID" + sessionID); SendEmptyRequestReq req = new SendEmptyRequestReq (); req. setSessionID (sessionID); req. setTicket (ticket); req. setpolicyid (policyid. policyid. get (); ImLog. d (TAG, "handleMessage ==> start of an empty request cycle"); this. service. getDataSyncer (). setValue (UserProfile. LASTREQUESTTIME, String. valueOf (SystemClock. elapsedRealtime (); clien T. SendEmptyRequest (req); policyerror. policyerrornum. set (0); if (! This. isRunning) return false; APNotifyImpl iface = new APNotifyImpl (); APNotify. Processor
   
    
Processor = new APNotify. Processor
    
     
(Iface); boolean isStop = false; while (! IsStop) {try {ImLog. d (TAG, "handleMessage ==> enter receive data processing"); while (processor. process (protocol, protocol) = true) {isStop = true; break;} ImLog. d (TAG, "handleMessage ==> end receiving data processing");} catch (TException e) {ImLog. d (TAG, "handleMessage ==> receive data processing exceptions"); isStop = true ;}} ImLog. d (TAG, "handleMessage ==> end of an empty request cycle"); if (! Iface. isSessionVaild) {// The background reports that the session is invalid this. service. setSessionID (0); this. service. setTicket (null); return false;} // reset the alarm this. service. getDataSyncer (). setValue (UserProfile. ALARM_TTIME, "0"); return true;}/*** close connection */private void close () {synchronized (this) {if (thc! = Null) {thc. shutdown (); thc. close (); thc = null ;}} if (client! = Null & client. getInputProtocol ()! = Null) {client. getInputProtocol (). getTransport (). close (); client. getOutputProtocol (). getTransport (). close () ;}/ *** thread interrupt */public void interrupt () {this. isRunning = false; this. isOld = true; close (); super. interrupt ();}/*** determine whether the task is running */public boolean isRunning () {return isRunning ;}
    
   


According to the above analysis and optimization, the android side receives instant messages, and the rest is to adjust the wake-up alarm cycle to balance the instant messaging and power consumption problems.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.