Android basic knowledge 05: four major components-service 02: Remote Call

Source: Internet
Author: User

This topic describes services. There are two articles:

Basic knowledge of Android 05: Service 01 of four components

Android basic knowledge 05: four major components-service 02: Remote Call

Android basic knowledge 05: four major components-service 03: Implementation Mechanism

Reference: aidl, parcelable, and remote services for Android service learning

Instance program address: http://download.csdn.net/detail/xianming01/4131187

1. Role of aidl
Because each application runs in its own process space and can run another service process from the application UI, objects are often transferred between different processes. On the Android platform, a process generally cannot access the memory space of another process. Therefore, to perform a conversation, you need to break down the object into basic units that the operating system can understand and orderly pass through the process boundary.
It is tedious to implement this data transmission process through code. Android provides the aidl tool to handle this task.

Aidl (Android Interface Definition Language) is an IDL Language used to generate code for interprocess communication (IPC) between two processes on the Android device. If you want to call operations on objects in another process (such as service) in a process (such as activity), you can use aidl to generate serializable parameters.
The aidl IPC Mechanism is interface-oriented, like com or CORBA, but more lightweight. It uses a proxy class to transmit data on the client and the implementation end.

2. Use aidl
The official documentation reminds us when to use aidl is necessary: Only you allow the client to access your service from different applications for inter-process communication, and want to process multithreading in your service.
If you do not need to perform concurrent communication (IPC) between different applications, you can create your interface by implementing a binder; or if you want to implement IPC, but do not need to process multiple threads, then implement your interface using a messenger. Before using aidl, you must understand how to bind Service -- bindservice.
Before designing the aidl interface, we should note that calling the aidl interface is a direct method call, not in our imagination. What is the difference between a call from a local or remote process? In particular, the following situations (reference the original text and do not translate it to avoid translation errors ):
Callmade from the local process are executed in the same thread that is making the call. if this is your main UI thread, that thread continues to execute in the aidl interface. if it is another thread, that is the one that executes your code in the service.
Thus, if only local threads are accessing the service, you can completely control which threads are executing in it (but if that is the case, then you shouldn't be using aidl at all, but shoshould instead create the interface by implementing a binder ).
Callfrom a remote process are dispatched from a thread pool the Platform maintains inside of your own process. you must be prepared for Incoming callfrom unknown threads, with multiple callhappening at the same time. in other words, an implementation
Of an aidl interface must be completely thread-safe.
The oneway keyword modifies the behavior of remote CILS. when used, a remote call does not block; it simply sends the transaction data and immediately returns. the implementation of the interface eventually generated es this as a regular call from the binder thread
Pool as a normal remote call. If oneway is used with a local call, there is no impact and the call is still synchronous.

3. Define the aidl Interface
The aidl interface file is nothing special to the common interface content, but its extension is. aidl. Save it in the src directory. If other applications require IPC, the SRC of those applications will also carry this file. Android SDK tools automatically generates an ibinder interface file in the gen directory. Service must implement this ibinder interface as appropriate. Then the client program can bind the service and call the method from ibinder during IPC.
Each aidl file can only define one interface, and can only be an interface declaration and method declaration.

3.1 create a. aidl File
Aidl uses a simple syntax to declare an interface and describe the parameters and return values of its methods and methods. These parameters and return values can be of any type, or even interfaces generated by other aidl.
The import statements are not required for the basic data types (INT, long, Char, Boolean, etc.), string, and charsequence of the Java programming language.
If you want to use other aidl Interface Types in aidl, You need to import them, even in the same package structure. Aidl allows passing classes that implement the parcelable interface. Import is required.
Note that for non-basic data types, which are not string and charsequence types, direction indication is required, including in, out, And inout. In indicates that the data is set by the client, the out parameter is set by the server, and the inout parameter is set by both.
Aidl only supports interface methods and does not expose static variables.

Imusicservice. aidl

package xuxm.demo.service03.server;/** * ClassName:IMusicService * Function: TODO ADD FUNCTION * Reason: TODO ADD REASON * * @author   Leon * @version * @since    Ver 1.1 * @Date 2011-5-19 */ interface IMusicService{void play();void pause();void stop();}

Android will automatically generate a stub class, which inherits the binder class and imusicservice interface. You can also see that it contains a proxy class to implement remote proxy. (Stub class is as follows)

Location of the stub class generated

/* * This file is auto-generated.  DO NOT MODIFY. * Original file: C:\\Users\\xuxianming01.INTERNAL\\workspace\\serviceTest03_server\\src\\xuxm\\demo\\service03\\server\\IMusicService.aidl */package xuxm.demo.service03.server;/** * ClassName:IMusicService * Function: TODO ADD FUNCTION * Reason: TODO ADD REASON * * @author   Leon * @version * @since    Ver 1.1 * @Date 2011-5-19 */public interface IMusicService extends android.os.IInterface{/** Local-side IPC implementation stub class. */public static abstract class Stub extends android.os.Binder implements xuxm.demo.service03.server.IMusicService{private static final java.lang.String DESCRIPTOR = "xuxm.demo.service03.server.IMusicService";/** Construct the stub at attach it to the interface. */public Stub(){this.attachInterface(this, DESCRIPTOR);}/** * Cast an IBinder object into an xuxm.demo.service03.server.IMusicService interface, * generating a proxy if needed. */public static xuxm.demo.service03.server.IMusicService asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof xuxm.demo.service03.server.IMusicService))) {return ((xuxm.demo.service03.server.IMusicService)iin);}return new xuxm.demo.service03.server.IMusicService.Stub.Proxy(obj);}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{switch (code){case INTERFACE_TRANSACTION:{reply.writeString(DESCRIPTOR);return true;}case TRANSACTION_play:{data.enforceInterface(DESCRIPTOR);this.play();reply.writeNoException();return true;}case TRANSACTION_pause:{data.enforceInterface(DESCRIPTOR);this.pause();reply.writeNoException();return true;}case TRANSACTION_stop:{data.enforceInterface(DESCRIPTOR);this.stop();reply.writeNoException();return true;}}return super.onTransact(code, data, reply, flags);}private static class Proxy implements xuxm.demo.service03.server.IMusicService{private android.os.IBinder mRemote;Proxy(android.os.IBinder remote){mRemote = remote;}public android.os.IBinder asBinder(){return mRemote;}public java.lang.String getInterfaceDescriptor(){return DESCRIPTOR;}public void play() throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_play, _data, _reply, 0);_reply.readException();}finally {_reply.recycle();_data.recycle();}}public void pause() throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_pause, _data, _reply, 0);_reply.readException();}finally {_reply.recycle();_data.recycle();}}public void stop() throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_stop, _data, _reply, 0);_reply.readException();}finally {_reply.recycle();_data.recycle();}}}static final int TRANSACTION_play = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);static final int TRANSACTION_pause = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);static final int TRANSACTION_stop = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);}public void play() throws android.os.RemoteException;public void pause() throws android.os.RemoteException;public void stop() throws android.os.RemoteException;}

This class is automatically generated by Android, so we don't need to change it.

In myremotebinder, You need to inherit this stub class and write the control on the player in this binder class. For the sake of simplicity, We will write these two classes into the same file.

Public class musicservice03 extends Service {private string tag = musicservice03.class. getsimplename (); Private mediaplayer mymediaplayer; public static final string intent_key = "action"; Public musicservice03 () {super ();} myremotebinder mbinder = new myremotebinder (musicservice03.this. mymediaplayer); @ overridepublic ibinder onbind (intent arg0) {// todo auto-generated method stublog. V (TAG, tag + "onbi Nd "); mbinder = new myremotebinder (musicservice03.this. mymediaplayer); Return mbinder;} public class myremotebinder extends imusicservice. stub {public myremotebinder (mediaplayer) {mymediacontroller. mediaplayer = mediaplayer;}; @ overridepublic void play () throws RemoteException {// todo auto-generated method stubmymediacontroller.play.exe cute () ;}@ overridepublic void pause () throws remoteex Ception {// todo auto-generated method into cute () ;}@ overridepublic void stop () throws RemoteException {// todo auto-generated method stubmymediacontroller.stop.exe cute ();};} @ overridepublic void oncreate () {// todo auto-generated method stublog. V (TAG, tag + "oncreate ()"); super. oncreate (); If (mymediaplayer = NULL) {mymediaplayer = mediaplayer. create (this, R. raw. test ); Mymediaplayer. setlooping (false) ;}@overridepublic void onstart (intent, int startid) {// todo auto-generated method stublog. V (TAG, tag + "onstart ()"); super. onstart (intent, startid) ;}@ overridepublic Boolean onunbind (intent) {// todo auto-generated method stublog. V (TAG, tag + "onunbind, success? "+ Super. onunbind (intent); Return true; // return false ;}@ overridepublic void onrebind (intent) {// todo auto-generated method stublog. V (TAG, tag + "onrebind () ------------------------------------->"); super. onrebind (intent) ;}@ overridepublic void ondestroy () {// todo auto-generated method stubsuper. ondestroy (); log. V (TAG, "ondestroy"); If (mymediaplayer! = NULL) {mymediaplayer. stop (); mymediaplayer. release () ;}} public mediaplayer getmymediaplayer () {return mymediaplayer;} public void setmymediaplayer (mediaplayer mymediaplayer) {This. mymediaplayer = mymediaplayer ;}}

In this case, the service can be called in the program where the service is located, and other applications can call the service (the purpose of aidl is exactly the same ).
The current program is relatively simple to call. You can refer to the instance code. For calls from other applications, here is a description.

We have created a client application.

In the client program, you must create a package with the same name as the service package (xuxm. Demo. service03.server), and create an aidl file identical to the service.

A stub file is automatically generated here.

Therefore, the activity in the client can use this service.

Package xuxm. demo. service03.client; import xuxm. demo. service03.server. imusicservice; import android. app. activity; import android. content. componentname; import android. content. context; import android. content. intent; 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. textview; public class servicetestserveractivity extends activity implements onclicklistener {/** called when the activity is first created. */Private Static final string tag = servicetestserveractivity. class. getsimplename (); Private textview m_textview_text; private button btnplay; private button btnpause; private button btnstop; private button btnunbind; private button btnfinish; private button btnexit; private imusicservice bindmusicservice; @ override public void oncreate (bundle savedinstancestate) {super. oncreate (savedinstancestate); setcontentview (R. layout. main); m_textview_text = (textview) findviewbyid (R. id. text); btnplay = (button) findviewbyid (R. id. play); btnpause = (button) findviewbyid (R. id. pause); btnstop = (button) findviewbyid (R. id. stop); btnfinish = (button) findviewbyid (R. id. finish); btnexit = (button) findviewbyid (R. id. exit); btnplay. setonclicklistener (this); btnpause. setonclicklistener (this); btnstop. setonclicklistener (this); btnfinish. setonclicklistener (this); btnexit. setonclicklistener (this); connection ();} private void connection () {log. V (TAG, tag + "connection"); intent = new intent ("xuxm. demo. service03.musicservice "); this. startservice (intent); this. bindservice (intent, myserviceconnection, context. bind_auto_create) ;}@ overridepublic void onclick (view v) {// todo auto-generated method stubswitch (v. GETID () {case R. id. play: Try {bindmusicservice. play ();} catch (RemoteException e) {// todo auto-generated catch blocke. printstacktrace ();} m_textview_text.settext (R. string. play); log. D (TAG, "play ....... "); break; case R. id. pause: Try {bindmusicservice. pause ();} catch (RemoteException e) {// todo auto-generated catch blocke. printstacktrace ();} m_textview_text.settext (R. string. pause); log. D (TAG, "pause ....... "); break; case R. id. stop: Try {bindmusicservice. stop ();} catch (RemoteException e) {// todo auto-generated catch blocke. printstacktrace ();} m_textview_text.settext (R. string. stop); log. D (TAG, "stop ....... "); break; case R. id. finish: log. D (TAG, "close ....... "); this. finish (); break; case R. id. exit: log. D (TAG, "exit ....... "); this. finish (); this. stopservice (new intent ("xuxm. demo. service03.musicservice "); break; default: }}// after bindservice is called, the service calls onbind () and calls back this function private serviceconnection myserviceconnection = new serviceconnection () {@ overridepublic void onserviceconnected (componentname, ibinder binder) {bindmusicservice = imusicservice. stub. asinterface (binder); log. D (TAG, "onserviceconnected") ;}@ overridepublic void onservicedisconnected (componentname name) {bindmusicservice = NULL; log. D (TAG, "onservicedisconnected") ;}}; // You must unbind it when the activity is finished. Otherwise, the overflow @ overridepublic void finish () {// todo auto-generated method stubsuper will occur. finish (); this. unbindservice (myserviceconnection );}}

4. Other Instructions

4.1 permission
If the service declares the global mandatory access permission in androidmanifest. XML, other references must declare the permission to start, stop or bind the service.
In addition, the Service can protect her IPC method calling through permissions, and ensure that this operation can be performed by calling the checkcallingpermission (string) method.

4.2 service element of androidmanifest. xml

<service android:name=".RemoteService" android:process=":remote">         <intent-filter>                 <action android:name="com.demo.IMyService" />         </intent-filter> </service>

Android: Process = ": Remote". I didn't add it at the beginning. I used IPC in the same program, that is, the same program as the client/server, the result is mremoteservice = imyservice. stub. asinterface (service); a null pointer exception is prompted. I have observed that the IPC code in different programs does not have this android: Process = ": Remote. Later, I learned from the official document http://androidappdocs.appspot.com/guide/topics/manifest/service-element.html( note the second text ):

Android: Process
The name of the process where the service is to run. normally, all components of an application run in the default process created for the application. it has the same name as the application package. the <Application> element's process attribute can set
Different default for all components. But component can override the default with its own process attribute, allowing you to spread your application processing SS multiple processes.
 
If the name assigned to this attribute begins with a colon (':'), a new process, private to the application, is created when it's needed and the service runs in that process. if the process name begins with a lowercase character, the service will run in a global
Process of that name, provided that it has permission to do so. This allows components in different applications to share a process, cing resource usage.

Android: Process = ": Remote" indicates that a new process is automatically created when the service is required in an application. If Android: Process = "remote" does not have a semicolon (:), a global process is created and different applications share the process.

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.