Service advanced
Introduction to this section
In the previous section we learned about the life cycle of Service and the two methods of starting Service. This section continues to have an in-depth understanding of IntentService in Service and 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 Service, but if we directly Put the time-consuming thread in the onStart() method in the Service. Although you can do this, it is very easy. It will cause ANR exception (Application Not Responding), and Android official introduced 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 that we should avoid performing time-consuming operations in Service
So, Android provides us with alternatives to solve the above problems, which is what we will talk about belowIntentService; IntentService is a class that inherits Service and handles asynchronous requests. There are A worker thread handles time-consuming operations, and the requested Intent record will be added to the queue
Workflow:
The client starts the IntentService through startService(Intent) ; We do not need to manually control the IntentService. When the task is completed, the IntentService will automatically stop; IntentService can be started multiple times, and each time-consuming operation will be processed 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 at a time. After executing the first one, and then the second one!
Then follows 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 the Service, and then lead to how good the IntentService is! I won’t demonstrate the Service here. The ones on the Internet are all customized Services, and then in the onStart() method Thread.sleep(20000) then triggers an ANR exception. If you are interested, you can try to write the code yourself. Here I only demonstrate the usage of IntentService!
TestService3.java
private final String TAG = "hehe";
//The constructor of the parent class must be implemented
public TestService3()
{
Super ("TestService3");
}
// The core method that must be rewritten
@Override
Protected void Onhandleintent (INTENT Intent) {
// Intent is from Activity Sent, 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, "onBind"); 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();
}
}
AndroidManifest.xml注册下Service
<intent-filter >
<action android:name="com.test.intentservice"/>
</intent-filter>
</service>
在MainActivity启动三次服务:
@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);
//接着启动多次IntentService,每次启动,都会新建一个工作线程
//但始终只有一个IntentService实例
startService(it1);
startService(it2);
startService(it3);
}
}
Run screenshot:
##Summary:
When a background task needs to be divided into several subtasks, and then executed in sequence, the subtasks (Simply put, it is an asynchronous operation). At this time, if we still define a normal Service and then It is very cumbersome to open a thread in the onStart method and then control the thread; At this time, you should customize an IntentService and complete related tasks in the onHandleIntent() method!
2.Activity communicates with ServiceOur previous operations are to start and stop Service through Activity. If we start a download The background Service, and we want to know the progress of the download task in the Service! Then this definitely requires Service Communicate with Activity, 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 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 this custom Binder class, then rewrite the onBind() method to return this Binder object! 3. Instantiate a ServiceConnection object in the Activity class, override the onServiceConnected() method, and then
Get the Binder object and then call the relevant method!
3. Implementation of a simple front-end service After learning now, we all know that Service generally runs later, but the system priority of Service It is still relatively low. When the system memory is insufficient, it is possible to recycle the Service running in the background. For this situation, we can use a foreground service to make the Service slightly less likely to be killed by the system. Of course, it is still possible to 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 happened to use this front-end service, so I dug out the core code. Share: In the custom Service class, rewrite onCreate(), and then customize Notification according to your own needs; After customization, just call startForeground(1, notification object)!
The core code is as follows:
{
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. Implementation of simple scheduled background threadIn addition to the above-mentioned front-end services, there is another common usage of Service in actual development, which is to execute scheduled tasks. For example, polling means requesting the server every once in a while to confirm the client status or update information. wait! There are two timing methods provided to us in Android, using the Timer class and the Alarm mechanism!
The former is not suitable for scheduled tasks that need to run in the background for a long time. Once the CPU goes to sleep, the scheduled tasks in Timer It cannot run; Alarm does not have this situation. It has the function of waking up the CPU. In addition, the CPU must also be distinguished. Wake up with screen wake up!
Usage process:
- Step 1: Get Service:AlarmManager manager = (AlarmManager) getSystemService( ALARM_SERVICE);
- Step 2: Set the scheduled task through the set methodint anHour = 2 * 1000; long triggerAtTime = SystemClock.elapsedRealtime() + anHour; manager.set(AlarmManager.RTC_WAKEUP,triggerAtTime,pendingIntent);
- Step 3: Define a ServiceOpen a transaction thread in onStartCommand to process some timing logic
- Step 4: Define a Broadcast (broadcast) for starting the ServiceFinally, don’t forget to register this Service and Boradcast in AndroidManifest.xml!
Detailed explanation of parameters: set(int type,long startTime,PendingIntent pi)
PS: The first parameter determines the second parameter Type, if it is REALTIME, use: The SystemClock.elapsedRealtime() method can obtain the number of milliseconds that have elapsed since the system was started. If it is RTC, use: System.currentTimeMillis() to get the time from 1970.1.1 0 to Number of milliseconds elapsed now① type: has five optional values:
AlarmManager.ELAPSED_REALTIME:The alarm clock is not available when the phone is in sleep state. In this state, the alarm clock uses relative time (relative to the start of system startup), status The value is 3;
AlarmManager.ELAPSED_REALTIME_WAKEUPThe alarm clock will wake up the system and perform prompt functions in the sleep state. In this state, the alarm clock also uses relative time, and the status value is 2;
AlarmManager .RTCThe 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 status value is 1;
AlarmManager.RTC_WAKEUP means that the alarm clock will be in the sleep state. Wake up the system and perform the prompt function. In this state, the alarm clock uses absolute time and the status value is 0;
AlarmManager.POWER_OFF_WAKEUP means that the alarm clock can also perform the prompt function normally when the phone is turned off, so there are 5 One of the most commonly used states among 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;
②startTime: The first execution time of the alarm clock, in milliseconds, the time can be customized, but the current time is generally used. It should be noted that this attribute is closely related to the first attribute (type). If the alarm clock corresponding to the first parameter Relative time is used (ELAPSED_REALTIME and ELAPSED_REALTIME_WAKEUP), then this property You have to 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 attribute must use absolute time. For example, the current time is expressed as: System.currentTimeMillis().
③PendingIntent:Binds the execution action of the alarm clock, such as sending a broadcast, giving a prompt, etc. PendingIntent It is the encapsulation class of Intent.
It should be noted that if the alarm prompt is implemented by starting the service, To obtain the PendingIntent object, Pending.getService should be used (Context c, int i, Intent intent, int j) method;
If the alarm reminder is implemented through broadcasting, To obtain the PendingIntent object, PendingIntent.getBroadcast should be used (Context c, int i, Intent intent, int j) method;
If the Activity method is used to implement the alarm clock prompt, the acquisition of the PendingIntent object You should use 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 prompt effect will not be visible.
In addition:
From version 4.4 (API 19), the trigger time of the Alarm task may become inaccurate and may be delayed. Yes system For optimization of power consumption, if you need to be accurate, you can call the setExtra() method~
Core code:
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand (INTENT Intent, Int Flags, Int Startid) {
// Here is used to perform specific logic operations:
New Thread (New Runnable () {
@Override
## public void run () {
Log.d ("Backservice", new date (). Tostring ());
}
}). Start ();
Alarmmanager Manager = (AlarmManager) getSystemService(ALARM_SERVICE);
//This is timed, the setting here is to print the time every two seconds =-=, change it yourself
. 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);
}
Summary of this section:
In this section we continue to learn more about Service, IntentService and Service Two common cases in actual development: implementation of front-end Service, and Service background The realization of Service! In the next section, we will continue to study Service's AIDL and cross-process communication. Please stay tuned ~
Reference: "The First Line of Code Android" - Guo Lin: A very good introductory book to Android!