Android开发秘籍学习笔记(七)

  该目录为有关Android中Service的学习

服务(Service)的简单介绍:

  服务(Service)是运行在后台且不与用户发生任何交互的Android组件。它可以被任意其他组件开启或停止。当其处于运行状态时,任何组件都可与它进行绑定。服务也可以自行停止。下面给出几个概念性场景,帮助理解什么是服务。

  1. Activity让用户可以选择一组音乐文件,然后启动一个服务来播放这些文件。播放期间,一个新的Activity被启动并绑定到这个服务之上,允许用户变更乐曲或停止播放。
  2. Activity启动一个服务向网站上传一组图片,一个新的Activity被启动并绑定到服务上,以确定当前正在上传的文件,并把该图片显示在屏幕上。
  3. 广播接收器接收到一条消息,消息表明用户拍摄了一张图片,随即启动一个服务以将该图片上传到某网站上。然后广播接收器转入非活动状态,并最终杀死以回收内存。但服务会继续运行,直至上传完成。最后,服务自动停止。

服务(Service)的生命周期:

  首先Service有两种状态:启动的绑定的。

    启动的(Started):
  通过startService()启动的服务处于“启动的”状态,一旦启动,service就在后台运行,即使启动它的应用组件已经被销毁了。通常started状态的service执行单任务并且不返回任何结果给启动者。比如当下载或上传一个文件,当这项操作完成时,service应该停止它本身。即能启动一个后台服务。但是不能通信
 绑定的(Bound):
“绑定”状态的service,通过调用bindService()来启动,一个绑定的service提供一个允许组件与service交互的接口,可以发送请求、获取返回结果,还可以通过夸进程通信来交互(IPC)。绑定的service只有当应用组件绑定后才能运行,多个组件可以绑定一个service,当调用unbind()方法时,这个service就会被销毁了。

 注意事项:

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



 生命周期:

 1). 被启动的服务的生命周期:如果一个Service被某个Activity 调用 Context.startService 方法启动,那么不管是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行。如果一个Service被startService 方法多次启动,那么onCreate方法只会调用一次,onStart将会被调用多次(对应调用startService的次数),并且系统只会创建Service的一个实例(因此你应该知道只需要一次stopService调用)。该Service将会一直在后台运行,而不管对应程序的Activity是否在运行,直到被调用stopService,或自身的stopSelf方法。当然如果系统资源不足,android系统也可能结束服务。
 2). 被绑定的服务的生命周期:如果一个Service被某个Activity 调用 Context.bindService 方法绑定启动,不管调用 bindService 调用几次,onCreate方法都只会调用一次,同时onStart方法始终不会被调用。当连接建立之后,Service将会一直运行,除非调用Context.unbindService 断开连接或者之前调用bindService 的 Context 不存在了(如Activity被finish的时候),系统将会自动停止Service,对应onDestroy将被调用。

特别注意:

1、你应当知道在调用 bindService 绑定到Service的时候,你就应当保证在某处调用 unbindService 解除绑定(尽管 Activity 被 finish 的时候绑定会自      动解除,并且Service会自动停止);

2、你应当注意 使用 startService 启动服务之后,一定要使用 stopService停止服务,不管你是否使用bindService;

3、同时使用 startService 与 bindService 要注意到,Service 的终止,需要unbindService与stopService同时调用,才能终止 Service,不管 startService 与 bindService 的调用顺序,如果先调用 unbindService 此时服务不会自动终止,再调用 stopService 之后服务才会停止,如果先调用 stopService 此时服务也不会终止,而再调用 unbindService 或者 之前调用 bindService 的 Context 不存在了(如Activity 被 finish 的时候)之后服务才会自动停止;

4、当在旋转手机屏幕的时候,当手机屏幕在“横”“竖”变换时,此时如果你的 Activity 如果会自动旋转的话,旋转其实是 Activity 的重新创建,因此旋转之前的使用 bindService 建立的连接便会断开(Context 不存在了),对应服务的生命周期与上述相同。

5、在 sdk 2.0 及其以后的版本中,对应的 onStart 已经被否决变为了 onStartCommand,不过之前的 onStart 任然有效。这意味着,如果你开发的应用程序用的 sdk 为 2.0 及其以后的版本,那么你应当使用 onStartCommand 而不是 onStart。


 

 Service的简单实例:

 
 布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="start" />

    <Button
        android:id="@+id/end"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="end" />

</LinearLayout>
两个Button,一个负责开始服务,一个负责关闭服务。
在Activity中则只需给两个Button添加监听事件:
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {

	Button start, end;

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

		start = (Button) findViewById(R.id.start);
		end = (Button) findViewById(R.id.end);

		start.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				startService(new Intent(MainActivity.this,MainServive.class));
			}
		});

		end.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				stopService(new Intent(MainActivity.this,MainServive.class));
			}
		});
	}
}

最后是Service的代码:
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class MainServive extends Service {

	@Override
	public IBinder onBind(Intent arg0) {
		return null;
	}
	
	@Override
	public void onCreate() {
		super.onCreate();
		Toast.makeText(this, "Service created", Toast.LENGTH_SHORT).show();
		Thread initBackground = new Thread(new Runnable() {
			
			@Override
			public void run() {
				play_music();
				Log.i("Did i go to here", "Yes I did"); 
			}
		});
		initBackground.start();
	}
	
	@Override
	public void onDestroy() {
		super.onDestroy();
		Toast.makeText(this, "Service Destoryed", Toast.LENGTH_SHORT).show();
		m_mediaPlayer.stop();
	}
	
	MediaPlayer m_mediaPlayer;
	private void play_music(){
		m_mediaPlayer = MediaPlayer.create(this, R.raw.a);
		try {
			m_mediaPlayer.start();
			Log.i("Did i go to here....", "Yes I did...."); 
			Thread.sleep(400);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}
最后的效果就是点击Button,会响起一段音乐,而且无论是点击Home键,Back键,切换屏幕的方向,音乐仍然照常播放。

 Service和Thread:

1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。

2). Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!


IntentService的使用:

  Android开发中,我们或许会碰到这么一种业务需求,一项任务分成几个子任务,子任务按顺序先后执行,子任务全部执行完后,这项任务才算成功。那么,利用几个子线程顺序执行是可以达到这个目的的,但是每个线程必须去手动控制,而且得在一个子线程执行完后,再开启另一个子线程。或者,全部放到一个线程中让其顺序执行。这样都可以做到,但是,如果这是一个后台任务,就得放到Service里面,由于Service和Activity是同级的,所以,要执行耗时任务,就得在Service里面开子线程来执行。那么,有没有一种简单的方法来处理这个过程呢,答案就是IntentService。
 
什么是IntentService,IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。

 在使用IntentService时要注意,一个必须通过调用super("Myname")为队列命名的构造函数;另一个是handleIntent方法,在其中对Intent进行反编列并执行查询。

 其实IntentService就是这样一类服务:它保持一个它收到的Intent的队列,并逐个执行他们。它对许多后台任务(比如对服务器进行轮询以获取新信息,或下载大量的数据)而言是个理想的处理者。由于Intent十分灵活,可以在其额外信息中包含任何类型的可打包说对象,所以在其中可以给出的配置信息量也差不多是无限制的。这就允许向IntentService发送非常复杂的查询,然后让其做出反应。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章