Android Service

分享到:

Service(服务)是一个没有用户界面的在后台运行执行耗时操作的应用组件。其他应用组件能够启动Service,并且当用户切换到另外的应用场景,Service将持续在后台运行。另外,一个组件能够绑定到一个service与之交互(IPC机制),例如,一个service可能会处理网络操作,播放音乐,操作文件I/O或者与内容提供者(content provider)交互,所有这些活动都是在后台进行。Service有两种形式,"启动的"和"绑定"

一、Android Service的两种启动形式 startService() 和 bindService()

通过startService()启动的服务处于"启动的"状态,一旦启动,service就在后台运行,即使启动它的应用组件已经被销毁了。通常started状态的service执行单任务并且不返回任何结果给启动者。比如当下载或上传一个文件,当这项操作完成时,service应该停止它本身。

还有一种"绑定"状态的service,通过调用bindService()来启动,一个绑定的service提供一个允许组件与service交互的接口,可以发送请求、获取返回结果,还可以通过夸进程通信来交互(IPC)。绑定的service只有当应用组件绑定后才能运行,多个组件可以绑定一个service,当调用unbind()方法时,这个service就会被销毁了。

service与activity一样都存在与当前进程的主线程中,所以一些阻塞UI的操作,比如耗时操作不能放在service里进行,比如另外开启一个线程来处理诸如网络请求的耗时操作。如果在service里进行一些耗CPU和耗时操作,可能会引发ANR警告,这时应用会弹出是强制关闭还是等待的对话框。所以,对service的理解就是和activity平级的,只不过是看不见的,在后台运行的一个组件。

二、Android Service生命周期

 

 

通过这个图可以看到,两种启动service的方式以及他们的生命周期,bind service的不同之处在于当绑定的组件销毁后,对应的service也就被kill了。service的声明周期相比与activity的简单了许多,只要好好理解两种启动service方式的异同就行。

service生命周期也涉及一些回调方法,这些方法都不用调用父类方法,代码如下:

public class ExampleService extends Service {
    int mStartMode;       // indicates how to behave if the service is killed
    IBinder mBinder;      // interface for clients that bind
    boolean mAllowRebind; // indicates whether onRebind should be used

    @Override
    public void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return mStartMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return mAllowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // The service is no longer used and is being destroyed
    }
}

关于停止Service,如果service是非绑定的,最终当任务完成时,为了节省系统资源,一定要停止service,可以通过stopSelf()来停止,也可以在其他组件中通过stopService()来停止,绑定的service可以通过onUnBind()来停止service。

三、Service的子类 IntentService

IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent,对于异步的startService请求,IntentService会处理完成一个之后再处理第二个,每一个请求都会在一个单独的worker thread中处理,不会阻塞应用程序的主线程,这里就给我们提供了一个思路,如果有耗时的操作与其在Service里面开启新线程还不如使用IntentService来处理耗时操作。而在一般的继承Service里面如果要进行耗时操作就必须另开线程,但是使用IntentService就可以直接在里面进行耗时操作,因为默认实现了一个worker thread。对于异步的startService请求,IntentService会处理完成一个之后再处理第二个。
看下IntentService的具体代码实现:

public class HelloIntentService extends IntentService {

  /** 
   * A constructor is required, and must call the super IntentService(String)
   * constructor with a name for the worker thread.
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }

  /**
   * The IntentService calls this method from the default worker thread with
   * the intent that started the service. When this method returns, IntentService
   * stops the service, as appropriate.
   */
  @Override
  protected void onHandleIntent(Intent intent) {
      // Normally we would do some work here, like download a file.
      // For our sample, we just sleep for 5 seconds.
      long endTime = System.currentTimeMillis() + 5*1000;
      while (System.currentTimeMillis() < endTime) {
          synchronized (this) {
              try {
                  wait(endTime - System.currentTimeMillis());
              } catch (Exception e) {
              }
          }
      }
  }
}

四、Service实例(本例代码来源于网络)

下面通过一个代码实例来进一步了解Service的运行原理,代码如下:

// activity 的onCreate()
  
@Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
  
        startSer1 = (Button) findViewById(R.id.startSer1);  
        stopSer1 = (Button) findViewById(R.id.stopSer1);  
  
        startSer2 = (Button) findViewById(R.id.startSer2);  
        stopSer2 = (Button) findViewById(R.id.stopSer2);  
  
        log = (TextView) findViewById(R.id.log);  
  
        logView = (ScrollView) findViewById(R.id.logView);  
  
        startSer1.setOnClickListener(btnListener);  
        stopSer1.setOnClickListener(btnListener);  
  
        startSer2.setOnClickListener(btnListener);  
        stopSer2.setOnClickListener(btnListener);  
  
        intent = new Intent(MyServiceActivity.this, IntentServiceDemo.class);  
  
        // 打印出主线程的ID  
        long id = Thread.currentThread().getId();  
        updateLog(TAG + " ----> onCreate() in thread id: " + id);  
    }  
// service 代码 
 
package com.archer.rainbow;  
  
import java.text.SimpleDateFormat;  
import java.util.Date;  
  
import android.app.IntentService;  
import android.content.Intent;  
  
public class IntentServiceDemo extends IntentService {  
    private static final String TAG = "IntentServiceDemo";  
    private static final SimpleDateFormat SDF_DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss.SSS");  
  
    public IntentServiceDemo() {  
        super(TAG);  
        MyServiceActivity.updateLog(TAG + " ----> constructor");  
    }  
  
    @Override  
    public void onCreate() {  
        super.onCreate();  
  
        // 打印出该Service所在线程的ID  
        long id = Thread.currentThread().getId();  
        MyServiceActivity.updateLog(TAG + " ----> onCreate() in thread id: "  
                + id);  
    }  
  
    @Override  
    public void onDestroy() {  
        super.onDestroy();  
        MyServiceActivity.updateLog(TAG + " ----> onDestroy()");  
    }  
  
    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {  
        MyServiceActivity.updateLog(TAG + " ----> onStartCommand()");  
        // 记录发送此请求的时间  
        intent.putExtra("time", System.currentTimeMillis());  
        return super.onStartCommand(intent, flags, startId);  
    }  
  
    @Override  
    public void setIntentRedelivery(boolean enabled) {  
        MyServiceActivity.updateLog(TAG + " ----> setIntentRedelivery()");  
        super.setIntentRedelivery(enabled);  
    }  
  
    @Override  
    protected void onHandleIntent(Intent intent) {  
        // 打印出处理intent所用的线程的ID  
        long id = Thread.currentThread().getId();  
        MyServiceActivity.updateLog(TAG  
                + " ----> onHandleIntent() in thread id: " + id);  
        long time = intent.getLongExtra("time", 0);  
        Date date = new Date(time);  
        try {  
            // 打印出每个请求对应的触发时间  
            MyServiceActivity.updateLog(TAG  
                    + " ----> onHandleIntent(): 下载文件中..." + SDF_DATE_FORMAT.format(date));  
            Thread.sleep(3000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  
  
}  

代码运行起来界面如下图:

 

 

从左图可以看出,主线程(UI线程)的ID是1。接,连续点击三次Start Service 1 按钮,得到右侧画面。可以看出,IntentServiceDemo的onCreate()所处的线程ID仍为1,说明它是在主线程中被执行的,且只被执行一次。然后,我每点击一次按钮,它都会触发一下onStartCommand()方法。仔细看第二次与第三次的onCommand()方法以及onHandleIntent()打印出来的语句,你会发现,第二、三两次点击按钮与第一次点击按钮的时间是没有超过3秒钟的,它们是连续被执行的,这说明了什么呢?说明,在第一个intent被处理时(即onHandleIntent()处于运行中),该Service仍然可以接受新的请求,但接受到新的请求后并没有立即执行,而是将它们放入了工作队列中,等待被执行。

五、BindService实例(本例代码来源于网络)

BindService和Started Service都是Service,有什么不同呢:

1. Started Service中使用StartService()方法来进行方法的调用,调用者和服务之间没有联系,即使调用者退出了,服务依然在进行【onCreate()- >onStartCommand()->startService()->onDestroy()】,注意其中没有onStart(),主要是被onStartCommand()方法给取代了,onStart方法不推荐使用了。
2. BindService中使用bindService()方法来绑定服务,调用者和绑定者绑在一起,调用者一旦退出服务也就终止了【onCreate()->onBind()->onUnbind()->onDestroy()】。
一个简单的BindService实现代码如下:

//Activity中的代码如下:

package com.zys.service;

import com.zys.service.BindService.MyBinder;

import android.R.bool;
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.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {
    private Button startBtn;
    private Button stopBtn;
    private boolean flag;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        flag = false;
        //设置
        startBtn = (Button)this.findViewById(R.id.startBtn);
        stopBtn = (Button)this.findViewById(R.id.stopBtn);
        startBtn.setOnClickListener(listener);
        stopBtn.setOnClickListener(listener);
    }
    
    private OnClickListener listener = new OnClickListener() {
        
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            switch (v.getId()) {
            case R.id.startBtn:
                bindService();
                break;
            case R.id.stopBtn:
                unBind();
                break;
            default:
                break;
            }
        }
        
        
    };
    
    private void bindService(){
        Intent intent = new Intent(MainActivity.this,BindService.class);
        bindService(intent, conn, Context.BIND_AUTO_CREATE);
    }
    
    private void unBind(){
        if(flag == true){
            unbindService(conn);
            flag = false;
        }
    }
    
    private ServiceConnection conn = new ServiceConnection() {
        
        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub
            
        }
        
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub
            MyBinder binder = (MyBinder)service;
            BindService bindService = binder.getService();
            bindService.MyMethod();
            flag = true;
        }
    };
    
}
//BindService代码

package com.zys.service;

import java.io.FileDescriptor;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;

public class BindService extends Service {

    private static final String TAG = "BindService";

    public void MyMethod(){
        Log.i(TAG, "BindService-->MyMethod()");
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return myBinder;
    }
    
    public class MyBinder extends Binder{
        
        public BindService getService(){
            return BindService.this;
        }
    }
    
    private MyBinder myBinder = new MyBinder();
}

由于Android 中的Service使用了onBind 的方法去绑定服务,返回一个Ibinder对象进行操作,而我们要获取具体的Service方法的内容的时候,我们需要Ibinder对象返回具体的Service对象才能操作,所以说具体的Service对象必须首先实现Binder对象,这个样子的话我们才能利用bindService的方法对Service进行绑定,获取Binder对象之后获取具体的Service对象,然后才获取Service中的方法等等。所以我们需要注意的是bindService的方式去绑定服务获取的必定是实现了Binder的对象,所以这是我们必须使用Binder的方式去获取Service的方式而不是直接使用Service的类,这个是Android内部实现所约束的。

方法过程如下:

Intent intent = new Intent(MainActivity.this,BindService.class)->新建了BindService对象->新建了MyBinder对象

->bindService(intent, conn, Context.BIND_AUTO_CREATE);->onBind()函数 -----传递MyBinder对象------->onServiceConnected()

--> 通过传递的Binder对象获取刚刚和Binder对象对应的BindService 对象  -->调用Service中定义的方法。

这个其中必须通过Binder对象,因为是通过Binder对象来传递的,通过Binder对象获取Service对象,然后获取所需的服务,所以Service必须实现Binder,以便传递和使用。

以上就是Android Service组件的基本原理和简单的使用方法,如需要进一步了解Service组件请访问http://developer.android.com/guide/components/services.html

昵    称:
验证码:

相关文档:

Android组件
Android基础知识
Android控件
Android实例