1 Diagram Interpreting Service
Here is a diagram of life cycle: basic concepts & interpretation of critical callback methods
2. Interpretation of Service Class Relationships
The inheritance diagram for the parent and child classes of the Service class is as follows:
3 Configure Service
Both Service and Active are android system components, which need to be in android Manifest. The XML configuration file declares otherwise the service will not be recognized or executed by the system. A simple service component is as follows:
<service android:name=".FirstService"> </service>
Common attributes are name, export (whether to be allowed to be called by other applications), permission (the privilege required to start a service), process (the process in which the service is located, default is in the APP process, but other processes can be specified), and label attributes are not required (because there is no interface). If the intent-filter option is not set, the Intent cannot be directly responded to, but can only be started by specifying the Intent of the Component.
4 Service Operation
4.1 Service Start/Stop
The key API s for starting and stopping services are as follows:
//Define Intent, carry service Intent intent = new Intent(MainActivity.this,com.ags.XXXService.class); //Start Services startService(intent); //Out of Service stopService(intent);
About service:
- The onCreate callback function executes once and the onStartCommand callback function executes more than once after the service has been started several times in a row.
- The API used to start/stop a service does not have the ability to exchange/communicate data with the original caller. To be able to communicate, you need to bind the service.
Note: Starting with android 5.0, Google requires that service components must be started using explicit Intent.
4.2 Bind Service s and communicate
If the service wants to communicate and exchange data with the initiator, the service should be started/closed using the bindService() and unbindService() methods. Here is an example of the bindService and unbindService methods. Two keys are set here, one binds the service and calls the service component's method addNum after the binding is successful. Another unbound service.
First, write a custom service inheriting system service named BinderService, which is implemented as follows:
public class BinderService extends Service { private static String TAG = "BinderService"; public class AgsBinder extends Binder { public BinderService getService(){ return BinderService.this; } } //Communication between caller and service via binder private AgsBinder binder = new AgsBinder(); @Nullable @Override public IBinder onBind(Intent intent) { Log.d(TAG, "onBind"); return binder; } @Override public boolean onUnbind(Intent intent) { Log.d(TAG, "onUnBind"); return super.onUnbind(intent); } @Override public void onCreate() { super.onCreate(); Log.d(TAG, "onCreate"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand"); return super.onStartCommand(intent, flags, startId); } /**Parametric Interpretation: *service: Specify the service to start through intent * conn: Listen for callback processing for successful/failed connections between visitors and service s * flags: Whether to automatically create a service */ @Override public boolean bindService(Intent service, ServiceConnection conn, int flags) { Log.d(TAG, "bindService"); return super.bindService(service, conn, flags); } @Override public void unbindService(ServiceConnection conn) { super.unbindService(conn); Log.d(TAG, "unbindService"); } @Override public void onDestroy() { Log.d(TAG, "onDestroy"); super.onDestroy(); } public int addNum(int a,int b){ Log.d(TAG, "addNum: "+(a+b)); return a+b; } }
Second, the MainActivity code is implemented as follows:
public class MainActivity extends AppCompatActivity { private static String TAG = "MainActivity"; private Button btn_bind; private Button btn_unbind; private BinderService binderservice = null; private boolean isBound = false; private ServiceConnection connection = new ServiceConnection() { @Override //Connection Successful Callback public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, "onServiceConnected"); isBound = true; BinderService.AgsBinder binder = (BinderService.AgsBinder)service; binderservice = binder.getService(); Log.d(TAG, "Activity onServiceConnected"); //Once the connection is successful, you can call various methods of the binderservice. int x = binderservice.addNum(3,4); Log.d(TAG, "Activity call binderservice.addNum:"+x); } @Override //Unexpected callback occurs, unbind does not cause callback public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "onServiceDisconnected"); isBound = false; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_bind = findViewById(R.id.btn_bind); btn_unbind = findViewById(R.id.btn_unbind); btn_bind.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, com.ags.myapplication.BinderService.class); //intent.putExtra("from", "MainActivity"); Log.d(TAG, "onClick:bindService"); //Start and bind the service bindService(intent,connection,BIND_AUTO_CREATE); } }); btn_unbind.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(isBound){ Log.d(TAG, "onClick:unbindService"); //Unbind service unbindService(connection); isBound = false; } } }); } }
Note: onServiceDisconnected will not be invoked when the end and Service unbundling are enabled. The onServiceDisconnected call occurs when the enabled end and Service connection are unexpectedly lost, at which point it is determined that the enabled end and Service must be disconnected.
5 IntentService
The problem with a service is that it is in the same process as the application and cannot directly handle time-consuming tasks in the service. To solve this problem, you need to use IntentService, which has the following advantages:
- A separate worker thread is created to process all Intent requests and code for the onHandleIntent method implementation.
- Automatically stop when request processing is complete without stopSelf method.
- Simply implement the onHandleIntent method to start the service to perform time-consuming work in the background.
Here is an example of how time-consuming tasks are handled. The intentService code for time-consuming tasks is implemented as follows:
public class SecondService extends IntentService { private static String TAG = "IntentService"; public SecondService() { super("SecondService"); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } //This method allows time-consuming functions to be executed without blocking the UI main thread @Override protected void onHandleIntent(@Nullable Intent intent) { Log.d(TAG, "onHandleIntent: Start Task"); synchronized (this){ try { wait(20*1000); } catch (InterruptedException e) { e.printStackTrace(); } } Log.d(TAG, "onHandleIntent: End Task"); } }
The MainActivity code is as follows:
public class MainActivity extends AppCompatActivity { private static String TAG = "MainActivity"; private Button btn_start; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_start = findViewById(R.id.btn_start); btn_start.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //Start as normal service. Intent intent = new Intent(MainActivity.this, com.ags.myapplication.SecondService.class); startService(intent); } }); } }
Since IntentService uses a separate worker thread, the UI main thread is not blocked.
6 Cross-process AIDL Service
Introduction to 6.1 aidl
Key Word Interpretation:
- IPC (Inter-Process Communication): Cross-process communication for data exchange between processes.
- AIDL (android interface definition language): The Android interface definition language is used to allow a Service to communicate across processes with multiple application components, thereby enabling multiple applications to share the same Service.
AIDL's purpose is to define a remote interface, that is, to define a communication interface between two processes.
Why do I need AIDL? Implementing cross-process requires a lot of complex code to be written, so android provides AIDL. By writing simple AIDL files, the compiler generates complex code based on AIDL rules, simplifying complexity is essential.
6.2 Interface Rules and Compilation
The data types supported by the Aidl interface file (.aidl is a suffix) are as follows:
- Basic data types byte, char, short, int, long, float, double, boolean (default tag is in)
- String, CharSequence (default tag is in)
- Implement the data type of the Parcelable interface (import is required)
- List type (content must be of type supported by AIDL, or an interface declared by other AIDL, requires import)
- Map type (content must be an AIDL-supported type, or an interface to other AIDL declarations, requires import)
About directed tags: A directed tag in AIDL represents the direction of data flow in cross-process communication:
- in indicates that data can only flow from the client to the server. It can be understood as client input and server output.
- out means that data can only flow from the server to the client. It can be understood as server-side input and client-side output.
- inout indicates that data can flow in both directions between the server and the client. Client/server can input/output.
Next, simply create a new aidl file, which reads as follows:
// IMyAidlInterface.aidl package com.ags.myservice; interface IMyAidlInterface { void testMethod1(String str); void testMethod2(int id); }
Compile to generate IMyAidlInterface after making project. Java file.
6.3 Use of Aidl
There are two things to look at here: client (getting and using services) and service (implementing and providing services):
- Key steps on the service side: Set up and define the aidl file - > Implement Interface Method and Lifecycle Method - > In AndroidMainfest. Register service in XML file & declare as remote service.
- Client-side key steps: Copy the server-side AIDL file to the client directory - > Bind the specified Service through Intent - > Use Stub. The asInterface interface gets the Service-side Binder and calls the interface method provided by the Service.
The case is as follows:
@1 Server-side Service:
Here, create an aidl file that directly copies the above as follows:
// IMyAidlInterface.aidl package com.ags.myservice; interface IMyAidlInterface { void testMethod1(String str); void testMethod2(int id); }
After compilation, the IMyAidlInterface is generated. Java. There's a lot of content here, just the framework section, as shown below:
package com.ags.myservice; public interface IMyAidlInterface extends android.os.IInterface { public static class Default implements com.ags.myservice.IMyAidlInterface { //... @Override public android.os.IBinder asBinder() { return null; } } public static abstract class Stub extends android.os.Binder implements com.ags.myservice.IMyAidlInterface { private static final java.lang.String DESCRIPTOR = "com.ags.myservice.IMyAidlInterface"; public Stub() { this.attachInterface(this, DESCRIPTOR); } public static com.ags.myservice.IMyAidlInterface asInterface(android.os.IBinder obj) { //... } @Override public android.os.IBinder asBinder() { return this; } @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { //... } private static class Proxy implements com.ags.myservice.IMyAidlInterface { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } //... public static com.ags.myservice.IMyAidlInterface sDefaultImpl; } static final int TRANSACTION_testMethod1 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_testMethod2 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); //... public static com.ags.myservice.IMyAidlInterface getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } } public void testMethod1(java.lang.String str) throws android.os.RemoteException; public void testMethod2(int id) throws android.os.RemoteException; }
With the IMyAidlInterface class, we create a Service that implements the methods in the aidl, as follows:
public class TestAIDLService extends Service { private static String TAG = "TestAIDLService"; //Instantiate the tub class of AIDL (the Binder subclass) to implement the method in Aidl IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub(){ @Override public void testMethod1(String str) throws RemoteException { Log.d(TAG, "service Impl:testMethod1:exec"); } @Override public void testMethod2(int id) throws RemoteException { Log.d(TAG, "service Impl:testMethod1:exec"); } }; //life cycle functions @Override public void onCreate() { Log.d(TAG, "onCreate: exec"); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand: exec"); return super.onStartCommand(intent, flags, startId); } @Nullable @Override public IBinder onBind(Intent intent) { Log.d(TAG, "onBind: exec"); //Returns a Binder of the tub type inherited from Binder return mBinder; } @Override public boolean onUnbind(Intent intent) { Log.d(TAG, "onUnbind: exec"); return super.onUnbind(intent); } @Override public void onDestroy() { Log.d(TAG, "onDestroy: exec"); super.onDestroy(); } }
In AndroidMainfest. Register Service in XML - Declares as a remote service and is configured to:
<service android:name=".TestAIDLService" android:process=":remote" android:exported="true"> <intent-filter> <action android:name="com.ags.myservice.IMyAidlInterface"/> </intent-filter> </service>
Be careful:
- Here remote means that the local service is set to a remote service.
- Here Intent's action must be written as "Server-side package name.aidl file name".
@2 Client MainActivity:
Copy and compile the package containing the server-side AIDL file into the client directory ($Project/app/src/main). Then write the code as follows:
public class MainActivity extends AppCompatActivity { private static String TAG = "MainActivity"; private Button btn_start; private IMyAidlInterface aidlService; private ServiceConnection connection = new ServiceConnection(){ @Override public void onServiceConnected(ComponentName name, IBinder service) { aidlService = IMyAidlInterface.Stub.asInterface(service); try { aidlService.testMethod1("testString"); Log.d(TAG, "onServiceConnected"); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { Log.d(TAG, "onServiceDisconnected"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_start = findViewById(R.id.btn_start); btn_start.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //Here the parameter is the same as the server-side action, which is "Server Package Name.aidl Interface File Name" Intent intent = new Intent("com.ags.myservice.IMyAidlInterface"); //Note: Android5. Bind remote services only through explicit Intent after 0 intent.setPackage("com.ags.myservice");//Specify Package Name bindService(intent, connection, Context.BIND_AUTO_CREATE); } }); } }
The process spans two applications, the caller is the client and the callee is the server. This AIDL communication case is complete.
More about AIDL can be found: Android Interface Definition Language (AIDL) for Android developers
7 System Service
This is the main explanation of getSystemService method, if Android applications can send text messages, process incoming calls, receive gyroscope data, and so on. Getting system services is essential, and getSystemService is an important API for Android. It is a method of Activity to get corresponding Object s based on the incoming NAME and get system services. Use the following:
public class MainActivity extends AppCompatActivity { private static String TAG = "MainActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE); AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); } }
Now that you have the system services, you can get the methods you need based on each of the different services. More about getSystemService can be found in the documentation: Android activity key method getSystemService detailed
8 Official Document Index
See the documentation for more about service: Service component of Android component