【翻译】Service

转载请注明出处:http://blog.csdn.net/kester_/article/details/52503723

参考地址:https://developer.android.com/reference/android/app/Service.html

Service

A Service is an application component representing either an application’s desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use. Each service class must have a corresponding declaration in its package’s AndroidManifest.xml. Services can be started with Context.startService() and Context.bindService().
Service是一个应用组件,要么是用来执行和用户交互无关的耗时操作,要么是用来给其他应用提供功能。每一个Service类必须在AndroidManifest.xml里有一个关联的声明。Service可以使用Context.startService()和Context.bindService()来开启。

Note that services, like other application objects, run in the main thread of their hosting process. This means that, if your service is going to do any CPU intensive (such as MP3 playback) or blocking (such as networking) operations, it should spawn its own thread in which to do that work. More information on this can be found in Processes and Threads. The IntentService class is available as a standard implementation of Service that has its own thread where it schedules its work to be done.
需要注意的是,Service像其他应用的对象,运行在进程的主线程。这就意味着,如果你的Service将要做CPU集中运算(例如MP3重放)或者阻塞操作(例如网络交流),它应该大量产生自己的线程来做这个事情。可以在Process和Threads章节来获取更多现骨干信息。IntentService类是Service的标准实现类,它拥有自己的线程来安排工作。

Topics covered here:
主题有下面几个:

What is a Service?
Service Lifecycle
Permissions
Process Lifecycle
Local Service Sample
Remote Messenger Service Sample


Developer Guides

For a detailed discussion about how to create services, read the Services developer guide.
更多关于如何创建Service的详细讨论参见Services开发者指引。


What is a Service?

Most confusion about the Service class actually revolves around what it is not:
大多数对于Service的疑惑是围绕“what it is not”:

A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.
一个Service不是一个分离的进程。Service不是运行在自己特有的进程;一般情况下,它和应用运行在同一个进程。

A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).
一个Service不是一个线程。它不会自己离开主线程工作(所以要避免ANR)。

Thus a Service itself is actually very simple, providing two main features:
因此一个Service是非常简单的,它主要有两个特性:

A facility for the application to tell the system about something it wants to be doing in the background (even when the user is not directly interacting with the application). This corresponds to calls to Context.startService(), which ask the system to schedule work for the service, to be run until the service or someone else explicitly stop it.
一个特性是用来告诉系统应用在做后台事情(甚至不是用户和应用直接交互的)的东西。这时候可以用Context.startService()来告诉系统给Service安排工作运行直到某人明确停止它。

A facility for an application to expose some of its functionality to other applications. This corresponds to calls to Context.bindService(), which allows a long-standing connection to be made to the service in order to interact with it.
另一个特性是用来暴露一些功能给其他应用。这时候可以用Context.bindService()来给Service维持一个长期存在的连接,因此可以互相操作。

When a Service component is actually created, for either of these reasons, all that the system actually does is instantiate the component and call its onCreate() and any other appropriate callbacks on the main thread. It is up to the Service to implement these with the appropriate behavior, such as creating a secondary thread in which it does its work.
当一个Service组件被创建的时候,如果不是上述两个理由的话,系统只会在主线程调用Service的onCreate()方法和其他合适的回调。由Service负责实现这些合适的行为,例如创建第二个线程来工作。

Note that because Service itself is so simple, you can make your interaction with it as simple or complicated as you want: from treating it as a local Java object that you make direct method calls on (as illustrated by Local Service Sample), to providing a full remoteable interface using AIDL.
需要注意的是由于Service本身是简单的,你可以自由发挥操控Service:可以作为本地Java对象的方法直接调用(如Local Service Sample例子),也可以使用AIDL提供远程接口。


Service Lifecycle

There are two reasons that a service can be run by the system. If someone calls Context.startService() then the system will retrieve the service (creating it and calling its onCreate() method if needed) and then call its onStartCommand(Intent, int, int) method with the arguments supplied by the client. The service will at this point continue running until Context.stopService() or stopSelf() is called. Note that multiple calls to Context.startService() do not nest (though they do result in multiple corresponding calls to onStartCommand()), so no matter how many times it is started a service will be stopped once Context.stopService() or stopSelf() is called; however, services can use their stopSelf(int) method to ensure the service is not stopped until started intents have been processed.
两种情况下系统会运行Service。一种是调用了Context.startService()然后系统检索到Service(创建它并且在需要的时候调用它的onCreate()方法)再调用它的onStartCommand(Intent,int,int)方法,参数由客户端提供。Service这时候持续运行直到Context.stopService()或者stopSelf()方法被调用。需要注意的是多个Context.startService()调用不会嵌套(尽管它们会唤起多次onStartCommand()),所以不论Service开启了多少次,只要调用一次Context.stopService()或者stopSelf()就会停止;但是,Service可以使用stopSelf(int)方法来确保Service没有停止直到开启的intents被处理。

For started services, there are two additional major modes of operation they can decide to run in, depending on the value they return from onStartCommand(): START_STICKY is used for services that are explicitly started and stopped as needed, while START_NOT_STICKY or START_REDELIVER_INTENT are used for services that should only remain running while processing any commands sent to them. See the linked documentation for more detail on the semantics.
对于开启了的Service,有两种附加的主要的模式来操作它们运行,onStartCommand()的返回值:START_STICKY 用来标记Service有明确的开始和结束,START_NOT_STICKY 或者 START_REDELIVER_INTENT 用来标记Service只在处理任何发送给它们的命令时维持运行。查看相关文档来获取更多语法详情。

Clients can also use Context.bindService() to obtain a persistent connection to a service. This likewise creates the service if it is not already running (calling onCreate() while doing so), but does not call onStartCommand(). The client will receive the IBinder object that the service returns from its onBind(Intent) method, allowing the client to then make calls back to the service. The service will remain running as long as the connection is established (whether or not the client retains a reference on the service’s IBinder). Usually the IBinder returned is for a complex interface that has been written in aidl.
客户端也能使用Context.bindService()来获得Service持久的连接。这个方法同样会在Service没有运行的时候创建Servcie(调用onCreate()来做),但不会调用onStartCommand()。客户端会接受到从Service的onBind(Intent)方法返回的IBinder对象,允许客户端回调Service。Service会维持运行只要连接被建立(无论客户端是否保持Service的IBinder的引用)。通常来说,IBinder返回值是给写在AIDL的复杂接口使用的。

A service can be both started and have connections bound to it. In such a case, the system will keep the service running as long as either it is started or there are one or more connections to it with the Context.BIND_AUTO_CREATE flag. Once neither of these situations hold, the service’s onDestroy() method is called and the service is effectively terminated. All cleanup (stopping threads, unregistering receivers) should be complete upon returning from onDestroy().
一个Service既可以开启也可以绑定连接。在这种情况下,只要它被开启或者有一个或多个带有Context.BIND_AUTO_CREATE 标记的连接绑定它,系统就会保持Service运行。一旦两种条件都不存在了,Service的onDestroy()方法就会被调用而且Service会被有效地终止。所有清理(停止线程,反注册广播)在onDestroy返回前都应该完成。


Permissions

Global access to a service can be enforced when it is declared in its manifest’s tag. By doing so, other applications will need to declare a corresponding element in their own manifest to be able to start, stop, or bind to the service.
当在manifest的标签里声明了Service后可以被全局访问。因此,其他应用将需要声明对应的元素来允许开启,停止,绑定到Service。

As of GINGERBREAD, when using Context.startService(Intent), you can also set Intent.FLAG_GRANT_READ_URI_PERMISSION and/or Intent.FLAG_GRANT_WRITE_URI_PERMISSION on the Intent. This will grant the Service temporary access to the specific URIs in the Intent. Access will remain until the Service has called stopSelf(int) for that start command or a later one, or until the Service has been completely stopped. This works for granting access to the other apps that have not requested the permission protecting the Service, or even when the Service is not exported at all.
Android 2.3开始,当使用Context.startService(Intent)时,你也可以在Internet设置Intent.FLAG_GRANT_READ_URI_PERMISSION 和/或 Intent.FLAG_GRANT_WRITE_URI_PERMISSION 。这会允许Service临时访问指定的URI。访问权将会持续到Service调用stopSelf(int),或者持续到Service被完全停止。这可以用来保证其他没有请求保护Service的权限的应用可以访问它,甚至当Service没有暴露给它们时。

In addition, a service can protect individual IPC calls into it with permissions, by calling the checkCallingPermission(String) method before executing the implementation of that call.
另外,一个Service可以通过权限保护个人的IPC调用,在执行IPC方法的实现之前使用checkCallPermission(String)方法来检测。

See the Security and Permissions document for more information on permissions and security in general.
查看Security和Permisssions文档来获取更多信息。


Process Lifecycle

The Android system will attempt to keep the process hosting a service around as long as the service has been started or has clients bound to it. When running low on memory and needing to kill existing processes, the priority of a process hosting the service will be the higher of the following possibilities:
Android系统会尝试保证持有Service的进程运行,只要Service已经开启或者被客户端绑定。当内存低并且需要杀死存在的进程时,持有Service的进程的优先级会比下面的高:

If the service is currently executing code in its onCreate(), onStartCommand(), or onDestroy() methods, then the hosting process will be a foreground process to ensure this code can execute without being killed.
如果一个Service在onCreate(),onStartCommand(),或者onDestroy()方法执行代码,它的进程会成为前台进程来确保这些代码能不被干掉地执行。

If the service has been started, then its hosting process is considered to be less important than any processes that are currently visible to the user on-screen, but more important than any process not visible. Because only a few processes are generally visible to the user, this means that the service should not be killed except in low memory conditions. However, since the user is not directly aware of a background service, in that state it is considered a valid candidate to kill, and you should be prepared for this to happen. In particular, long-running services will be increasingly likely to kill and are guaranteed to be killed (and restarted if appropriate) if they remain started long enough.
如果Service已经开启,持有它的进程被认为重要性比任何当前屏幕可见的进程低,但是比任何不可见的进程的重要性高。因为只有少量进程总是对用户可见,这就意味着Service不应该被干掉除非内存低。但是,由于用户不是直接指导后台Service,在那个状态是被认为有效的可杀的候选人,你应该准备好这件事情发生。特别地,长时间运行的Service将会更可能被杀掉,要保证好被杀掉(以及在适当的时候重启)的准备如果他们维持开启状态足够长。

If there are clients bound to the service, then the service’s hosting process is never less important than the most important client. That is, if one of its clients is visible to the user, then the service itself is considered to be visible. The way a client’s importance impacts the service’s importance can be adjusted through BIND_ABOVE_CLIENT, BIND_ALLOW_OOM_MANAGEMENT, BIND_WAIVE_PRIORITY, BIND_IMPORTANT, and BIND_ADJUST_WITH_ACTIVITY.
如果有客户端绑定Service,持有Service 的进程的重要性永远不会比最重要的客户端低。也就是说,如果一个客户端对用户可见,这个客户端的Service也认为是可见的。客户端重要性影响Service重要性可以通过几个标签来调整,BIND_ABOVE_CLIENT , BIND_ALLOW_OOM_MANAGEMENT , BIND_WAIVE_PRIORITY , BIND_IMPORTANT , 和 BIND_ADJUST_WITH_ACTIVITY

A started service can use the startForeground(int, Notification) API to put the service in a foreground state, where the system considers it to be something the user is actively aware of and thus not a candidate for killing when low on memory. (It is still theoretically possible for the service to be killed under extreme memory pressure from the current foreground application, but in practice this should not be a concern.)
一个开启的Service可以使用startForeground(int,Notification) API来把Service放到前台状态, 系统就会认为认为这是用户关注的并且不会在内存低时干掉它。(理论上,由当前前台应用导致的内存极低的情况下仍然有可能会干掉Service,但是实际上不需要关心这个。)

Note this means that most of the time your service is running, it may be killed by the system if it is under heavy memory pressure. If this happens, the system will later try to restart the service. An important consequence of this is that if you implement onStartCommand() to schedule work to be done asynchronously or in another thread, then you may want to use START_FLAG_REDELIVERY to have the system re-deliver an Intent for you so that it does not get lost if your service is killed while processing it.
这意味着大多数情况下你的Service运行时,内存低的情况下可能会被系统干掉。如果这个发生了,系统迟一些会把它重启。一个重要的结论是,如果你实现onStartCommand()来异步做一些事情或者在其他的线程干事,你需要使用START_FLAG_REDELIVERY 标签来让系统重新传Intent给你,让你的Service处理事情的时候不至于丢失数据。

Other application components running in the same process as the service (such as an Activity) can, of course, increase the importance of the overall process beyond just the importance of the service itself.
其他应用组件也能和Service运行在同一个进程(例如Activity),当然,这会比只有Service的进程的重要性更高。


Local Service Sample

One of the most common uses of a Service is as a secondary component running alongside other parts of an application, in the same process as the rest of the components. All components of an .apk run in the same process unless explicitly stated otherwise, so this is a typical situation.
Service其中一个最普通的用法就是作为应用的应用次要的组件,和其他组件放在同一个进程。所有的组件运行在同一个进程除非特殊声明。

When used in this way, by assuming the components are in the same process, you can greatly simplify the interaction between them: clients of the service can simply cast the IBinder they receive from it to a concrete class published by the service.
当这样使用时,假设组件在同一个进程,你可以大大简化它们之间的相关作用:Service的客户端可以简单地抛出它们从一个具体的类接收到的IBinder。

An example of this use of a Service is shown here. First is the Service itself, publishing a custom class when bound:
这里展示了一个Service这样使用的例子。首先是Service自身,当绑定的时候建立了一个自定义的类:

public class LocalService extends Service {
    private NotificationManager mNM;

    // Unique Identification Number for the Notification.
    // We use it on Notification start, and to cancel it.
    private int NOTIFICATION = R.string.local_service_started;

    /**
     * Class for clients to access.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with
     * IPC.
     */
    public class LocalBinder extends Binder {
        LocalService getService() {
            return LocalService.this;
        }
    }

    @Override
    public void onCreate() {
        mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

        // Display a notification about us starting.  We put an icon in the status bar.
        showNotification();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("LocalService", "Received start id " + startId + ": " + intent);
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        // Cancel the persistent notification.
        mNM.cancel(NOTIFICATION);

        // Tell the user we stopped.
        Toast.makeText(this, R.string.local_service_stopped, Toast.LENGTH_SHORT).show();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    // This is the object that receives interactions from clients.  See
    // RemoteService for a more complete example.
    private final IBinder mBinder = new LocalBinder();

    /**
     * Show a notification while this service is running.
     */
    private void showNotification() {
        // In this sample, we'll use the same text for the ticker and the expanded notification
        CharSequence text = getText(R.string.local_service_started);

        // The PendingIntent to launch our activity if the user selects this notification
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                new Intent(this, LocalServiceActivities.Controller.class), 0);

        // Set the info for the views that show in the notification panel.
        Notification notification = new Notification.Builder(this)
                .setSmallIcon(R.drawable.stat_sample)  // the status icon
                .setTicker(text)  // the status text
                .setWhen(System.currentTimeMillis())  // the time stamp
                .setContentTitle(getText(R.string.local_service_label))  // the label of the entry
                .setContentText(text)  // the contents of the entry
                .setContentIntent(contentIntent)  // The intent to send when the entry is clicked
                .build();

        // Send the notification.
        mNM.notify(NOTIFICATION, notification);
    }
}

With that done, one can now write client code that directly accesses the running service, such as:
上面完成后,你现在可以写客户端代码直接访问运行中的Service,例如:

private LocalService mBoundService;

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.  Because we have bound to a explicit
        // service that we know is running in our own process, we can
        // cast its IBinder to a concrete class and directly access it.
        mBoundService = ((LocalService.LocalBinder)service).getService();

        // Tell the user about this for our demo.
        Toast.makeText(Binding.this, R.string.local_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.
        // Because it is running in our same process, we should never
        // see this happen.
        mBoundService = null;
        Toast.makeText(Binding.this, R.string.local_service_disconnected,
                Toast.LENGTH_SHORT).show();
    }
};

void doBindService() {
    // Establish a connection with the service.  We use an explicit
    // class name because we want a specific service implementation that
    // we know will be running in our own process (and thus won't be
    // supporting component replacement by other applications).
    bindService(new Intent(Binding.this, 
            LocalService.class), mConnection, Context.BIND_AUTO_CREATE);
    mIsBound = true;
}

void doUnbindService() {
    if (mIsBound) {
        // Detach our existing connection.
        unbindService(mConnection);
        mIsBound = false;
    }
}

@Override
protected void onDestroy() {
    super.onDestroy();
    doUnbindService();
}

Remote Messenger Service Sample

If you need to be able to write a Service that can perform complicated communication with clients in remote processes (beyond simply the use of Context.startService to send commands to it), then you can use the Messenger class instead of writing full AIDL files.
如果你需要写一个Service与其他进程通信来执行更复杂的交流(超过简单实用Context.startService来发送命令),你可以使用Messenger类来替代写完整的AIDL文件。

An example of a Service that uses Messenger as its client interface is shown here. First is the Service itself, publishing a Messenger to an internal Handler when bound:
一个使用Messenger作为客户端接口的例子在这里。首先是Service本身,建立一个Messenger作为内部Handler当绑定的时候:

public class MessengerService extends Service {
    /** For showing and hiding our notification. */
    NotificationManager mNM;
    /** Keeps track of all current registered clients. */
    ArrayList<Messenger> mClients = new ArrayList<Messenger>();
    /** Holds last value set by a client. */
    int mValue = 0;

    /**
     * Command to the service to register a client, receiving callbacks
     * from the service.  The Message's replyTo field must be a Messenger of
     * the client where callbacks should be sent.
     */
    static final int MSG_REGISTER_CLIENT = 1;

    /**
     * Command to the service to unregister a client, ot stop receiving callbacks
     * from the service.  The Message's replyTo field must be a Messenger of
     * the client as previously given with MSG_REGISTER_CLIENT.
     */
    static final int MSG_UNREGISTER_CLIENT = 2;

    /**
     * Command to service to set a new value.  This can be sent to the
     * service to supply a new value, and will be sent by the service to
     * any registered clients with the new value.
     */
    static final int MSG_SET_VALUE = 3;

    /**
     * Handler of incoming messages from clients.
     */
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_REGISTER_CLIENT:
                    mClients.add(msg.replyTo);
                    break;
                case MSG_UNREGISTER_CLIENT:
                    mClients.remove(msg.replyTo);
                    break;
                case MSG_SET_VALUE:
                    mValue = msg.arg1;
                    for (int i=mClients.size()-1; i>=0; i--) {
                        try {
                            mClients.get(i).send(Message.obtain(null,
                                    MSG_SET_VALUE, mValue, 0));
                        } catch (RemoteException e) {
                            // The client is dead.  Remove it from the list;
                            // we are going through the list from back to front
                            // so this is safe to do inside the loop.
                            mClients.remove(i);
                        }
                    }
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    }

    /**
     * Target we publish for clients to send messages to IncomingHandler.
     */
    final Messenger mMessenger = new Messenger(new IncomingHandler());

    @Override
    public void onCreate() {
        mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

        // Display a notification about us starting.
        showNotification();
    }

    @Override
    public void onDestroy() {
        // Cancel the persistent notification.
        mNM.cancel(R.string.remote_service_started);

        // Tell the user we stopped.
        Toast.makeText(this, R.string.remote_service_stopped, Toast.LENGTH_SHORT).show();
    }

    /**
     * When binding to the service, we return an interface to our messenger
     * for sending messages to the service.
     */
    @Override
    public IBinder onBind(Intent intent) {
        return mMessenger.getBinder();
    }

    /**
     * Show a notification while this service is running.
     */
    private void showNotification() {
        // In this sample, we'll use the same text for the ticker and the expanded notification
        CharSequence text = getText(R.string.remote_service_started);

        // The PendingIntent to launch our activity if the user selects this notification
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                new Intent(this, Controller.class), 0);

        // Set the info for the views that show in the notification panel.
        Notification notification = new Notification.Builder(this)
                .setSmallIcon(R.drawable.stat_sample)  // the status icon
                .setTicker(text)  // the status text
                .setWhen(System.currentTimeMillis())  // the time stamp
                .setContentTitle(getText(R.string.local_service_label))  // the label of the entry
                .setContentText(text)  // the contents of the entry
                .setContentIntent(contentIntent)  // The intent to send when the entry is clicked
                .build();

        // Send the notification.
        // We use a string id because it is a unique number.  We use it later to cancel.
        mNM.notify(R.string.remote_service_started, notification);
    }
}

If we want to make this service run in a remote process (instead of the standard one for its .apk), we can use android:process in its manifest tag to specify one:
如果我们要让这个Service在另一个进程工作(而不是标准的在它的.APK中),我们可以在manifest使用android:process。

<service android:name=".app.MessengerService"
        android:process=":remote" />

Note that the name “remote” chosen here is arbitrary, and you can use other names if you want additional processes. The ‘:’ prefix appends the name to your package’s standard process name.
“remote”是随便取的,你可以使用其他名字,“:”前缀是标准的进程名需要的。

With that done, clients can now bind to the service and send messages to it. Note that this allows clients to register with it to receive messages back as well:
完成后,客户端现在可以绑定Service发送消息。这也允许客户端注册和接受消息。

/** Messenger for communicating with service. */
Messenger mService = null;
/** Flag indicating whether we have called bind on the service. */
boolean mIsBound;
/** Some text view we are using to show state information. */
TextView mCallbackText;

/**
 * Handler of incoming messages from service.
 */
class IncomingHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MessengerService.MSG_SET_VALUE:
                mCallbackText.setText("Received from service: " + msg.arg1);
                break;
            default:
                super.handleMessage(msg);
        }
    }
}

/**
 * Target we publish for clients to send messages to IncomingHandler.
 */
final Messenger mMessenger = new Messenger(new IncomingHandler());

/**
 * 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 = new Messenger(service);
        mCallbackText.setText("Attached.");

        // We want to monitor the service for as long as we are
        // connected to it.
        try {
            Message msg = Message.obtain(null,
                    MessengerService.MSG_REGISTER_CLIENT);
            msg.replyTo = mMessenger;
            mService.send(msg);

            // Give it some value as an example.
            msg = Message.obtain(null,
                    MessengerService.MSG_SET_VALUE, this.hashCode(), 0);
            mService.send(msg);
        } 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;
        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();
    }
};

void doBindService() {
    // Establish a connection with the service.  We use an explicit
    // class name because there is no reason to be able to let other
    // applications replace our component.
    bindService(new Intent(Binding.this, 
            MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);
    mIsBound = true;
    mCallbackText.setText("Binding.");
}

void doUnbindService() {
    if (mIsBound) {
        // If we have received the service, and hence registered with
        // it, then now is the time to unregister.
        if (mService != null) {
            try {
                Message msg = Message.obtain(null,
                        MessengerService.MSG_UNREGISTER_CLIENT);
                msg.replyTo = mMessenger;
                mService.send(msg);
            } catch (RemoteException e) {
                // There is nothing special we need to do if the service
                // has crashed.
            }
        }

        // Detach our existing connection.
        unbindService(mConnection);
        mIsBound = false;
        mCallbackText.setText("Unbinding.");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值