Android Service Advanced

Introduction to this section

In the previous section, we learned about the life cycle of Service and two methods of starting Service. This section continues to learn more about IntentService in Service and the usage examples of Service: Implementation of foreground service and polling!


1. Use of IntentService

After the previous section, we already know how to define and start the Service, but if we directly put the time-consuming thread into the onStart() method in the Service, although we can do this, it will easily cause ANR exception (Application Not Responding), and Android's official introduction to Service has the following passage:

Direct translation:

1. Service is not a separate process, it is in the same process as its application
2. Service is not a thread, which means we should avoid time-consuming operations in Service

Ever since, Android provides us with an alternative to solve the above problems, which is the IntentService to be discussed below ; IntentService is a class that inherits from Service and handles asynchronous requests. In IntentService, there is a worker thread to handle time-consuming operations. Intent records will be added to the queue

work process:

The client starts the IntentService through startService(Intent); we do not need to manually control the IntentService, when the task is executed, the IntentService will automatically stop; the IntentService can be started multiple times, and each time-consuming operation will be in the IntentService in the form of a work queue It is executed in the onHandleIntent callback method, and only one worker thread will be executed each time, after one is executed, and then two are executed!

Then there is the code demonstration. Most of the codes on the Internet compare Service and IntentService, define a long enough sleep time, demonstrate the ANR exception of Service, and then lead out how good IntentService is! I won’t demonstrate Service here, all the ones on the Internet are Customize the Service, then Thread.sleep(20000) in the onStart() method and then trigger an ANR exception. If you are interested, you can try to write the code yourself. Here we only demonstrate the usage of IntentService!

TestService3.java

public class TestService3 extends IntentService {   
    private final String TAG = "hehe";   
    //Must implement the construction method of the parent class   
    public TestService3()   
    {   
        super("TestService3");   
    }   
  
    //The core method that must be rewritten   
    @Override   
    protected void onHandleIntent (Intent intent) {   
        //Intent is sent from the Activity, carries identification parameters, and performs different tasks according to different parameters   
        String action = intent.getExtras().getString("param");   
        ​​if(action.equals("s1 "))Log.i(TAG,"Start service1");   
        else if(action.equals("s2"))Log.i(TAG,"Start service2");   
        else if(action.equals("s3") )Log.i(TAG,  "Start service3"); 
          
        //Let the service sleep for 2 seconds    
        try{  
            Thread.sleep(2000);  
        }catch(InterruptedException e){e.printStackTrace();}           
    }   
  
    //Override other methods to view the calling order of methods   
    @Override   
    public IBinder onBind(Intent intent) {   
        Log.i(TAG,"onBind");   
        return super.onBind(intent);   
    }   
  
    @Override   
    public void onCreate() {   
        Log.i(TAG,"onCreate");   
        super.onCreate();   
    }   
  
    @Override   
    public int onStartCommand(Intent intent, int flags, int startId) {   
        Log.i(TAG,"onStartCommand");   
        return super.onStartCommand(intent, flags, startId);   
    }   
  
  
    @Override  
    public void setIntentRedelivery(boolean enabled) {  
        super.setIntentRedelivery(enabled);  
        Log.i(TAG,"setIntentRedelivery");  
    }  
      
    @Override  
    public void onDestroy() {  
        Log.i(TAG,"onDestroy");  
        super.onDestroy();  
    }  
      
} 

Register Service under AndroidManifest.xml

<service android:name=".TestService3" android:exported="false">  
    <intent-filter >  
        <action android:name="com.test.intentservice"/>  
    </intent-filter>  
</service>  

Start the service three times in MainActivity:

public class MainActivity extends Activity {  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
          
        Intent it1 = new Intent("com.test.intentservice");  
        Bundle b1 = new Bundle();  
        b1.putString("param", "s1");  
        it1.putExtras(b1);  
          
        Intent it2 = new Intent("com.test.intentservice");  
        Bundle b2 = new Bundle();  
        b2.putString("param", "s2");  
        it2.putExtras(b2);  
          
        Intent it3 = new Intent("com.test.intentservice");  
        Bundle b3 = new Bundle();  
        b3.putString("param", "s3");   
        it3.putExtras(b3);   
          
        //Then start multiple times of IntentService, each start will create a new worker thread   
        //But there is always only one IntentService instance   
        startService(it1);   
        startService(it2);   
        startService(it3);   
    }   
}

Run the screenshot:

summary:

When a background task needs to be divided into several subtasks, and then executed in sequence, the subtasks (simply speaking, asynchronous operations), at this time, if we still define a normal Service and open up a thread in the onStart method, and then go to It is very cumbersome to control the thread; at this time, you should customize an IntentService and then complete related tasks in the onHandleIntent() method!


2.Activity communicates with Service

Our previous operations are to start and stop the Service through the Activity. If we start a downloaded background Service, and we want to know the progress of the download task in the Service! Then this definitely requires Service and Activity to communicate, and the medium of communication between them is the onBind() method in Service! Return a custom Binder object!

The basic process is as follows:

  • 1. In the custom Service, customize a Binder class, and then write all the methods that need to be exposed into this class!
  • 2.In the Service class, instantiate the custom Binder class, and then rewrite the onBind() method to return the Binder object!
  • 3. Instantiate a ServiceConnection object in the Activity class, rewrite the onServiceConnected() method, then get the Binder object, and then call the relevant method!

3. Implementation of a simple foreground service

Now, we all know that Service generally runs later, but the system priority of Service is still relatively low. When the system memory is insufficient, it is possible to recycle the Service that is running in the background. In this case, we can Use the foreground service, so that the Service is not so easy to be killed by the system, of course it may still be killed... The so-called foreground service is the Notification displayed in the status bar!

It is also very simple to implement. The recent project just used this foreground service, so I took out the core code and shared it:

In the custom Service class, rewrite onCreate(), and then customize Notification according to your own needs; after customization, call startForeground(1, notification object)! The core code is as follows:

public void onCreate()
{
    super.onCreate();
    Notification.Builder localBuilder = new Notification.Builder(this);
    localBuilder.setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0));
    localBuilder.setAutoCancel(false);
    localBuilder.setSmallIcon(R.mipmap.ic_cow_icon);
    localBuilder.setTicker("Foreground Service Start");
    localBuilder.setContentTitle("Socket服务端");
    localBuilder.setContentText("正在运行...");
    startForeground(1, localBuilder.getNotification());
}

Screenshot of running effect:


4. Realization of simple timing background thread

In addition to the above-mentioned foreground services, there is another common usage of Service in actual development, which is to perform scheduled tasks, such as polling, which is to request the server every interval to confirm the status of the client or update information, etc.! And Android provides us with two timing methods using the Timer class and the Alarm mechanism!

The former is not suitable for timing tasks that need to run in the background for a long time. Once the CPU sleeps, the timing tasks in the Timer cannot run; Alarm does not exist in this situation. It has the function of waking up the CPU. In addition, it is necessary to distinguish between CPU wakeup and screen wake!

manual:

  • Step 1:获得Service: AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
  • Step 2: Set the timing task through the set method  int anHour = 2 * 1000; long triggerAtTime = SystemClock.elapsedRealtime() + anHour; manager.set(AlarmManager.RTC_WAKEUP,triggerAtTime,pendingIntent);
  • Step 3: Define a Service  to open a transaction thread in onStartCommand to handle some timing logic
  • Step 4: Define a Broadcast (broadcast) to start the Service  Finally, don't forget to register the Service and Broadcast in AndroidManifest.xml!

Detailed parameter explanation:  set(int type,long startTime,PendingIntent pi)

①type:  There are five optional values:
AlarmManager.ELAPSED_REALTIME:  The alarm clock is not available in the sleep state of the mobile phone. In this state, the alarm clock uses relative time (relative to the start of the system), and the state value is 3;
AlarmManager.ELAPSED_REALTIME_WAKEUP  alarm clock is in the sleep state It will wake up the system and execute the reminder function. In this state, the alarm clock also uses relative time, and the state value is 2;
AlarmManager.RTC  alarm clock is not available in the sleep state. In this state, the alarm clock uses absolute time, that is, the current system time, and the state value is 1 ;
AlarmManager.RTC_WAKEUP  indicates that the alarm clock will wake up the system and execute the reminder function in the sleep state. In this state, the alarm clock uses absolute time, and the status value is 0;
AlarmManager.POWER_OFF_WAKEUP  indicates that the alarm clock can also perform the reminder function normally when the mobile phone is turned off, so it is One of the most used states among the 5 states. In this state, the alarm clock also uses absolute time, and the state value is 4; however, this state seems to be affected by the SDK version, and some versions do not support it;

PS: The first parameter determines the type of the second parameter. If it is REALTIME, use: SystemClock.elapsedRealtime( ) method to get the number of milliseconds since the system was started. If it is RTC, use: System.currentTimeMillis() Get the number of milliseconds from 1970.1.1 0 o'clock to the present

②startTime:  The first execution time of the alarm clock, in milliseconds, you can customize the time, but generally use the current time. It should be noted that this attribute is closely related to the first attribute (type). If the alarm clock corresponding to the first parameter uses relative time ( ELAPSED_REALTIME and ELAPSED_REALTIME_WAKEUP ), then this attribute must use relative time (relative to the system startup time), for example, the current time is expressed as: SystemClock.elapsedRealtime(); if the alarm clock corresponding to the first parameter uses absolute time (RTC, RTC_WAKEUP, POWER_OFF_WAKEUP), then this property must use absolute time, such as the current The time is expressed as: System.currentTimeMillis().

③PendingIntent:  Binding the execution actions of the alarm clock, such as sending a broadcast, giving reminders, and so on. PendingIntent is the encapsulation class of Intent.
It should be noted that if the alarm clock prompt is realized by starting the service, the Pending.getService (Context c,int i,Intent intent,int j) method should be used to obtain the PendingIntent object; if the alarm clock prompt is realized through
broadcasting , the PendingIntent object should be acquired using the PendingIntent.getBroadcast (Context c,int i,Intent intent,int j) method;
if the alarm clock reminder is implemented in the form of Activity, the PendingIntent object should be acquired using the PendingIntent.getActivity(Context c,int i,Intent intent,int j) method.
If these three methods are used incorrectly, although no error will be reported, the alarm clock prompt effect will not be seen.

in addition:

After version 4.4 (API 19), the triggering time of the Alarm task may become inaccurate and may be delayed. This is the system's optimization of power consumption. If you need to be accurate, you can call the setExtra() method~

Core code:

public class LongRunningService extends Service { 
    @Override 
    public IBinder onBind(Intent intent) { 
        return null; 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
        // Create a thread here to perform specific logical operations : 
        new Thread(new Runnable() { 
            @Override 
            public void run() { 
                Log.d("BackService", new Date().toString()); 
            } 
        }).start(); 
        AlarmManager manager = (AlarmManager) getSystemService (ALARM_SERVICE); 
        //This is timing, here is set to print the time every two seconds =-=, change  
        int anHour = 2 * 1000;
        long triggerAtTime = SystemClock.elapsedRealtime() + anHour;
        Intent i = new Intent(this,AlarmReceiver.class);
        PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);
        manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
        return super.onStartCommand(intent, flags, startId);
    }
}

AlarmReceiver.java

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Intent i = new Intent(context,LongRunningService.class);
        context.startService(i);
    }
}

Guess you like

Origin blog.csdn.net/leyang0910/article/details/131291598