Android四大组件-Service并非详解

距离上篇文章竟然快一年了。这次是想明确service一些比较重要的点。

至于什么是service,我也不想多去讨论,我只想清晰确认这么几个问题:

1、service的生命周期到底如何?

2、Activity如何让service做事?

3、service与thread之间有没有关系?

4、远程service是什么东西?

5、AIDL的使用?

6、前台service?

一、生命周期

如果需要图,可以百度,好多。我这里直接运行代码打log。

1、startService()启动Service

操作顺序是:

startService(intent),service相应执行的是oncreate() ------>   onStartCommand() ------> onStart()。

stopService(intent),service相应执行的是onDestroy()。

startService(intent),service相应执行的是oncreate() ------>   onStartCommand() ------> onStart()。

startService(intent),service相应执行的是onStartCommand() ------> onStart()。

stopService(intent),service相应执行的是onDestroy()。

这里可见,onCreate() 只会执行一次,即service第一次被启动的时候,在没有destroy之前,继续启动onCreate()不会再执行。

2、bindService()启动Service

首先说明:

如果使用bindService()启动Service,需要实例一个接口,ServiceConnection。然后实现接口里面的两个方法,onServiceDisconnected()和onServiceConnected()。正常情况下只会执行onServiceConnected()这个方法,另一个方法会在系统内存不足强制回收service导致connection断开时执行。

private ServiceConnection connection = 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
			DebugLog("onServiceConnected()");

		}
	};

bindService的原型:

public boolean bindService(Intent service, ServiceConnection conn, int flags) 

参数:

service:Intent对象,说明要启动哪一个service

conn:就是上面创建的连接

flags:一个标志,一般使用自动创建(BIND_AUTO_CREATE)

unBindService的原型:

 public void unbindService(ServiceConnection conn)

参数:

conn:就是上面建立的连接,如果unbindservice后继续unbind会抛出运行异常,终止程序。

log如下:

操作顺序:

bindService(intent3, connection, BIND_AUTO_CREATE): service执行顺序:onCreate() ------>onBind() ------> onServiceConnected()

unbindService(connection):service执行顺序:onUnbind() -------> onDestroy()

startService(intent):service执行顺序:onCreate() ------> onStartCommand() -------->onStart()

bindService(intent3, connection, BIND_AUTO_CREATE): service执行顺序:onBind() ------> onServiceConnected()

unbindService(connection):service执行顺序:onUnbind()

stopService(intent):service执行顺序:onDestroy()

当service的生命周期了解之后,那么如果需要用到service时,应该也知道该在哪个方法里面写了。

二、Activity如何让service服务自己?

对于activity向service传值不再讲,使用intent启动服务时,该intent就是service 中onStartCommand()和onStart()函数中参数的intent,因此简单的传值可以直接使用intent即可。下面主要讲如何进行方法的调用?使service真正的服务activity。

1、使用binder类

首先在Service类里面创建一个继承于Binder的类,比如:

public class MyBinder extends Binder{
		public void startDownload(){
			DebugLog("start download...");
		}
		//获取当前Myservice实例
		public MyService getService(){
			return MyService.this;
		}
	}

这个类里面有一个startDownload()方法,模拟下载。

在onBinder()方法中返回类实例:

public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		DebugLog("onBind()");
		return new MyBinder();
	}

在serviceConnection实现里的onServiceConnected()方法中,得到这个类的实例,,然后可以执行里面的方法。

MyService.MyBinder myBinder = (MyBinder)service;
myBinder.startDownload();

这种方法可以简单的让Activity调用service里面的方法。

2、使用广播

至于activity与service哪一端做接收器哪一端做发送端,根据实际情况而定。这里是activity发送广播,service进行监听。这种方式在音乐播放器可以使用,比如让service监听系统广播,如果来电了要暂停播放。等等。

这里简单写一下,只是提供思路。

在service里面动态注册广播:

private BroadcastReceiver myReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			// TODO Auto-generated method stub
			String string = intent.getStringExtra("main");
			DebugLog("string:"+string);
		}
	};

在Service 中的onCreate()函数里注册:

IntentFilter filter = new IntentFilter();
		filter.addAction("com.fleur.mybroadcast");
		registerReceiver(myReceiver, filter);
		DebugLog("registerReceiver success");

在service中的onDestroy()函数中反注册:

unregisterReceiver(myReceiver);

动态注册的广播一定不要忘记反注册。

如此之后就可以在activity里面发送广播了。比如:

			case R.id.button8:
				Intent intent5 = new Intent("com.fleur.mybroadcast");
				intent5.putExtra("main", "this broadcast is from mainActivity");
				sendBroadcast(intent5);
				break;

log如下:

3、使用回调

我一直觉得回调是一件很神奇的事情。如果不懂回调可以看一下这篇文章:http://blog.csdn.net/xiaanming/article/details/8703708

回调解决了service去调用activity里面的方法。

首先创建回调接口(单独一个接口文件):

public interface OnProgressListener {

	public void onProgress(int progress);

}

接口里面就是回调方法。

在Service里面生命一个接口变量,然后提供一个外部注册接口用的方法。比如:

//更新进度的回调接口
	private OnProgressListener onProgressListener;

	/**
	 * 注册回调接口的方法
	 * @param onProgressListener
	 */
	public void setOnProgressListener(OnProgressListener onProgressListener) {
		this.onProgressListener = onProgressListener;
	}

然后再Service里面声明一个方法,依然模拟下载:

public void startDownload(){
		new Thread(){
			@Override
			public void run() {
				while(progress < MAX_PROGRESS){
					progress += 5;

					//进度发生变化时告诉调用方
					if(onProgressListener!=null){
						onProgressListener.onProgress(progress);
					}
					try {
						sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}.start();
	}

注意这个是service里面的方法,不是MyBinder类里面的方法。

在activity里面:

首先声明一个MyService类的对象,然后在connection中得到这个对象,注册回调接口,实现回调方法。如下:

public void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub
			DebugLog("onServiceConnected()");
			myBinder = (MyBinder) service;
			myService = myBinder.getService();
			myService.setOnProgressListener(new OnProgressListener() {

				@Override
				public void onProgress(int progress) {
					// TODO Auto-generated method stub
					progressBar.setProgress(progress);
				}
			});
		}
//然后自己写一个button控制,使用得到的MyService对象调用startDownload()方法,实现回调。
myService.startDownload();

对于不同进程间的activity通信,有两种方式,一是使用Messenger,二是使用AIDL。这里先不讲了。

三、service与thread之间有没有关系?

service是运行在后台的没有用户界面的,新建一个thread也是用户不能看到的,运行在后台的。但是service与thread真的是一点关系都没有,对于普通的local service来说,他跟activity是运行在同一个进程里面的主线程里的,也就是说service也是主线程,UI线程,不能进行耗时操作。那如果我想后台访问网页去下载呢?简单啊,在service里开辟一个新线程呗,跟在activity里面开辟新线程没有区别。

四、远程service是什么东西?

正常我们在ActivityManifest.xml文件中声明的service都是LocalService,即本地服务。也就是只能服务本应用程序(APP)。但是有些service是想服务别的APP的,这时就应该用远程service,其实只需要在ActivityManifest.xml文件声明service时这样写:

<service android:name="com.fleur.service.MyRemoteService"
            android:process=":remote">
            <intent-filter >
                <action android:name="com.fleur.service.MyRemoteService"/>
            </intent-filter>

添加了一句话:android:process=":remote"

即变成了远程服务。

这里注意,远程服务已经跟activity不在同一个进程了,使用startService() 打印log如下:

这样如果在远程服务做耗时操作,并不会产生ANR问题。但是,

使用使用远程服务,不能直接使用bindService()了,不能像localservice那样与activity通信了。这时需要使用AIDL进行,进程间通信。

还是能不使用远程service就不要用了吧。

五、AIDL的使用?

首先建立一个.aidl文件,里面使用Java的语法写一个接口。保存后会在gen下面自动生成Java文件。如下:

package com.fleur.service;
interface MyAIDLService{
	String toUpperCase(String str);
}

在远程服务里实例一个Binder对象,实现接口的方法。如下:

import com.fleur.service.MyAIDLService.Stub;
Stub mBinder = new Stub() {

		@Override
		public String toUpperCase(String str) throws RemoteException {
			// TODO Auto-generated method stub
			if(str!=null){
				return str.toUpperCase();
			}
			return null;
		}
	};

其实stub是aidl文件里的,它继承了Binder实现了我们自己写的接口。

然后在onBind()里面return这个对象。

在activity中同样实例serviceConnected接口,声明一个刚才写的接口对象,在onServiceConnected里面得到实例。

	private MyAIDLService myAIDLService;
	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
			myAIDLService = MyAIDLService.Stub.asInterface(service);
			try {
				String upperStr = myAIDLService.toUpperCase("hello world");
				DebugLog("upperStr = "+upperStr);
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	};

这样在去bindService就OK了。实现了不同进程间的通信。

六、前台service

service优先级特别低的,如果内存不足很容易会回收,但是有时候我们的APP很依赖service,不希望回收,如果回收了,我这app也没意思了,这时就可以使用前台service了。其实很简单,在service的onCreate方法中这样写:

Notification notification = new Notification(R.drawable.ic_launcher, "Android_Component", System.currentTimeMillis());
		Intent notificationIntent = new Intent(this,MainActivity.class);
		PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
		notification.setLatestEventInfo(this, "title of notification", "content of notification", pendingIntent);
		startForeground(1, notification);

最最关键的就是最后一句,startForeground()方法。

当再次启动这个服务的时候就会发现通知栏一个图标,这就是你在后台运行的“前台service”。

当service被销毁时前台service相应销毁。

比如音乐播放器啊,天气类的啊,对service依赖比较高的可以考虑前台service。

一些东西自己明白但是也可能说不明白,参考了一篇博客:http://www.360doc.com/content/14/0415/18/2793098_369238276.shtml

然后加之自己的理解。

对于service一些盲点或者重要的点,以前没有总结过,这次真的认真总结了一回。除此还有前台service,可以自己看一下。

service只是Android中我需要总结的很多重要的点中的一个。接下来会陆陆续续总结一下。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-28 11:17:13

Android四大组件-Service并非详解的相关文章

Android四大组件之Activity详解 &middot; yclog

Activity生命周期: onCreate:在Acitivty第一次创建时调用,用于做初始化的工作onStart:onCreate调用后调用,此次界面对用户来说无法看见onResume:此次界面可见并显示到前台,且当前Acitvity位于当前栈顶,并且处于运行状态onPause:表示当前Activity正在停止,常做一些存储数据.停止动画等工作(不做耗时操作)onStop:表示当前Activity即将停止,一般做微量级的回收工作onDestory:表示当前Activity即将被销毁,可做一些回

Android四大组件之Activity详解

.Activity的本质 Activity是Android提供的四大组件之一,是进行Android开发必不可少的组件.Activity是一个界面的载体,可以把它与html页面进行类比,html页面由各种各样的标签组成,而Activity则可以由各种控件组成.然而Activity也并不是那么简单.查看Activity类的源码我们就可以看到,这个类大概有六千多行代码,说明Android对Activity的处理是相当复杂的.不过我们平时进行开发的时候不需要了解到那么深入的地步,因为我们可以根据Acti

Android四大组件之Activity详解——传值和获取结果

废话不多说,先来看效果图 项目源码: http://download.csdn.net/detail/ginodung/8331535 程序说明: 在MainActivity中输入用户名和密码,然后提交到SecondActivity 在SecondActivity中获取提交的数据,通过Toast显示该数据 在SecondActivity设置新的用户名和密码,然后返回给MainActivity MainActivity获取到SecondActivity返回的数据后从新设置用户名和密码的值,然后用T

Android四大组件之Activity详解——创建和启动Activity

前面我们已经对Activity有过简单的介绍: Android开发——初始Activity Android开发——响应用户事件 Android开发——Activity生命周期 先来看一下最终结果 创建Activity: 接下来打开我们的IDE,创建一个名叫ActivityDemo的Android Application Project 工程默认已经为我们创建了一个Activity,现在我们手动添加一个名叫SecondActivity的类 点击finish完成SecondActivity类的创建.

Android四大组件——Service

Service相关链接 Service初涉 Service进阶 Service精通 Service是Android系统中的一种组件,它跟Activity的级别差不多,但是它不能自己运行,只能后台运行,并且可以和其他组件进行交互.Service是没有界面的长生命周期的代码.Service是一种程序,它可以运行很长时间,但是它却没有用户界面.这么说有点枯燥,来看个例子,打开一个音乐播放器的程序,这个时候若想上网了,那么,我们打开Android浏览器,这个时候虽然我们已经进入了浏览器程序,但是,歌曲播

Android开发之Service服务详解

服务,作为Android四大组件之一,必然是重点.我们今天就来讲解一下有关服务的生命周期.两种开启方式以及相关用法. 服务有两种开启方式,一种是正常开启, 一种是以绑定的方式开启,当然,这两种方式可以组成混合开启. 一.服务的正常开启 正常开启服务的方法非常简单,我们先看如何定义一个服务 1.编写一个类,继承Service类. 我们先不管代码中的binder类.那个后续讲解用. public class TestService extends Service { @Override public

Android四大组件——Service后台服务、前台服务、IntentService、跨进程服务、无障碍服务、系统服务

Service后台服务.前台服务.IntentService.跨进程服务.无障碍服务.系统服务 本篇文章包括以下内容: 前言 Service的简介 后台服务 不可交互的后台服务 可交互的后台服务 混合性交互的后台服务 前台服务 IntentService AIDL跨进程服务 AccessibilityService无障碍服务 系统服务 部分源码下载 前言 作为四大组件之一的Service类,是面试和笔试的必备关卡,我把我所学到的东西总结了一遍,相信你看了之后你会对Service娓娓道来,在以后遇

Android四大组件-Service

http://blog.csdn.net/guolin_blog/article/details/11952435 http://www.jianshu.com/p/eeb2bd59853f 概述 定义.特点: Service是可以在后台执行长时间(长生命周期)而又不与用户产生UI交互(没有用户界面)的操作 注意事项:1.只能在后台运行,即便用户切换了其他应用,启动的Service仍可在后台运行.2.可以和其他组件进行Service绑定并与之交互,甚至是跨进程通信(IPC).3.不能运行在一个独

Android 四大组件 Service 服务

1.Service简介 按照使用范围分类: 类别 优点 缺点 区别 应用 本地服务 Local  Service 本地服务在一定程度上节约了资源,另外本地服务因为是在同一进程,因此不需要IPC,也不需要AIDL.相应bindService会方便很多. 主进程被Kill后,服务便会终止. 本地服务依附在主进程上,而不是独立的进程,用于应用程序内部 . 音乐播放服务 远程服务 Remote Service 对应进程名格式为所在包名加上指定的android:process字符串.由于是独立的进程,因此