今天重新学习一下android service的用法,service在一般的应用开发中比较常见,比如:应用商店的apk下载,播放音乐等。

1. service简介

service到底是个神马东西呢?根据官网文档的描述可以得知,service是android系统的一个应用组件,启动之后一直默默的长时间的运行在后台,不像activty那样可以跟用户交互,就算我们退出应用了,service仍然可以在后台执行。因此可以利用service的这个特性帮我们解决很多问题,想熟练使用service就得先了解它的生命周期。service可分为两种:本地服务和远程服务,本篇只介绍本地服务,下一篇介绍远程服务,实现跨进程通信(IPC)。

2.service生命周期及本地Service的使用

service可以通过两种方式创建:startService()和bindService().

startService():一般用于在后台上传文件或者下载文件等,不跟其他组件通信,就算启动它的应用被销毁了,它仍然会欢快的在后台执行,直到完成任务的时候自刎(自己调用stopSelf())或者被其他人下黑手(调用stopService()).

bindService():允许其他组件跟它进行通信,允许多个客户端绑定到同一个service上,当所有的客户端都解除绑定后,该service就销毁了。

service的生命周期主要是跟这4个回调函数相关,onCreate()、onStartCommend()、onBind()、onDestory(),首先看看下面这张图,然后结合下面的demo,就很容易理解了。

 

下面通过一个简单demo看看分别通过两种方式启动service时,这些回调函数的执行过程。

(1)startService()

新建一个StartLocalServiceActivity.java文件,定义两个按钮用来启动和停止service

package com.alexzhou.servicedemo;

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

/**
 * 启动一个本地Service 
 * 
 * @author alexzhou
 */
public class StartLocalServiceActivity extends Activity implements
		OnClickListener {

	private Button startButton;
	private Button stopButton;

	private final String LOCAL_START_SERVICE_ACTION = "com.alexzhou.service.LOCAL_START_SERVICE";

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.start_local_service);
		findViews();
		setListeners();
	}

	private void findViews() {
		startButton = (Button) this.findViewById(R.id.start);
		stopButton = (Button) this.findViewById(R.id.stop);
	}

	private void setListeners() {
		startButton.setOnClickListener(this);
		stopButton.setOnClickListener(this);
	}

	@Override
	public void onClick(View view) {
		switch (view.getId()) {
		case R.id.start:
			this.startService(new Intent(LOCAL_START_SERVICE_ACTION));
			break;

		case R.id.stop:
			this.stopService(new Intent(LOCAL_START_SERVICE_ACTION));
			break;
		}

	}
}

新建一个LocalService.java文件,这个就是本地service文件。

package com.alexzhou.servicedemo.service;

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

/**
 * 本地服务
 * @author alexzhou
 */
public class LocalService extends Service {

	private final String TAG = LocalService.class.getSimpleName();

	private LocalBinder mBinder = new LocalBinder();

	public class LocalBinder extends Binder {

		public LocalService getService() {
			return LocalService.this;
		}
	}

	@Override
	public IBinder onBind(Intent intent) {
		Log.e(TAG, "onBind");
		return mBinder;
	}

	@Override
	public void onCreate() {
		Log.e(TAG, "onCreate");
		super.onCreate();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.e(TAG, "onStartCommand");
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public void onDestroy() {
		Log.e(TAG, "onDestroy");
		super.onDestroy();
	}

	public String getContent() {
		return "welcome access local service!";
	}

}

AndroidManifest.xml添加

 <activity android:name=".StartLocalServiceActivity" />
 <activity android:name=".BindLocalServiceActivity" />     

  <service
            android:name=".service.LocalService"
            android:exported="false" >
            <intent-filter>
                <action android:name="com.alexzhou.service.LOCAL_BIND_SERVICE" />
                <action android:name="com.alexzhou.service.LOCAL_START_SERVICE" />
            </intent-filter>
        </service>

考虑到篇幅问题,布局文件就不贴出来了,点击屏幕上的启动服务按钮,看看Logcat的输出信息:会依次打印出onCreate()->onStartCommand().

点击停止服务按钮,此时会执行:onDestory()方法销毁service。

onCreate()方法在service第一次创建的时候会调用,如果该service已经运行了则不会执行该函数。

onStartCommand()方法是在其他组件通过调用startService()启动服务时才会执行。每次启动service时,onStartCommand()都会被执行。你多点几次启动服务按钮,会看到每次都会执行onStartCommand()。

(2) bindService()

创建一个BindLocalServiceActivity.java文件,也同样弄两个button来绑定和解绑服务。

package com.alexzhou.servicedemo;

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.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.alexzhou.servicedemo.service.LocalService;

/**
 * 绑定一个本地Service
 * 
 * @author alexzhou
 */
public class BindLocalServiceActivity extends Activity implements
		OnClickListener {

	private TextView callbackView;
	private Button bindButton;
	private Button unbindButton;

	private boolean isBind;
	private final String LOCAL_BIIND_SERVICE_ACTION = "com.alexzhou.service.LOCAL_BIND_SERVICE";
	private LocalService mLocalService = null;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.bind_local_service);
		findViews();
		setListeners();
		callbackView.setText("Not attached.");
	}

	private void findViews() {
		callbackView = (TextView) this.findViewById(R.id.callback);
		bindButton = (Button) this.findViewById(R.id.bind);
		unbindButton = (Button) this.findViewById(R.id.unbind);
	}

	private void setListeners() {
		bindButton.setOnClickListener(this);
		unbindButton.setOnClickListener(this);
	}

	@Override
	public void onClick(View view) {
		switch (view.getId()) {
		case R.id.bind:
			this.bindService(new Intent(LOCAL_BIIND_SERVICE_ACTION),
					mConntectin, Context.BIND_AUTO_CREATE);
			isBind = true;
			callbackView.setText("binding...");
			break;

		case R.id.unbind: {
			if (isBind) {

				this.unbindService(mConntectin);
				isBind = false;
				callbackView.setText("unbind...");
			}
		}
			break;

		}

	}

	private ServiceConnection mConntectin = new ServiceConnection() {

		@Override
		public void onServiceDisconnected(ComponentName arg0) {
			Log.i(BindLocalServiceActivity.class.getSimpleName(),
					"onServiceDisConnected");
			callbackView.setText("Disconnected!");
			Toast.makeText(BindLocalServiceActivity.this,
					R.string.remote_service_disconntected, Toast.LENGTH_SHORT)
					.show();
		}

		@Override
		public void onServiceConnected(ComponentName name, IBinder binder) {
			Log.i(BindLocalServiceActivity.class.getSimpleName(),
					"onServiceConnected");
			mLocalService = ((LocalService.LocalBinder) binder).getService();
			callbackView.setText("attached!" + mLocalService.getContent());

			Toast.makeText(BindLocalServiceActivity.this,
					R.string.remote_service_connected, Toast.LENGTH_SHORT)
					.show();
		}
	};

	@Override
	protected void onDestroy() {
		super.onDestroy();
		if (isBind) {
			this.unbindService(mConntectin);
			isBind = false;
		}

	}

}

点击绑定服务按钮,从Logcat输出的信息中可以看出调用顺序:onCreate()->onBind() ->onServiceConnnected()

同理onCreate()只会在service第一次创建时执行。

点击解绑服务,会调用service的onDestory()方法。可以先调用startService(),然后再绑定该service,这样解除绑定的时候service就不会被销毁了,需要unbindService()和stopService()都调用,服务才会销毁。注意:连接正常关闭的情况下,上述代码中onServiceDisconnected是不会调用的,只有在异常关闭的时候调用,比如被kill了。

3.  service和线程的区别

刚开始接触service的时候,很多人会有这样的疑问,为什么不用thread代替service呢。首先得明白本地service是运行在主进程的main线程上的,如果是远程service,则运行在独立进程的main线程上。而新建线程主要是用来执行一些异步的操作。首先从生命周期来分析,当一个应用程序被强制终止后,应用程序中开启的线程也会被销毁,而service可以做到在应用被终止的情况下仍然在后台欢快的运行。其次是同一个线程对象没法被多个activty控制,如有时候会出现这种情况:当 Activity 被 finish 之后,该Activty启动的线程还在执行,此时你失去了对该线程的引用,只能通过终止应用来停止该线程的运行。对于一些比较关键的服务,一般选择使用service,如果比较耗时则可以在service中创建和控制线程,进行异步操作。

android使用tcpdump抓包

最近游戏在接qq opensdk的时候调用一个cgi一直不成功,文档描述太简单,我们调用的又是互娱这边msdk的api,由msdk调用opensdk相关api,中间跨了两部门,为了...

阅读全文

Android.mk文件解读

我们在Android平台写c/c++程序的时候需要用到Android.mk(Makefile),一般用来编译c/c++源码、引用第三方头文件和库,生成程序所需的so文件。下面是一个cocos2...

阅读全文

Android性能优化案例研究(下)

去掉冗余的图层 为 了去掉重绘我们必须首先理解它从哪里产生的。这就轮到Hierarchy Viewer和Tracer for OpenGL大显身手的时候了。Hierarchy Viewer是ADT工具...

阅读全文

5 条评论

  1. 很遗憾已经不是学生了,想转行学的android。。。游戏最好是用cocos2d-x做吗?

    1. 看公司的需求吧,如果是新项目且是2d游戏的话,我觉得cocos2d-x非常不错~~,至少移植到其他平台会轻松很多。

  2. 楼主讲的精辟深入,学习了。业余学习android一段时间了,不知道该怎么入门写点东西呢,有朋友建议加入学校的一些创业团队,不知道海哥能否指点下。。。

    1. 谈谈我自己的想法吧,不过不一定对,学东西就是拿来用的,其实现在android学习资料满天飞,小项目源码也是很多,可以找一个项目源码研究一下,比如网上有人写的新浪或者腾讯微博客户端或者一个小游戏也行,不急不贪,别短时间做很多应用,大多数普通应用就是熟悉调用API而已,搞定一个项目总结一下,这样就不会那么浮躁了,而且会很有成就感,心里也踏实。然后可以研究一些UI特性,比如类似于网易新闻客户端实现、微信开门效果、瀑布流效果等等,平常多查查android官方文档。如果你还是学生的话,既然有机会加入创业团队那最好不过了,比起自己瞎摸索要好很多。

欢迎留言