注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

民主与科学

独立之人格,自由之思想

 
 
 

日志

 
 

Service简介  

2010-06-15 20:05:35|  分类: Android基础 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
 public abstract class
Service
extends ContextWrapper
implements ComponentCallbacks
java.lang.Object
        android.content.Context
              android.content.ContextWrapper
                    android.app.Service
Class Overview
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 <service> declaration in its package's AndroidManifest.xml. Services can be started with Context.startService() and 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 Application Fundamentals: 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必须在AndroidManifest.xml中进行声明。可以通过Context.startService() and Context.bindService()来启动Service。Service也是运行在主要线程的。所以如果想要做些非常耗CPU(放MP3)或阻塞操作(网络),最好自己新建个线程来做这些工作。IntentService就是一个Intent的标准实现哦。它拥有它自己的线程。
什么是Service呢?
    有两个需要强调的概念是:
    * 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本身并没有运行在一个单独的进程上面。如果没有特殊的规定,它运行在它所在的那个应用程序的进程上面。
    * 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也不是个线程。他本身也运行在主线程中。它本身并不能避免应用程序没有响应的错误

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.
    Service只是告诉系统,它是运行在后台。调用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. 
    Service为进程之间通信提供了便利。可以通过调用Context.bindService()来实现。对于本地的通信也提供方便。
    对于本地通信也是通过Context.bindService(),只是不用提供AIDL来声明远程接口。

当Service被创建时,所有这些系统实际所做的是实例化该组件并调用它的OnCreate()和主线程上的任何其他合适的回调。
Service任何时候最多只有一个实例。多此次调用Context.startService,不会产生多个实例。通常,在Service中新建一个线程。让该线程来做些耗时的工作。

Service的本身生命周期
    1,当调用Context.startService()时,如果Service还没创建就会调用onCreate(),然后调用onStartCommand(Intent, int, int),
    如果已经创建,就不会掉用onCreate(),直接调用onStartCommand(Intent, int, int)。
    Service创建后直到调用Context.stopService()  or stopSelf()才回消亡。    如果使用stopSelf  (int startId)的话,它直到startId的那个Intent被执行完才消亡. 这里的startId对应于onStartCommand(Intent, int, int)的第三个参数startId。

    2,当Service启动后,它主要有三种运行模式。运行模式取决于从onStartCommand()中返回的值。
Constants
intSTART_CONTINUATION_MASKBits returned by onStartCommand(Intent, int, int) describing how to continue the service if it is killed.
intSTART_FLAG_REDELIVERYThis flag is set in onStartCommand(Intent, int, int) if the Intent is a re-delivery of a previously delivered intent, because the service had previously returned START_REDELIVER_INTENT but had been killed before calling stopSelf(int) for that Intent.
intSTART_FLAG_RETRYThis flag is set in onStartCommand(Intent, int, int) if the Intent is a a retry because the original attempt never got to or returned from onStartCommand(Intent, int, int).
intSTART_NOT_STICKYConstant to return from onStartCommand(Intent, int, int): if this service's process is killed while it is started (after returning from onStartCommand(Intent, int, int)), and there are no new start intents to deliver to it, then take the service out of the started state and don't recreate until a future explicit call to Context.startService(Intent).
intSTART_REDELIVER_INTENTConstant to return from onStartCommand(Intent, int, int): if this service's process is killed while it is started (after returning from onStartCommand(Intent, int, int)), then it will be scheduled for a restart and the last delivered Intent re-delivered to it again via onStartCommand(Intent, int, int).
intSTART_STICKYConstant to return from onStartCommand(Intent, int, int): if this service's process is killed while it is started (after returning from onStartCommand(Intent, int, int)), then leave it in the started state but don't retain this delivered intent.
intSTART_STICKY_COMPATIBILITYConstant to return from onStartCommand(Intent, int, int): compatibility version of START_STICKYthat does not guarantee that onStartCommand(Intent, int, int) will be called again after being killed.
    2.1,如果是START_STICKY就说明它是显式启动的,也要显式的来停止. 即如果它因为内存的原因被系统杀死了的话,系统可以让它重生。    当其进程因为System.exit(0);或android.os.Process.killProcess(android.os.Process.myPid())而结束后,系统会安排该service很快(大概5秒重生。但是通过手机的Setting->Application->Manage applications停止应用程序或Setting->Application->Running services来停止服务来杀死Service的话,系统并不会让安排该service重生。
注意它在被杀死时,不会保存已经发送了的Intent.如果重生时,没有未处理的Intent, 那么onStartCommand(Intent, int, int)中的Intent就是null,
    2.2,如果是START_NOT_STICKY ,当它因为内存的原因被系统杀死的时候,如果没有Intent需要传送。
    那么即使内存充足的是时候,它也不会立即被重新创建启动。它要直到Context.startService(Intent),才重新被创建启动。

    2.3,如果是START_REDELIVER_INTENT,当它因为内存的原因被系统杀死。那么内存充足的是时候,它立即被重新创建启动。
    这时它在被杀死钱前传递的那个Intent会再次传递到onStartCommand(Intent, int, int)中,因此其不可能Intent就是null

    3,客户也可以使用Context.bindService()来取得和服务的永久性链接. 如果服务没有启动, 那么这将创建它(调用onCreate())。
     使用
Context.bindService()时(无论此时service是否已经启动),不会调用onStartCommand(). 客户将获取IBinder对象, 这些对象由服务的onBind(Intent)方法返回,
     以便客户能够向服务发出调用. 只要链接建立, 服务就会一直运行(不管客户是否保留服务的IBinder的引用). 
     通常IBinder是使用aidl写成的一个复杂接口.    
    4,Service可以同时以start和绑定连接的方式使用。这时只要有start的没有stop,或至少有一个通过Context.BIND_AUTO_CREATE来绑定的连接没有断开,那么Service就不会调onDestroy()方法,也不会消亡。
Permissions
    如果一个服务在manifest中的<service>中声明一个服务的强制全局访问, 
    那么其它的应用程序必须在对应的<user-permission>元素中做相应权限的声明, 以便启动,停止或者绑定该服务.
    此外, 一个服务可以使用权限来保护一个IPC调用. 使用 checkCallingPermission(String) 方法.

Process Lifecycle 进程生命周期
    android系统会试图保持持有服务的进程运行, 只要该服务被启动或者有客户连接它. 
    当内存不足时, 持有服务的进程将有较高的优先级
   
 1,如果服务正在运行onCreate(), onStartCommand()或者onDestroy()的代码, 那么持有服务的进程将变为前台进程。
    它是不会被系统杀死的。

    2,当Service被创建后,他所驻留的进程虽然比可见的进程优先级低,但是它比不可见的进程高。
    因为大多数进程都是不可见的,所有Service也只会在内存非常低的时候才被系统杀死。

    3,如果有客户端绑定到了Service,那么该Service所驻留的优先级就不比该客户端的进程低。
    即如果该客户端是可见的话,那么该进程就和可见的线程的优先级一样。

    4,一个已启动的服务可以通过调研startForeground(int, Notification) API来将服务放在前台状态, 
    系统认为它是用户可见的, 因此在内存低的时候不会被kill.    当然从理论上来说它也可能在当前应用程序面临巨大内存不足的情况下被杀死,但一般不考虑这种情况。

    注意1:通过上面我们知道大部分服务在运行的时候, 它有可能被系统Kill掉. 这样, 系统之后会重启该服务. 
    如果你实现onStartCommand()来安排异步工作或者在另一个线程中工作,     那么你可能需要使用
START_FLAG_REDELIVERY来让系统重新发送一个 intent。这样如果你的服务在处理它的时候被Kill掉, Intent不会丢失.
    注意2:应用程序进程的优先级是由其包中正在运行的程序组件(service ,Activity)中最高者决定的。
主要函数
Public Methods
final ApplicationgetApplication()
Return the application that owns this service.
abstract IBinderonBind(Intent intent)
Return the communication channel to the service.
voidonConfigurationChanged(Configuration newConfig)
Called by the system when the device configuration changes while your component is running.
voidonCreate()
Called by the system when the service is first created.
voidonDestroy()
Called by the system to notify a Service that it is no longer used and is being removed.
voidonLowMemory()
This is called when the overall system is running low on memory, and would like actively running process to try to tighten their belt.
voidonRebind(Intent intent)
Called when new clients have connected to the service, after it had previously been notified that all had disconnected in itsonUnbind(Intent).
voidonStart(Intent intent, int startId)
This method is deprecated. Implement onStartCommand(Intent, int, int) instead.
intonStartCommand(Intent intent, int flags, int startId)
Called by the system every time a client explicitly starts the service by calling startService(Intent), providing the arguments it supplied and a unique integer token representing the start request.
voidonTaskRemoved(Intent rootIntent)
This is called if the service is currently running and the user has removed a task that comes from the service's application.
voidonTrimMemory(int level)
Called when the operating system has determined that it is a good time for a process to trim unneeded memory from its process.
booleanonUnbind(Intent intent)
Called when all clients have disconnected from a particular interface published by the service.
final voidstartForeground(int id, Notification notification)
Make this service run in the foreground, supplying the ongoing notification to be shown to the user while in this state
        //在4.3以上的设备上不能使用startForeground方法,会导致通知栏常驻一个“正在运行”的通知,造成不好的用户体验
        if(android.os.Build.VERSION.SDK_INT < 18){
            this.startForeground(NotificationUtil.NOTIFY_APP_LANUNCH__EMPTY, new Notification());
        }.

final void
stopForeground(boolean removeNotification)
Remove this service from foreground state, allowing it to be killed if more memory is needed.
final voidstopSelf()
Stop the service, if it was previously started.
final voidstopSelf(int startId)
Old version of stopSelfResult(int) that doesn't return a result.
final booleanstopSelfResult(int startId)
Stop the service if the most recent time it was started was startId.
如果startId是最后一个通过onStartCommand函数而传人的startId,那么就返回true并停止该Service,否则并不会停止该Service,而只是返回false
例1:start启动方式。并没处理什么实质的工作

        Button button3 = (Button) findViewById(R.id.Button03);
        OnClickListener listener3 = new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(Hello.this,MyService.class);
                startService(intent);
            }
        };
        button3.setOnClickListener(listener3);
        Button button4 = (Button) findViewById(R.id.Button04);
        OnClickListener listener4 = new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(Hello.this,MyService.class);
                stopService(intent);
            }
        };
        button4.setOnClickListener(listener4);

mainfest.xml文件中
<service android:name=".MyService"></service>
MyService.java文件

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
    String tag="hubin";
    @Override
    public void onCreate() {
        Log.i(tag,"oncreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(tag, "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() {
        Log.i(tag,"OnDestory");
    }
    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }
}

2:start启动方式。已经可以处理工作,但没有通信

public class MyService extends Service implements Runnable{
    String tag="hubin";
    @Override
    public void onCreate() {
        Log.i(tag,"oncreate");
    }

    @Override
    public int 
onStartCommand(Intent intent, int flags, int startId) {
        Log.i(tag, "Received start id " + startId + ": " + intent);
        // We want this service to continue running until it is explicitly
        // stopped, so return sticky.
        if(blRun==false)
        {
            Thread t=new Thread(this);
            t.start();
        }
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        blRun=false;
        Log.i(tag,"OnDestory");
    }

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    boolean blRun=false;
    final static int kSleepTime=5;
    public void run()
    {
        blRun=true;
        while(blRun)
        {
            Log.i(tag, "run"+System.currentTimeMillis());
            try{
            Thread.sleep(kSleepTime);
            }catch(InterruptedException e)
            {
                Log.e(tag, "InterruptedException", e);
            }
        }
    }

}

例3:启动方式。可以处理工作,虽然没有通信,但是已经可以通过Intent来发命令。
Intent intent=new Intent(Hello.this,MyService.class);
String value="Hello"+System.currentTimeMillis();
intent.putExtra("cmd", value);
startService(intent);

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service implements Runnable{
    String tag="hubin";
    @Override
    public void onCreate() {
        Log.i(tag,"oncreate");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(tag, "Received start id " + startId + ": " + intent);
        // We want this service to continue running until it is explicitly
        // stopped, so return sticky.
        if(blRun==false)
        {
            Thread t=new Thread(this);
            t.start();
        }
        if(intent!=null)
        {
            String cmd=intent.getStringExtra("cmd");
            if(cmd!=null)
            {
                addCmd(cmd);
            }

        }
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        blRun=false;
        Log.i(tag,"OnDestory");
    }

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }
    boolean blRun=false;
    final static int kSleepTime=5;
    final String cmdPool[]=new String[10];
    int cmdStartCursor=-1;
    int cmdEndCursor=-1;
    public void run()
    {
        blRun=true;
        while(blRun)
        {
            if(cmdStartCursor!=cmdEndCursor)
            {
                cmdStartCursor=(cmdStartCursor+1)%cmdPool.length;
                Log.i(tag, "run:"+cmdPool[cmdStartCursor]);
            }
            try{
            Thread.sleep(kSleepTime);
            }catch(InterruptedException e)
            {
                Log.e(tag, "InterruptedException", e);
            }
        }
    }
    void addCmd(String cmd)
    {
        if((cmdEndCursor+1)%cmdPool.length!=cmdStartCursor)
        {
            cmdEndCursor++;
            cmdEndCursor=cmdEndCursor%cmdPool.length;
            cmdPool[cmdEndCursor]=cmd;
        }        
    }
}


例4:绑定方式。可以处理工作,实现了进程的本地通信
MyService.java文件

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service implements Runnable{
    final static String tag="robin";
    @Override
    public void onCreate() {
        Log.i(tag,"oncreate");
            Thread t=new Thread(this);
            t.start();
    }

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

    @Override
    public void onDestroy() {
        blRun=false;
        Log.i(tag,"OnDestory");
    }
    /**
     * 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 {
        MyService getService() {
            return MyService.this;
        }
    }
    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return mBinder;
    }

    // This is the object that receives interactions from clients.  See
    // RemoteService for a more complete example.
    private final IBinder mBinder = new LocalBinder();
    boolean blRun=false;
    final static int kSleepTime=5;
    final String cmdPool[]=new String[10];
    int cmdStartCursor=-1;
    int cmdEndCursor=-1;
    public void run()
    {
        blRun=true;
        while(blRun)
        {
            if(cmdStartCursor!=cmdEndCursor)
            {
                cmdStartCursor=(cmdStartCursor+1)%cmdPool.length;
                Log.i(tag, "run:"+cmdPool[cmdStartCursor]);
            }
            try{
            Thread.sleep(kSleepTime);
            }catch(InterruptedException e)
            {
                Log.e(tag, "InterruptedException", e);
            }
        }
    }
    void addCmd(String cmd)
    {
        if((cmdEndCursor+1)%cmdPool.length!=cmdStartCursor)
        {
            cmdEndCursor++;
            cmdEndCursor=cmdEndCursor%cmdPool.length;
            cmdPool[cmdEndCursor]=cmd;
        }        
    }

Hello.java文件

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.util.Log;
public class Hello extends Activity {
    final static String tag="hubin";
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ..............................
        Button button4 = (Button) findViewById(R.id.Button04);
        OnClickListener listener4 = new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(Hello.this,MyService.class);
                
stopService(intent);
            }
        };
        button4.setOnClickListener(listener4);
        
        Button button5 = (Button) findViewById(R.id.Button05);
        OnClickListener listener5 = new OnClickListener() {
            @Override
            public void onClick(View v) {
                doBindService();
            }
        };
        button5.setOnClickListener(listener5);
        Button button6 = (Button) findViewById(R.id.Button06);
        OnClickListener listener6 = new OnClickListener() {
            @Override
            public void onClick(View v) {
                doUnbindService();
            }
        };
        button6.setOnClickListener(listener6);

        Button button7 = (Button) findViewById(R.id.Button07);
        OnClickListener listener7 = new OnClickListener() {
            @Override
            public void onClick(View v) {
                if(mBoundService==null)
                {
                    Log.i(tag,"the Service has not bind!Please bind the service first");
                    return;
                }
                String cmd="Hello:"+System.currentTimeMillis()%100;
                mBoundService.addCmd(cmd);
            }
        };
        button7.setOnClickListener(listener7);
    }
    private MyService mBoundService;

    private ServiceConnection mConnection = new ServiceConnection() {
        public void 
onServiceConnected(ComponentName className, IBinder service) {
            mBoundService = ((MyService.LocalBinder)service).getService();
        }

        public void 
onServiceDisconnected(ComponentName className) {
            mBoundService = null;
        }
    };

    boolean mIsBound=true;
    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(Hello.this, 
                MyService.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();
    }
}

注意:   使用Context.bindService()时(无论此时service是否已经启动),不会调用onStartCommand(). 
例5:绑定方式,通过Handler来实现跨进程简单通信
文件TakeScreenshotService.java (frameworks\base\packages\systemui\src\com\android\systemui\screenshot)

public class TakeScreenshotService extends Service {
    private static final String TAG = "TakeScreenshotService";

    private static GlobalScreenshot mScreenshot;

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    final Messenger callback = msg.replyTo;
                    if (mScreenshot == null) {
                        mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);
                    }
                    mScreenshot.takeScreenshot(new Runnable() {
                        @Override public void run() {
                            Message reply = Message.obtain(null, 1);
                            try {
                                callback.send(reply);
                            } catch (RemoteException e) {
                            }
                        }
                    }, msg.arg1 > 0, msg.arg2 > 0);
            }
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return new Messenger(mHandler).getBinder();
    }
}

文件PhoneWindowManager.java (frameworks\base\policy\src\com\android\internal\policy\impl)
// Assume this is called from the Handler thread.

    private void takeScreenshot() {
        synchronized (mScreenshotLock) {
            if (mScreenshotConnection != null) {
                return;
            }
            ComponentName cn = new ComponentName("com.android.systemui",
                    "com.android.systemui.screenshot.TakeScreenshotService");
            Intent intent = new Intent();
            intent.setComponent(cn);
            ServiceConnection conn = new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName name, IBinder service) {
                    synchronized (mScreenshotLock) {
                        if (mScreenshotConnection != this) {
                            return;
                        }
                        Messenger messenger = new Messenger(service);
                        Message msg = Message.obtain(null, 1);
                        final ServiceConnection myConn = this;
                        Handler h = new Handler(mHandler.getLooper()) {
                            @Override
                            public void handleMessage(Message msg) {
                                synchronized (mScreenshotLock) {
                                    if (mScreenshotConnection == myConn) {
                                        mContext.unbindService(mScreenshotConnection);
                                        mScreenshotConnection = null;
                                        mHandler.removeCallbacks(mScreenshotTimeout);
                                    }
                                }
                            }
                        };
                        msg.replyTo = new Messenger(h);
                        msg.arg1 = msg.arg2 = 0;
                        if (mStatusBar != null && mStatusBar.isVisibleLw())
                            msg.arg1 = 1;
                        if (mNavigationBar != null && mNavigationBar.isVisibleLw())
                            msg.arg2 = 1;
                        try {
                            messenger.send(msg);
                        } catch (RemoteException e) {
                        }
                    }
                }
                @Override
                public void onServiceDisconnected(ComponentName name) {}
            };
            if (mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)) {
                mScreenshotConnection = conn;
                mHandler.postDelayed(mScreenshotTimeout, 10000);
            }
        }
    }


例6:绑定方式。可以处理工作,实现了两个进程的通信
具体参照《AIDL和Service实现两进程通信
  评论这张
 
阅读(2223)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017