您的位置:首页 > 移动开发 > Android开发

Android 四大组件之一Service

2014-04-04 11:42 405 查看
Android的四大组件包括Activity,Service,contentProvider,broadcast receiver。

Service和Activity是比较像的,都需要继承Service,都需要在AndroidMainfest.xml中注册,在其中的inter-filter中配置可以响应的Intent事件,都是从context中派生出来的。区别在于Service一直运行在后台,没有自己的界面。



启动Service:

1. 用Context的startService方法,访问者与Service没有关联,即使访问者退出了Service仍然继续运行。

2. 用Context的bindService方法,访问者与Service绑定在一起,访问者一旦退出,Service也退出了。并且可以进行数据交换。



用第一种方法启动如下:

final Intent intent = new Intent();
intent.setAction("FIRST_SERVICE");  // <action android:name="FIRST_SERVICE" >
startService(intent); // 启动
stopService(intent);  // 停止


使用第二种方法时:

Service类实现步骤:

1. 新建IBinder子类MyBinder,在其中可以添加方法来控制Service类中的数据,以后Activity会调用这些方法。

2. 重写public IBinder onBind(Intent intent),来返回Service中新建的MyBinder实例。

Activity中实现步骤:

1. 实现一个ServiceConnection对象,在其中的连接时触发的事件函数中获取返回的MyBinder的实例。

2. bindService(Intent service,ServiceConnect,flag)

3. 通过调用MyBinder中的方法即可以获取Service中的数据。



注意:

当访问者主动调用unBindService()方法来断开连接时不会触发ServiceConnect中的onServiceDisconnect方法。



当BindService一个已经启动的Service,系统只是把Service的IBinder对象返回来,unbindService时只是把切断了联系,并没有停止该组件。



疑惑:

调用unbindService后,仍可以去用Mybinder的实例去掉用里面的方法。关键是Service已经onDestory了,方法怎么还能访问里面的变量呢。



可能是这样的,onDestory只是通知了系统但Service并没有被销毁。如果没有进行ServiceConnection去掉用就会出错。



示例

Service:

package com.bindservice;

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

/*****************************************
 * 使用BindService启动Service时,需要实现onBind方法
 * 
 * IBinder相当于Service中的内部钩子,绑定时将返回给其他组件
 *****************************************/

public class BindService extends Service {

	private int count;
	private boolean quit;

	// 定义onBind方法返回的对象
	private MyBinder binder = new MyBinder();

	private String TAG = "BindServiceDemo";

	// 必须实现的方法
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		Log.i(TAG, "=== onBind ===");
		return binder;
	}

	@Override
	public void onCreate() {
		super.onCreate();
		Log.i(TAG, "=== onCreate ===");
		// 启动一个线程动态修改count的值
		new Thread() {
			@Override
			public void run() {
				while (!quit) {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					count++;
				}
			}
		}.start();
	}

	// 解除绑定时调用的方法
	public boolean onUnbind(Intent intent) {
		Log.i(TAG, "=== onUnbind ===");
		System.out.println("=== onUnbind ===");
		return true;
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		Log.i(TAG, "=== onDestroy ===");
		this.quit = true;
	}

	public class MyBinder extends Binder {
		public int getCount() {
			// 获取Service的运行状态
			return count;
		}
	}

}


Activity



package com.bindservice;

import android.os.Bundle;
import android.os.IBinder;
import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

/************************************************
 * 主要是借助IBind实现的Activity与Service之间通信。
 * 
 * 在Activity中实现ServiceConnect用于建立连接时回调。从而能够获取新建的Service的IBinder对象
 * 通过IBinder中的方法(在Service中已经实现)来控制Service中的数据
 * 
 ***********************************************/

public class MainActivity extends Activity {

	// 定义启动Service的IBind对象
	BindService.MyBinder binder;
	// 定义一个ServiceConnect 对象
	private ServiceConnection conn = new ServiceConnection() {

		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub

		}

		// 当Activity与Service连接时回调该方法
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub

			// 获取Service的onBind方法返回的MyBind对象
			binder = (BindService.MyBinder) service;
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		Button bindbutton = (Button) findViewById(R.id.bindButton);
		Button unbindButton = (Button) findViewById(R.id.unbindButton);
		Button statusButton = (Button) findViewById(R.id.statusButton);

		final Intent intent = new Intent();
		intent.setAction("BIND_SERVICE");

		bindbutton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				// 绑定指定的Service
				bindService(intent, conn, Service.BIND_AUTO_CREATE);
			}
		});
		unbindButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				// 解除绑定
				unbindService(conn);
			}
		});
		statusButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				// 获取Service的count的值
				Toast.makeText(MainActivity.this,
						"BindService count: " + binder.getCount(),
						Toast.LENGTH_SHORT).show();
			}
		});

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}






==============================================================================================



onStartCommand()
The system calls this method when another component, such as an activity, requests that the service be started, by calling
startService()
.
Once this method executes, the service is started and can run in the background indefinitely. If you implement this, it is your responsibility to stop the service when its work is done, by calling
stopSelf()

or
stopService()
. (If you only want to provide binding, you don't need to implement this method.)

START_STICKY
If the system kills the service after
onStartCommand()

returns, recreate the service and call
onStartCommand()
, butdo not redeliver
the last intent. Instead, the system calls
onStartCommand()
with a null intent, unless
there were pending intents to start the service, in which case, those intents are delivered. This is suitable for media players (or similar services) that are not executing commands, but running indefinitely and waiting for a job.




在用StartService启动Service时,onStartCommand的返回值如果是START_STICKY的话,比如在onStartCommand中是耗时任务导致ANR,被系统kill掉,这是这个Service还会再起来。 先运行onCreate,在运行onStartCommand

每次调用startService(Intent)的时候,都会调用该Service对象的onStartCommand(Intent,int,int)方法,这个方法return 一个int值,return 的值有四种:



START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。



START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。



START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。



START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: