Android Doc学习之Service

来源:互联网 发布:直播跳舞的软件 编辑:程序博客网 时间:2024/06/05 06:19

Service,简单的理解就是一个没有UI界面的应用程序组件,它适合于执行长时间运行的操作。


它有两种形式:

1、Started:通过startService()启动,一旦启动,如果没有显式stop的话,它就会一直执行下去,即使程序退出

2、Bound:通过bindService()启动,它一般用于C/S模式:客户端发送请求,并从服务端返回结果。可用于跨进程之间的通讯,当没有绑定该Service的任何客户端时,这个Service便会自动销毁

虽然Service被分为这两种形式,但一个Service可以同时以这2种形式提供服务,只不过在提供不同服务的时候是选择执行onStartCommand()还是onBind()方法.


要创建Service,可以选择继承以下两个类:

1、Service,它是所有Service的基类,包括IntentService,但在使用的过程中要注意线程安全

2、IntentService,基于线程考虑而退出的Service的子类,通过查看它的源码,可知是通过Handler消息机制保证线程的安全,在使用过程中,只需要重写onHandleIntent()方法处理Intent


两种形式的Service的创建与销毁

创建

1、Started: 通过startService创建,有两种情况:

如果该Service未在后台运行,则调用onCreate() -> onStartCommand()

如果该Service已经在后台运行,则条用onStartCommand()

2、Bound:通过bindService创建,该Service必须提供onBind方法的实现

销毁:

1、Started: stopSelf()或者stopService(),注意,当有同时有多个请求给onStartCommand时,不能立刻stop该Service,因为处理完一个请求后可能还有另外一个请求,如果直接stop,那就会影响到第二个请求。正确的做法是:使用stopSelf(id),该id是通过onStartCommand传紧来的Service的id

2、Bound:通过unBindService()

两种形式的Service的生命周期:



Bound Service:

在Service必须实现onBind()接口并且返回IBinder对象。client通过bindService()访问Service,而且client要通过ServiceConnection建立与Service的连接,当连接建立成功后,会调用 onServiceConnected()。 注意:建立连接时一个异步的过程,所以在bindService()方法调用后并不能立刻建立连接,不能立刻使用Service所提供的服务。在Actviity的onCreate()使用会报异常,要在Activity的onResume()后使用Service所提供的服务。

Bound Service的创建:

为了创建Bound Service,必须提供实现IBinder接口的对象,有3种方式提供这样的接口:

1、通过继承Binder类: 此时client和service运行在同一个进程中,使用该方法时,Service几乎不是一个后台的工作者,如果要和其他进程进行交互,那就要使用其他方式。

2、使用Messager:此方法可以进程间通讯,该方法使用Handler实现消息的传递,这是最简单的IPC通讯,因为使用了Handler,每次只有一个任务执行,保证了线程安全。

3、使用AIDL:该方法可以进程间 通讯,并且可通过并发处理多个任务请求。未了使用AIDL,你必须创建一个.aidl文件,并定义一些接口,此时android会自动创建一个实现该接口的抽象类,在使用的时候,继承android自动创建的这个类,便可提供服务。


实例演示:

1、继承自Binder类

建立步骤

  • 建立一个Binder的子类实例
  • 通过onBinder返回该实例
  • 在Activity的onServiceConnected()获得该binder

public class LocalService extends Service {    // Binder given to clients    private final IBinder mBinder = new LocalBinder();    // Random number generator    private final Random mGenerator = new Random();    /**     * Class used for the client Binder.  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 this instance of LocalService so clients can call public methods            return LocalService.this;        }    }    @Override    public IBinder onBind(Intent intent) {        return mBinder;    }    /** method for clients */    public int getRandomNumber() {      return mGenerator.nextInt(100);    }}

public class BindingActivity extends Activity {    LocalService mService;    boolean mBound = false;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);    }    @Override    protected void onStart() {        super.onStart();        // Bind to LocalService        Intent intent = new Intent(this, LocalService.class);        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);    }    @Override    protected void onStop() {        super.onStop();        // Unbind from the service        if (mBound) {            unbindService(mConnection);            mBound = false;        }    }    /** Called when a button is clicked (the button in the layout file attaches to      * this method with the android:onClick attribute) */    public void onButtonClick(View v) {        if (mBound) {            // Call a method from the LocalService.            // However, if this call were something that might hang, then this request should            // occur in a separate thread to avoid slowing down the activity performance.            int num = mService.getRandomNumber();            Toast.makeText(this, "number: " + num, Toast.LENGTH_SHORT).show();        }    }    /** Defines callbacks for service binding, passed to bindService() */    private ServiceConnection mConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName className,                IBinder service) {            // We've bound to LocalService, cast the IBinder and get LocalService instance            LocalBinder binder = (LocalBinder) service;            mService = binder.getService();            mBound = true;        }        @Override        public void onServiceDisconnected(ComponentName arg0) {            mBound = false;        }    };}

2、使用Messenger

如何使用:

  • Service创建一个可以从client接收请求的Handler
  • 该Handler用于创建一个Messager
  • Messager创建了onBind()所需要的IBinder对象
  • client使用IBinder对象初始化Messager(引用Service的Handler),然后使用它给Service传递消息
  • Service在Handler的handleMessage()接收消息

public class MessengerService extends Service {    /** Command to the service to display a message */    static final int MSG_SAY_HELLO = 1;    /**     * Handler of incoming messages from clients.     */    class IncomingHandler extends Handler {        @Override        public void handleMessage(Message msg) {            switch (msg.what) {                case MSG_SAY_HELLO:                    Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();                    break;                default:                    super.handleMessage(msg);            }        }    }    /**     * Target we publish for clients to send messages to IncomingHandler.     */    final Messenger mMessenger = new Messenger(new IncomingHandler());    /**     * When binding to the service, we return an interface to our messenger     * for sending messages to the service.     */    @Override    public IBinder onBind(Intent intent) {        Toast.makeText(getApplicationContext(), "binding", Toast.LENGTH_SHORT).show();        return mMessenger.getBinder();    }}

public class ActivityMessenger extends Activity {    /** Messenger for communicating with the service. */    Messenger mService = null;    /** Flag indicating whether we have called bind on the service. */    boolean mBound;    /**     * 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 object we can use to            // interact with the service.  We are communicating with the            // service using a Messenger, so here we get a client-side            // representation of that from the raw IBinder object.            mService = new Messenger(service);            mBound = true;        }        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;            mBound = false;        }    };    public void sayHello(View v) {        if (!mBound) return;        // Create and send a message to the service, using a supported 'what' value        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);        try {            mService.send(msg);        } catch (RemoteException e) {            e.printStackTrace();        }    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);    }    @Override    protected void onStart() {        super.onStart();        // Bind to the service        bindService(new Intent(this, MessengerService.class), mConnection,            Context.BIND_AUTO_CREATE);    }    @Override    protected void onStop() {        super.onStop();        // Unbind from the service        if (mBound) {            unbindService(mConnection);            mBound = false;        }    }}

注:在该例子中,Service客户端不能接收来自于Service的消息,如果要使用双向的消息可如下实现ApiDemo的(MessengerService.java (service) 、MessengerServiceActivities.java (client)):


MessengerService.javaThe file containing the source code shown below is located in the corresponding directory in <sdk>/samples/android-<version>/.../* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.example.android.apis.app;import android.app.Notification;import android.app.NotificationManager;import android.app.PendingIntent;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.util.Log;import android.widget.Toast;import java.util.ArrayList;// Need the following import to get access to the app resources, since this// class is in a sub-package.import com.example.android.apis.R;import com.example.android.apis.app.RemoteService.Controller;/** * This is an example of implementing an application service that uses the * {@link Messenger} class for communicating with clients.  This allows for * remote interaction with a service, without needing to define an AIDL * interface. * * <p>Notice the use of the {@link NotificationManager} when interesting things * happen in the service.  This is generally how background services should * interact with the user, rather than doing something more disruptive such as * calling startActivity(). */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);        // Set the icon, scrolling text and timestamp        Notification notification = new Notification(R.drawable.stat_sample, text,                System.currentTimeMillis());        // 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.setLatestEventInfo(this, getText(R.string.remote_service_label),                       text, contentIntent);        // 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);    }}

MessengerServiceActivities.javaThe file containing the source code shown below is located in the corresponding directory in <sdk>/samples/android-<version>/...package com.example.android.apis.app;import com.example.android.apis.R;import com.example.android.apis.app.LocalServiceActivities.Binding;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.Handler;import android.os.IBinder;import android.os.Message;import android.os.Messenger;import android.os.RemoteException;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;public class MessengerServiceActivities {    /**     * Example of binding and unbinding to the remote service.     * This demonstrates the implementation of a service which the client will     * bind to, interacting with it through an aidl interface.</p>     *      * <p>Note that this is implemented as an inner class only keep the sample     * all together; typically this code would appear in some separate class.     */    public static class Binding extends Activity {        /** 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.");            }        }        /**         * 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.messenger_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);            mCallbackText = (TextView)findViewById(R.id.callback);            mCallbackText.setText("Not attached.");        }        private OnClickListener mBindListener = new OnClickListener() {            public void onClick(View v) {                doBindService();            }        };        private OnClickListener mUnbindListener = new OnClickListener() {            public void onClick(View v) {                doUnbindService();            }        };    }}


3、AIDL(略)

Service状态转换流程:



注意事项:

1、记得在调用bind的同时,也不要忘记调用unbind

2、如果你只需要Service在Activity可见的情况下运行,可在onStart()下绑定,在onStop()下解绑,其他同理

3、注意在onResume()和onPause()中绑定和解码Service的使用,因为如果有多个Activity都绑定到该服务,那么该服务便会频繁的绑定和解码,会消耗大量资源






原创粉丝点击