[Android基础]Service

一、

Service主要有两种用途:

1.执行耗时操作。因为Service是工作在UI线程(即主线程)中的,所以当想在Service中执行耗时操作,应该新建一个线程。

2.用于组件之间的交互。通过将某些功能以Service组件的形式进行封装,然后提供给其他应用组件调用。


二、

Service的生命周期:

Service有两种调用的方式,根据调用方式的不同,有不同的生命周期。


1.启动模式(即startService())

如果Service用于执行长时间运行的操作,则一般采用启动模式。

如果当前指定的Service实例没有被创建,则调用Service的onCreate()来创建一个实例。

否则直接调用Service的onStartCommand()来运行Service。因此Service的onStartCommand()可能会重复调用多次。所以在onStartCommand()中要注意线程同步。

[Android基础]Service_第1张图片


2.绑定模式(即bindService())

如果Service用于提供一种封装的功能供其他组件使用,则一般采用绑定模式。

如果当前指定的Service实例没有被创建,则调用Service的onCreate()来创建一个实例。

实例启动后,将调用onBind()。onBind将返回一个IBinder接口实例,IBinder允许客户端回调Service的方法。在绑定模式下,Android将调用者(如Activity)和Service绑定在一起,当调用者退出时,Service先后调用onUnbind()和onDestroy()退出。注意onBind只一次,不可多次绑定。

[Android基础]Service_第2张图片


三、

启动模式下的Service:

重点就是onStartCommand()了:

@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// TODO Auto-generated method stub
		return super.onStartCommand(intent, flags, startId);
	}

它的返回值可以取:

START_NOT_STICKY

如果Service在它启动后(从onStartCommand()返回后)被kill掉,那么它将不会被重启。适用场景:网上下载数据。

START_REDELIVER_INTENT

如果Service在它启动后(从onStartCommand()返回后)被kill掉,那么它将会被重启(onCreate()方法会执行),onStartCommand()会执行。并且最后传给它的Intent通过onStartCommand()会被重新传给它。这种模式保证了传递给它的Intent一定会被处理完毕。适用场景:关键业务处理。

START_STICKY

如果Service在它启动后(从onStartCommand()返回后)被kill掉,那么它将会被重启(onCreate()方法会执行),onStartCommand()不会执行。但是Intent不被保留,此时Intent的值为null。适用场景:后台播放音乐。



同时注意的是onStartCommand()中的多请求下的线程同步。

在开发Service组件的过程中,经常要涉及线程及线程同步等复杂的问题。这是我们可以使用IntentService(继承Service)。

IntentService:异步处理服务,新开一个线程,当完成所有的任务以后自己关闭。

IntentService有以下特点:

1.创建一个工作队列,它每次将一个Intent传递到onHandleIntent(),解决了同步的问题。

2.当所有请求被处理完成后,将自动停止服务。

3.提供了一个返回null的onBind()方法的默认实现。

4.提供了onStartCommand()方法的默认实现,它将所有的Intent发送到一个工作队列,并进一步发送到onHandleIntent()方法。

继承IntentService的类至少要实现两个函数:构造函数和onHandleIntent()函数。要覆盖IntentService的其它函数时,注意要通过super调用父类的对应的函数。


下面用一个例子展示一下:

package com.example.test;

import java.text.SimpleDateFormat;

import android.app.IntentService;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

/*
 * IntentService注意点:
 * 1.通过一个无参数的构造方法,并在方法中调用超类中以字符串为参数的构造方法
 * 其中字符串被用来作为IntentService的工作线程的名称
 * 2.可以覆盖onCreate(),onDestory()等方法,不过必须在方法的最后调用超类
 * 的对应方法的实现,否则将抛出意外
 */
public class TestService extends IntentService {

	private int span;
	
	public TestService() {
		super("TestService");
	}

	@Override
	protected void onHandleIntent(Intent intent) {
		Log.v("onHandleIntent", "服务启动时间" + getCurrentTime());
		Bundle bundle = intent.getBundleExtra("bundle");
		span = bundle.getInt("waitTime");
		long endTime = System.currentTimeMillis() + span * 1000;
		
		Log.v("onHandleIntent", "服务持续时间" + span);
		while (System.currentTimeMillis() <  endTime) 
		{
			try 
			{
				synchronized (this) 
				{
					wait(endTime - System.currentTimeMillis());
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	@Override
	public void onDestroy() {
		Log.v("onHandleIntent", "服务摧毁时间" + getCurrentTime());
		super.onDestroy();
	}
	
	private String getCurrentTime() 
	{
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String date = sdf.format(new java.util.Date());
		return date;
	}
}

package com.example.test;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		((Button) findViewById(R.id.start)).setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				Intent intent = new Intent(MainActivity.this,TestService.class);
				Bundle bundle = new Bundle();
				
				double a = Math.random() * 10;
				a = Math.ceil(a);
				int randomNum = new Double(a).intValue();
				bundle.putInt("waitTime", randomNum);
				intent.putExtra("bundle", bundle);
//				Toast.makeText(getApplicationContext(), randomNum + "", Toast.LENGTH_SHORT).show();
				startService(intent);
			}
		});
		
		((Button) findViewById(R.id.end)).setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				stopService(new Intent(MainActivity.this,TestService.class));
			}
		});
	}
}

快速点击四次start按钮:

[Android基础]Service_第3张图片


四、

绑定模式下的Service:

1.本地绑定

要实现对Service组件功能的调用,Service组件要做以下改造:

a.将Service组件的功能封装到一个接口中

b.实现一个内部类,它继承Bind类(即实现IBinder接口),并实现上面的接口

c.在Service组件的onBind()中,返回b中的内部类对象,供其他组件使用


下面用一个例子展示一下:

package com.example.test2;

public interface ICount {

	public abstract int getCount();
}


package com.example.test2;

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

public class CountService extends Service {

	private int count;
	private ServiceBinder serviceBinder = new ServiceBinder();
	
	@Override
	public void onCreate() {
		super.onCreate();
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				while (true) 
				{
					try 
					{
						Thread.sleep(1000);
					} catch (InterruptedException e) 
					{
						e.printStackTrace();
					}
					count++;
					Log.v("CountService", "Count is" + count);
				}
			}
		}).start();	
	}
	
	@Override
	public IBinder onBind(Intent intent) {
		return serviceBinder;
	}
	
	public class ServiceBinder extends Binder implements ICount {

		@Override
		public int getCount() {
			return count;
		}
	}
}

package com.example.test2;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends Activity implements ServiceConnection {

	private ICount iCount;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		bindService(new Intent("com.example.test2.CountService"), this, BIND_AUTO_CREATE);
	}

	@Override
	public void onServiceConnected(ComponentName name, IBinder service) {
		iCount = (ICount) service;
		Log.v("MainActivity", iCount.getCount() + "");
	}

	@Override
	public void onServiceDisconnected(ComponentName name) {
		iCount = null;
	}
	
	@Override
	protected void onDestroy() {
		unbindService(this);
		super.onDestroy();
	}
}

<service 
            android:name=".CountService">
            <intent-filter >
                <action android:name="com.example.test2.CountService"/>
            </intent-filter>          
        </service>



2.远程绑定

你可能感兴趣的:(service)