Android Service组件

本文详细介绍了Android中的Service组件,包括其定义、生命周期、启动方式及权限管理等内容,并提供了本地服务和远程服务的具体实现案例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Service

Service继承了ContextWrapper,实现了componentCallbacks2接口
概述

概述

Service是应用程序的一个组件,用来实现应用程序中不与用户进行交互而且耗时的操作,或者用来支持其他应用程序的一些继承服务或功能。应用中每一个Service都必须相应的在AndroidManifest.xml文件中通过< service >标签进行声明。Services通过调用Context.startService()或Context.bindService()启动。

注:Service和应用程序中的其他对象一样,在主线程中运行,也就是说当Service执行一些耗费CPU资源的(Mp3后台播放)或者阻塞操作(网络操作)时,必须内部单独开一个线程执行相应的操作。详情可以参考进程与线程IntentService类是Service的一个标准实现,它拥有自己的线程来执行相应的操作。

Service的定义:
Service并不是一个单独的进程,Service对象并不表示它所存在的进程,除非特别的指定,它存在应用程序的进程当中。
Service也不是一个线程,也意味着它所做的任务在主线程中执行(所以要避免ANR)

当Service组件被创建后,系统会将会在主线程对其进行初始化,调用onCreate()方法,和其他相应的回调方法。Service所做的工作主要通过在回调方法中进行实现,比如创建一个辅助线程进行任务操作。

注:Service对象本身很简单,开发者可以根据需求执行前台交互的工作,或者仅仅针对一个Java对象进行相应方法的回调,或者使用AIDL提供一个远程接口。

Service生命周期:

有两种方法来启动Service。
1. 调用Context.startService(),然后系统会创建对象并回调Service.onCreate()方法,接着回调Service.onStartCommand(Intent, int, int)方法,方法中的参数有开发人员传入;然后Service会一直在后台运行至调用Context.stopService()和Service.stopSelf()。Context.startService()不会被嵌套,不论调用多少次Context.startService()方法,当Context.stopService()和Service.stopSelf()被调用时,Service就会停止。Service可以调用Service.stopSelf()方法来确保直到意图被处理完后再停止Service.

在启动Service时,有两种可选的操作模式,取决于Service.onStartCommand()的返回值

  • START_STICKY:代表根据需要显示的开始和停止Service
  • START_ NOT_STICKY :
  • START_ REDELIVER_INTENT:代表Service将一直运行至接收到相应的命令。
    1. 调用Context.bindService(),与Service打开一个持久连接,当Service不存在时进行创建,然后调用onCreate(),而不调用onStartCommand();与Service创建连接的对象将接收一个Service调用onBind()方法返回的IBinder对象,通过这个对象,可以回调Service内的方法。当连接被创建后,Service将一直处于运行状态,不论IBinder对象是否被引用。通常情况下,返回的IBinder对象是一个实现在aidl的复杂的接口。

Service可以同时被启动和绑定,在这样的情况下,Service将会一直运行只要有一个连接存在,这些连接添加了Context.BIND_ AUTO_CREATE标志。当上述的条件不满足时,Service将调用onDestroy()方法,进行销毁,所有的清理操作必须在onDestroy()返回前完成,比如终止线程,注销Receivers等等。

权限

如果想让其他应用能访问Service,必须在声明它的AndroidManifest.xml文件中进行配置,而想要调用该服务的应用也必须在其AndroidManifest.xml文件中进行权限的声明。
在GINGERBREAD版本中,当调用Context.startService(Intent)时,可以为传入的intent设置参数,赋予相应的权限,权限将保留着Service调用stopSelf(int)的命令或者更高层次的命令。或者Service已经被停止了。授予其他应用接入该Service并不要求权限来进行保护,甚至也不需要将Service声明wei exported。
另外,Service通过权限保护单独的进程间通信的回调。通过调用checkCallingPermission(String)方法在执行相应的回调方法之前。

执行生命周期:
当Service启动或者被绑定时,Android系统试图通过进程托管Service。当处于低内存或者需要杀死现存的进程时,进程托管Service的优先级将提升,处于以下的可能性时:
1. 当Service正在执行onCreate(),onStartCommand(),onDestroy()方法时,托管Service的进程会变成一个前台进程直到确保代码执行完之前不被杀死。
2. 当Service已经启动,托管Service的进程被认为重要性低于任何一个和在屏幕上用户可见的进程,却高于任何一个不可见的进程时。毕竟用户可见的进程很少,这就意味着,只有在内存极低的情况下Service才会被杀死。
3. 当Service被绑定后,托管Service的进程重要性高于绑定它的所有对象要高,换句话说,当绑定该Service的对象对用户可见,也就意味着Service对用户可见。
4. 启动的Service可以使用startForeground(int,Notification)接口,使Service处于前景状态,在这个状态下,系统认为用户会关注这个Service或者说Service将在低内存时不在被杀列表中。
注:当Service在极低内存的情况被杀死后,系统会在内存满足条件的情况下重启Service。一个重要的方法是在onStartCommand()中开启一个异步任务或者开启一个辅助线程执行工作,如果你希望Service被杀死时,任务继续执行。

其他应用的组件运行和Service运行在同一个进程中时,也可以提示托管Service的进程。

本地Service用例:
LocalService

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);
        // We want this service to continue running until it is explicitly
        // stopped, so return sticky.
        return START_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);

        // 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, LocalServiceActivities.Controller.class), 0);

        // Set the info for the views that show in the notification panel.
        notification.setLatestEventInfo(this, getText(R.string.local_service_label),
                       text, contentIntent);

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

使用LocalService的对象

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();
}

远程信息服务用例:
MessengerService

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);
    }
}

远程服务的声明:

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

调用服务的代码:

/** 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、付费专栏及课程。

余额充值