http://wiki.eoeandroid.com/Android_Interface_Definition_Language_(AIDL)

Android接口定义语言(AIDL)

Android接口定义语言(以下简称AIDL)和其他您使用过得IDL差不多,他使您可以定义应用程序的接口。通过这个接口,客户端和服务器之间可以顺利的进行进程间通讯(IPC)。在android设备上,一个进程的不能通过正常的方式访问其他进程的内存,也就是说,必须把需要通信的对象翻译成操作系统可以识别的原语,通过这些原语才能穿越这些对象的外表,从而得到该物体的内部信息。如果使用用代码来做这些事情,那将非常枯燥和乏味,因此,android为您提供了AIDL。

注意:只有您允许来自不同应用的客户端访问您的IPC服务并且您希望在服务中处理多线程,使用AIDL才是必要的。如果您不需要使用并发的IPC访问不同的应用,您应该通过继承Binder来创建您的接口,或者,如果您确实需要使用IPC,但是不需要处理多线程,那请继承Messenger来实现您的接口。总之,在实现一个AIDL之前,请确保您已经理解了Bound Services。

在您开始设计您的AIDL接口的时候,请注意AIDL接口的调用都是直接的函数调用。请不要想当然的认为这个调用是发生在线程里。具体的情况会取决于这个调用发生在本地进程还是远程进程。描述如下:

  • 发生在本地进程的调用会在发生这个调用的线程里执行。如果这是您的主UI线程,这个线程将会持续的在AIDL接口接口中执行。如果这是其他的线程,那这个线程将会是在服务中执行您的代码的那一个。那么,只有本地线程在访问服务,您才能完全控制是那些线程在这个服务里发生(但是如果是这种情况,那您不应该使用AIDL,而是通过继承Binder创建一个接口)。
  • 发生在远程的调用是在该平台所维护的,您的进程内部的一个线程池中发送的。您必须准备好从未知的线程里接收调用,与此同时,多重调用也会发生。换句话说,AIDL接口的实现必须是完全线程安全的。
  • 单向(oneway)的关键字传输决定了远程调用的行为。使用时,一个远程调用不会被阻塞,它只是发送需要交流的数据然后立即返回。这个接口的实现最终就像一个来自Binder线程池的调用一样作为一个普通的远程调用而被接受。如果单向是在本地被调用的,那他将不会有任何影响,而这个调用是一直同步的。

声明一个AIDL接口

您必须在一个.aidl格式的文件里使用java程序语言的语法声明AIDL接口,并且把它放到承载这个服务的应用和绑定这个服务的应用的源代码的文件夹(文件夹src/)下。

当您创建一个含有.aidl格式的文件的应用时,Android SDK工具会基于这个.aidl文件自动生成一个IBinder的接口并且把它保存到工程的gen文件夹下。这个服务必须正确的继承IBinder接口。这样客户程序就可以绑定这个服务,从而可以从IBinder中调用方法来执行IPC。

使用一下步骤通过AIDL建立一个边界服务:

1.创建一个.aidl:

这个文件使用签名方法定义一个一应用程序接口。

2.继承这个接口:

这个Android SDK工具使用Java应用程序语言基于您的.aidl文件生成一个接口。这个接口有一个叫Stub的内部抽象类,这个类继承自Binder并且实现您的AIDL接口中的方法。您必须继承这个Stub类并且实现这些方法。

3.Expose the interface to clients

把接口暴露给客户端: 继承一个Service并且重写onBind()来返回您实现的Stub类。

注意:为了避免打断使用您服务的其他应用,在您第一次打开AIDL接口的时候,您对AIDL接口的任何改变必须保持向后兼容。这就是说,您必须保证对原始接口的支持,因为为了可以访问您的服务接口,您的.aidl文件已经被复制到了其他应用程序里面。

1. 创建一个.aidl

AIDL使用一个简单的语法,让你一个接口与一个或多个参数和返回值的方法,可以申报。参数和返回值可以是任何类型,甚至其他AIDL生成的接口。 AIDL使用一种简单的语法使您使用一个或者多个可以输入参数输出返回值的方法来声明一个接口。这些参数和返回值可以是任何数据类型,甚至是AIDL生成的接口。 您必须使用java语言构建一个.aidl文件。每个.aild文件必须定义一个单独的接口,并且使用确定的声明和方法签名。

By default, AIDL supports the following data types:

详细来说,AIDL支持下面的数据类型:

  • 所有的java语言的基本数据类型,比如int, long, char, Boolean 等等。
  • String 字符串
  • CharSequence 字符数组
  • List

List中的所有元素必须是list所支持的数据类型中的一种,或者是您已经声明的其他AIDL接口或Parcelables数组之一。一个List有时可能被当作一个“通用”类来使用(比如List<String>)。这些类具体实现的时候,对方接收的通常是ArrayList,即使该方法继承List的接口生成的。

  • Map

在map中的所有元素必须是list所支持的数据类型中的一种,或者是您已经声明的其他AIDL接口或Parcelables数组之一。一般的Map,(比如形如Map<String,Integer>一类)是不被 支持的。这些类具体实现的时候,对方接收的通常是HashMap,即使该方法是继承Map的接口生成的。

如果需要增加上面没有列出的数据类型,您必须使用import语句引入该类型,即使他们作为您的接口被定义在同一个包。

When defining your service interface, be aware that:

当定义您的服务接口的时候,请注意:

  • Methods can take zero or more parameters, and return a value or void.
  • 方法可以不使用参数也可以使用多个参数,可以返回一个值或者不返回值。
  • All non-primitive parameters require a directional tag indicating which way the data goes. Either in, out, orinout (see the example below).
  • 所有的非原始参数需要一个方向标签,来指示数据的去向:是in out 或者inout的一种(请看下面的例子)。

Primitives are in by default, and cannot be otherwise.

原语默认是in,并且不能是其他的。

Caution: You should limit the direction to what is truly needed, because marshalling parameters is expensive.

注意:您应该尽量使方向标签指示到真正需要的地方,因为编组参数会耗费很多的系统资源。

  • All code comments included in the .aidl file are included in the generatedIBinderinterface (except for comments before the import and package statements).
  • 所有包含在.aidl文件的代码注释会被包含在生成的IBinder接口中(在引入和声明包之前的注释除外)。
  • Only methods are supported; you cannot expose static fields in AIDL.Here is an example .aidl file:
  • 只支持方法,您不必期望在AIDL中暴露静态方法,这是一个.aidl文件的例子:
// IRemoteService.aidlpackage com.example.android;// Declare any non-default types here with import statements/** Example service interface */interface IRemoteService {    /** Request the process ID of this service, to do evil things with it. */    int getPid();    /** Demonstrates some basic types that you can use as parameters * and return values in AIDL. */    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,            double aDouble, String aString);}

Simply save your .aidl file in your project's src/ directory and when you build your application, the SDK tools generate theIBinderinterface file in your project's gen/ directory. The generated file name matches the .aidlfile name, but with a .java extension (for example, IRemoteService.aidl results in IRemoteService.java).

建立您的工程时,您只需要把.aidl文件保存到src/目录里,SDK工具会在您的gen、文件夹下自动生成IBinder接口文件。生成的文件名和.aidl文件名相符合,但是使用.java的扩展名(例如, 如果文件是IRemoteService.aidl则生成的是 IRemoteService.java)。

If you use Eclipse, the incremental build generates the binder class almost immediately. If you do not use Eclipse, then the Ant tool generates the binder class next time you build your application—you should build your project with ant debug (or ant release) as soon as you're finished writing the .aidl file, so that your code can link against the generated class.

如果您使用Eclipse,增量构建几乎即时地生成绑定者类。如果你不使用Eclipse,那么Ant工具在你下次构建你的应用程序时生成绑定着类——你应该用ant debug命令(甚至ant release命令)构建你的工程,只要你完成编写.aidl文件时,以使你的代码可以链接到被生成的类。

2. Implement the interface

实现该接口

When you build your application, the Android SDK tools generate a .java interface file named after your .aidlfile. The generated interface includes a subclass named Stub that is an abstract implementation of its parent interface (for example, YourInterface.Stub) and declares all the methods from the .aidl file.

在您创建应用的时候,AndroidSDK工具会生成一个以您.adil文件命名的.java文件。生成的接口包括一个名为Stub的子类,这个子类是他的父接口的一个抽象实现(例如 YourInterface.Stub),并且声明.aidl文件里的所有方法。

Note: Stub also defines a few helper methods, most notably asInterface(), which takes anIBinder(usually the one passed to a client'sandroid.os.IBinder) onServiceConnected()callback method) and returns an instance of the stub interface. See the sectionCalling an IPC Methodfor more details on how to make this cast.

注意:Stub也定义一些辅助方法,尤其是 asInterface(),它需要一个IBinder(通常是传递给客户端的一个回调方法。)并且返回一个stub接口的实例。更多细节参考Calling an IPC Method这一节。

To implement the interface generated from the .aidl, extend the generatedBinderinterface (for example,YourInterface.Stub) and implement the methods inherited from the .aidl file.

要实现.AIDL里面定义的接口,就要继承已经生成的Binder接口(例如 YourInterface.Stub)并且继承.aidl文件的方法。

Here is an example implementation of an interface called IRemoteService (defined by theIRemoteService.aidl example, above) using an anonymous instance:

这里是一个使用继承IRemoteService(使用上面例子的IRemoteService.aidl 定义)接口的例子,这个IRemoteService接口使用一个匿名实例调用IRemoteService 。

private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {    public int getPid(){        return Process.myPid();    }    public void basicTypes(int anInt, long aLong, boolean aBoolean,        float aFloat, double aDouble, String aString) {        // Does nothing    }};

Now the mBinder is an instance of the Stub class (aBinder), which defines the RPC interface for the service. In the next step, this instance is exposed to clients so they can interact with the service.

mBinder 是Stub类的一个实例(一个Binder),它定义了服务的RPC接口。下一步,这个实例暴露给客户端,从而使客户端可以和服务进行交互。

There are a few rules you should be aware of when implementing your AIDL interface:

当继承AIDL接口的时候,有许多规则需要注意:

  • Incoming calls are not guaranteed to be executed on the main thread, so you need to think about multithreading from the start and properly build your service to be thread-safe.
  • 来自外部的调用不保证在主线程中一定执行,所以您需要一开始就考虑多线程,合理的创建您的服务保证线程安全。
  • By default, RPC calls are synchronous. If you know that the service takes more than a few milliseconds to complete a request, you should not call it from the activity's main thread, because it might hang the application (Android might display an "Application is Not Responding" dialog)—you should usually call them from a separate thread in the client.
  • RPC调用默认是同步的。如果您知道一个服务需要耗费很多时间来完成请求,那请不要从activty的主线程里调用,因为这样会是应用没有响应(Android可能会显示一个“应用程序没有响应”(ANR)对话框)。通常你应该从客户端的另一个线程里调用他们。
  • No exceptions that you throw are sent back to the caller.
  • 抛出的异常不要返回给调用者。

3. Expose the interface to clients-为客户端公开接口

Once you've implemented the interface for yourservice, you need to expose it to clients so they can bind to it. To expose the interface for your service, extend Service and implementonBind()to return an instance of your class that implements the generated Stub (as discussed in the previous section). Here's an example service that exposes the IRemoteService example interface to clients.

一旦您完成了对接口的实现,你需要向客户端公开该实现,这样客户端就可以使用它了。这要发布一个Service,请继承Service并实现onBinder()方法来返回您的一个被实现的类的实例,该类继承自生成的Stub类(前面已经叙述过)。下面是一个例子,其中Service向客户端公了 IRemoteService接口。

public class RemoteService extends Service {    @Override    public void onCreate() {        super.onCreate();    }    @Override    public IBinder onBind(Intent intent) {        // Return the interface        return mBinder;    }    private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {        public int getPid(){            return Process.myPid();        }        public void basicTypes(int anInt, long aLong, boolean aBoolean,            float aFloat, double aDouble, String aString) {            // Does nothing        }    };}

Now, when a client (such as an activity) callsandroid.content.ServiceConnection, int)bindService()to connect to this service, the [client'sonServiceConnected()] callback receives the mBinder instance returned by the service's onBind() method.

当一个客户端(比如一个activty调用)android.content.ServiceConnection, int) bindService()方法来和这个服务连接时,这个客户端的android.os.IBinder) onServiceConnected()方法接收mBinder实例并且通过服务的onBind方法返回。

The client must also have access to the interface class, so if the client and service are in separate applications, then the client's application must have a copy of the .aidl file in its src/ directory (which generates theandroid.os.Binder interface—providing the client access to the AIDL methods).

客户端也必须访问接口类,所以如果客户端和服务分属两个不同的应用,那客户端应用必须复制.aidl文件到他的src/目录(这个目录生成android.os.Binder接口,提供客户端访问的AIDL接口)。

When the client receives the IBinder in the onServiceConnected() callback, it must callYourServiceInterface.Stub.asInterface(service) to cast the returned parameter toYourServiceInterface type. For example:

当客户端在android.os.IBinder) onServiceConnected()回调方法中接收IBinder时,它必须调用YourServiceInterface.Stub.asInterface(service)来与您的YourServiceInterface 接口类型保持一致。例如:

IRemoteService mIRemoteService;private ServiceConnection mConnection = new ServiceConnection() {    // Called when the connection with the service is established    public void onServiceConnected(ComponentName className, IBinder service) {        // Following the example above for an AIDL interface,        // this gets an instance of the IRemoteInterface, which we can use to call on the service        mIRemoteService = IRemoteService.Stub.asInterface(service);    }    // Called when the connection with the service disconnects unexpectedly    public void onServiceDisconnected(ComponentName className) {        Log.e(TAG, "Service has unexpectedly disconnected");        mIRemoteService = null;    }};

For more sample code, see theRemoteService.javaclass inApiDemos. 更多代码,请看ApiDemos的RemoteService.java。

Passing Objects over IPC

If you have a class that you would like to send from one process to another through an IPC interface, you can do that. However, you must ensure that the code for your class is available to the other side of the IPC channel and your class must support theParcelableinterface. Supporting theParcelableinterface is important because it allows the Android system to decompose objects into primitives that can be marshalled across processes.

如果你的类中有的需要通过IPC接口从一个进程发送到另一个进程,您可以这么做。然而,你必须确保类代码可以被其他的IPC接收端所使用。您的类必须支持Parcelable接口。支持Parcelable接口非常重要因为Android系统需要分解对象为可以穿越进程的原语。

To create a class that supports theParcelableprotocol, you must do the following:

创建一个支持Parcelable协议的类你需要这么做:

1. Make your class implement the Parcelable interface. 确保您的类继承了Parcelable 接口

2. Implementint) writeToParcel, which takes the current state of the object and writes it to aParcel.

实现public voidint) writeToParcel(Parcel out),该方法可以将当前对象的状态写入parcel.

3. Add a static field called CREATOR to your class which is an object implementing theParcelable.Creatorinterface.

向类中添加一个静态成员,名为CREATOR。该对象实现了Parcelable.Creator接口.

4. Finally, create an .aidl file that declares your parcelable class (as shown for the Rect.aidl file, below).

最好,创建一个声明您的parcelable 类的.aidl文件(就像下面的Rect.aidl文件那样)。

If you are using a custom build process, do not add the .aidl file to your build. Similar to a header file in the C language, this .aidl file isn't compiled. 如果您在使用自定义的进程,不要在里面加入.aild文件。这和C语言的头文件和相似,.aidl文件不会被编译。

AIDL uses these methods and fields in the code it generates to marshall and unmarshall your objects.

AIDL将使用代码中生成的这些方法和成员来伪装或解读对象。

For example, here is a Rect.aidl file to create a Rect class that'sparcelable: 这里有一个Rect.aidl文件创建一个有parcelable类型Rect类的例子

package android.graphics;// Declare Rect so AIDL can find it and knows that it implements// the parcelable protocol.parcelable Rect;

And here is an example of how theRectclass implements the Parcelable protocol.

这个例子说明了Rect类如何实现了Parcelable协议.

import android.os.Parcel;import android.os.Parcelable;public final class Rect implements Parcelable {    public int left;    public int top;    public int right;    public int bottom;    public static final Parcelable.Creator<Rect> CREATOR = newParcelable.Creator<Rect>() {        public Rect createFromParcel(Parcel in) {            return new Rect(in);        }        public Rect[] newArray(int size) {            return new Rect[size];        }    };    public Rect() {    }    private Rect(Parcel in) {        readFromParcel(in);    }    public void writeToParcel(Parcel out) {        out.writeInt(left);        out.writeInt(top);        out.writeInt(right);        out.writeInt(bottom);    }    public void readFromParcel(Parcel in) {        left = in.readInt();        top = in.readInt();        right = in.readInt();        bottom = in.readInt();    }}

The marshalling in the Rect class is pretty simple. Take a look at the other methods onParcelto see the other kinds of values you can write to a Parcel.

Rect类中的伪装是相当简单的。仔细看看Parcel中的其他方法,你会看到其他各种值你都可以写进Parcel.

Warning: Don't forget the security implications of receiving data from other processes. In this case, the Rectreads four numbers from the Parcel, but it is up to you to ensure that these are within the acceptable range of values for whatever the caller is trying to do. See Security and Permissions for more information about how to keep your application secure from malware.

警告:不要忘了考虑从其他进程接收数据时的安全性。在本例中,Rect将从Parcel中读四个数字,而你的工作则是确保这些都在可接受的值得范围内而不管调用者想要干什么。AndRoid中的安全和访问许可中有更多关于如何确保应用程序安全的信息。 Calling an IPC Method

调用一个IPC方法

________________________________________

Here are the steps a calling class must take to call a remote interface defined with AIDL:

调用类调用AIDL接口的步骤:

1. Include the .aidl file in the project src/ directory.

引入项目src/目录的.aidl文件

2. Declare an instance of theIBinderinterface (generated based on the AIDL).

声明一个IBinder的实例(基于AIDL生成)。

3. ImplementServiceConnection.

实现ServiceConnection.。

4. Callandroid.content.ServiceConnection, int) Context.bindService(), passing in yourServiceConnectionimplementation.

调用android.content.ServiceConnection, int) Context.bindService(),并在ServiceConnection实现中进行传递.

5. In your implementation ofandroid.os.IBinder) onServiceConnected(), you will receive anIBinderinstance (called service). Call YourInterfaceName.Stub.asInterface((IBinder)service) to cast the returned parameter toYourInterface type.

在您实现android.os.IBinder) onServiceConnected()时,您将会收到一个IBinder实例(被调用的Service) , 调用 YourInterfaceName.Stub.asInterface((IBinder)service) 并将参数转换为YourInterface类型。

6. Call the methods that you defined on your interface. You should always trapDeadObjectExceptionexceptions, which are thrown when the connection has broken; this will be the only exception thrown by remote methods.

调用接口中定义的方法。,你应该捕捉DeadObjectException异常,该异常在连接断开时被抛出。它只会被远程方法抛出。

7. To disconnect, callContext.unbindService()with the instance of your interface.

断开连接,调用接口实例中的Context.unbindService()方法。

A few comments on calling an IPC service: 调用IPC服务时候的一些经验:

  • Objects are reference counted across processes.-跨进程时,对象会被统计。
  • You can send anonymous objects as method arguments.-匿名对象可以通过方法参数发送。

For more information about binding to a service, read theBound Servicesdocument.

公关于绑定服务的更多信息请参阅Bound Services的文档。

Here is some sample code demonstrating calling an AIDL-created service, taken from the Remote Service sample in the ApiDemos project.

这是一些展示调用基于AIDL创建服务的简单例子,来自ApiDemo项目的远程服务模块。

public static class Binding extends Activity {    /** The primary interface we will be calling on the service. */    IRemoteService mService = null;    /** Another interface we use on the service. */    ISecondary mSecondaryService = null;    Button mKillButton;    TextView mCallbackText;    private boolean mIsBound;    /** * Standard initialization of this activity. Set up the UI, then wait * for the user to poke it before doing anything. */    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.remote_service_binding);        // Watch for button clicks.        Button button = (Button)findViewById(R.id.bind);        button.setOnClickListener(mBindListener);        button = (Button)findViewById(R.id.unbind);        button.setOnClickListener(mUnbindListener);        mKillButton = (Button)findViewById(R.id.kill);        mKillButton.setOnClickListener(mKillListener);        mKillButton.setEnabled(false);        mCallbackText = (TextView)findViewById(R.id.callback);        mCallbackText.setText("Not attached.");    }    /** * Class for interacting with the main interface of the service. */    private ServiceConnection mConnection = new ServiceConnection() {        public void onServiceConnected(ComponentName className,                IBinder service) {            // This is called when the connection with the service has been            // established, giving us the service object we can use to            // interact with the service. We are communicating with our            // service through an IDL interface, so get a client-side            // representation of that from the raw service object.            mService = IRemoteService.Stub.asInterface(service);            mKillButton.setEnabled(true);            mCallbackText.setText("Attached.");            // We want to monitor the service for as long as we are            // connected to it.            try {                mService.registerCallback(mCallback);            } catch (RemoteException e) {                // In this case the service has crashed before we could even                // do anything with it; we can count on soon being                // disconnected (and then reconnected if it can be restarted)                // so there is no need to do anything here.            }            // As part of the sample, tell the user what happened.            Toast.makeText(Binding.this, R.string.remote_service_connected,                    Toast.LENGTH_SHORT).show();        }        public void onServiceDisconnected(ComponentName className) {            // This is called when the connection with the service has been            // unexpectedly disconnected -- that is, its process crashed.            mService = null;            mKillButton.setEnabled(false);            mCallbackText.setText("Disconnected.");            // As part of the sample, tell the user what happened.            Toast.makeText(Binding.this, R.string.remote_service_disconnected,                    Toast.LENGTH_SHORT).show();        }    };    /** * Class for interacting with the secondary interface of the service. */    private ServiceConnection mSecondaryConnection = new ServiceConnection() {        public void onServiceConnected(ComponentName className,                IBinder service) {            // Connecting to a secondary interface is the same as any            // other interface.            mSecondaryService = ISecondary.Stub.asInterface(service);            mKillButton.setEnabled(true);        }        public void onServiceDisconnected(ComponentName className) {            mSecondaryService = null;            mKillButton.setEnabled(false);        }    };    private OnClickListener mBindListener = new OnClickListener() {        public void onClick(View v) {            // Establish a couple connections with the service, binding            // by interface names. This allows other applications to be            // installed that replace the remote service by implementing            // the same interface.            bindService(new Intent(IRemoteService.class.getName()),                    mConnection, Context.BIND_AUTO_CREATE);            bindService(new Intent(ISecondary.class.getName()),                    mSecondaryConnection, Context.BIND_AUTO_CREATE);            mIsBound = true;            mCallbackText.setText("Binding.");        }    };    private OnClickListener mUnbindListener = new OnClickListener() {        public void onClick(View v) {            if (mIsBound) {                // If we have received the service, and hence registered with                // it, then now is the time to unregister.                if (mService!= null) {                    try {                        mService.unregisterCallback(mCallback);                    } catch (RemoteException e) {                        // There is nothing special we need to do if the service                        // has crashed.                    }                }                // Detach our existing connection.                unbindService(mConnection);                unbindService(mSecondaryConnection);                mKillButton.setEnabled(false);                mIsBound = false;                mCallbackText.setText("Unbinding.");            }        }    };    private OnClickListener mKillListener = new OnClickListener() {        public void onClick(View v) {            // To kill the process hosting our service, we need to know its            // PID. Conveniently our service has a call that will return            // to us that information.            if (mSecondaryService!= null) {                try {                    int pid = mSecondaryService.getPid();                    // Note that, though this API allows us to request to                    // kill any process based on its PID, the kernel will                    // still impose standard restrictions on which PIDs you                    // are actually able to kill. Typically this means only                    // the process running your application and any additional                    // processes created by that app as shown here; packages                    // sharing a common UID will also be able to kill each                    // other's processes.                    Process.killProcess(pid);                    mCallbackText.setText("Killed service process.");                } catch (RemoteException ex) {                    // Recover gracefully from the process hosting the                    // server dying.                    // Just for purposes of the sample, put up a notification.                    Toast.makeText(Binding.this,                            R.string.remote_call_failed,                            Toast.LENGTH_SHORT).show();                }            }        }    };    // ----------------------------------------------------------------------    // Code showing how to deal with callbacks.    // ----------------------------------------------------------------------    /** * This implementation is used to receive callbacks from the remote * service. */    private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {        /** * This is called by the remote service regularly to tell us about * new values. Note that IPC calls are dispatched through a thread * pool running in each process, so the code executing here will * NOT be running in our main thread like most other things -- so, * to update the UI, we need to use a Handler to hop over there. */        public void valueChanged(int value) {            mHandler.sendMessage(mHandler.obtainMessage(BUMP_MSG, value, 0));        }    };    private static final int BUMP_MSG = 1;    private Handler mHandler = new Handler() {        @Override public void handleMessage(Message msg) {            switch (msg.what) {                case BUMP_MSG:                    mCallbackText.setText("Received from service: " + msg.arg1);                    break;                default:                    super.handleMessage(msg);            }        }    };}

更多相关文章

  1. android 入门xml布局文件--转
  2. Android - 文件读写操作 总结
  3. android中的布局文件
  4. Android布局文件中的各种属性
  5. 老罗Android开发视频教程 (android解析xml文件 )3集集合
  6. Android工具箱之理解app资源文件
  7. android 文件读取

随机推荐

  1. 详解Android数据存储―使用SQLite数据库
  2. android 控件 单项选择(RadioGroup,Radio
  3. Unable to find method 'org.gradle.api.
  4. Android(安卓)Studio 在run时报的异常 Fa
  5. Android之external部分目录功能说明整理
  6. Android中GC_EXTERNAL_ALLOC的含义小结
  7. listview 常用智识总结
  8. android百度地图定位显示当前位置(androi
  9. x86平台下 Android(安卓)系统的 Linux 部
  10. Android(安卓)解屏幕锁与点亮屏幕