android-Service

Service:
是app的组件
可以长时间运行在后台,不提供用户界面
其他应用app也可以启动Service
即使用户切换到其他app, Service依然运行
Service可以跨进程,


使用Service的两种方式
1.Start
其他组件,比如Activity,启动Service 通过startService
即使启动该Service的Activity被销毁了,Service依然在运行.
Service通常会执行一个操作,不会给调用者返回结果,
Service的事情一旦做完了,应该停止,
2.Bound
其他组件可以绑定Service上,通过bindService()
绑定式 可以认为是  客户端-服务端    发送请求,获取数据,甚至可以进行进程间通信
该Service跟绑定到Service上的组件共存亡.某一时刻,可以有多个组件绑定在Service上.所有
绑定在Service上的组件都解绑了,Service就销毁了.
启动的Service,还允许被绑定.所要做的事情,实现两个回调方法:onStartCommond(),onBind()

注意:Service运行在主线程.如果想要进行耗时,阻塞的操作需要开线程.

创建Service

创建Service的子类
重写方法,比较重要的:
onStartCommond()    :另外一个组件请求启动这个Service的时候调用该方法.
一旦该方法执行了,Service就已经开启起来了,运行在后台.独立的,
一旦Service的事情做完,应该停掉Service,    stopSelf()    ,stopService()
onBind()    :另外一个组件通过调用bindService(),想要绑定到Service,系统会调用onBind();
必须要返回一个借口IBinder,  接口---->让绑定者跟Service交流
如果不允许其他组件绑定上来,返回null

onCreate()    :Service第一次创建执行,该方法先于onStartCommond()或者onBind();
onDestory()    :当Service不在被使用的时候调用被销毁.通常情况下需要重写该方法,来清理一些东西,比如线程,注册监听.


一旦Service开启起来之后,将会保持 运行,直到Service自己stopSelf(), 其他组件调用stopService()

bindService()创建Service对象,该Service跟绑定着共存亡.
所有的绑定着都解绑了,系统销毁Service

注册:  
清单文件中,  Application节点中添加子节点, Service--name

跟Activity一样,也可以声明意图过滤器.让设备上的任意一个app启动该Service
Service可以被声明为私有的.通过Exported属性:false

第一次startService的时候:
onCreate()  onStartCommand()----传值

再次点击开启Service,   onStartCommand()---继续传值


当系统内存过低的时候,系统为了恢复资源,就会强制停止Service
如果Service上绑定了一个位于界面最前面(拥有用户焦点,)Activity,该Service被杀死的可能性比较小
如果Service被声明为前提Service,几乎不被杀死,Service运行时间过长,随着时间的推移.
系统杀死该Service的可能性会越来越大,系统内存资源恢复的时候,会重启Service,(虽然系统会重启,还取决于onStartConmmand()方法.合理设置重启操作)

生命周期方法:
StrarService   第一次,  onCreate().   onStartCommand()
startService 再次,  onstartCommand()
...onstartCommand()
stopServiceDestory();


IntentService
默认创建一个工作线程,来处理intent  传递进 onStartCommand()
多个Intent.放进队列,一次只传一个给HandleIntent()

所有的请求处理完了的时候,Service会停止.,所以调用stopSelf()

默认提供 onBind()方法的实现.所以.
提供了对onStartCommand()方法的实现,把Intent放进队列中,Intent交给HandlerIntent()处理

所有,用IntentService的时候,只要实现onHandlerIntent()
注意:  添加构造方法 ,无参,   必须调用父类的有参构造.传递一个字符串(工作线程的名字)

onHandleIntent()工作在非UI线程.:

START_NOT_STICKY :       系统在onStartCommand()返回之后,系统杀死Service后,不会重新创建Service
                            直到有新的Intent传进来的时候,才会创建Service,这是一种最安全的方式,避免让Service不必要的运行/
                            再次创建Service去做未完成的工作.

START_STICKY    :      系统在onStartCommand()返回之后,系统杀死Service后,系统内存恢复的时候,会重新创建Service并且调用onStartCommand() 但是不会吧最后一个Intent穿进来,传null    除非后来又有Intent来启动Service来传递Intent
(播放音乐)

START_REDELIVER_INTENT    :
系统在onStartCommand()返回之后,系统杀死Service后,系统内存恢复的时候,会重新创建Service并且调用onStartCommand()
而且会把最后一个传递进Service的Intent传递进来,(下载文件)
 

BondService:
相对于client---Server        客户端可以发送请求,接受结果,进行进程间通信.   不会独立存在,

只有当客户端需要它的服务的时候才会存在。




实现Service类.  必须重写onBind()方法,必须要返回IBinder()
IBinder 是客户端跟服务端交互的时候使用.

IBinder对象所有连接者用的都是同一个.

OnBind()方法,在第一个连接者连接上来的时候会调用,其他连接者 不会在调用OnBind

最后一个客户端从Service上解绑的时候,系统会销毁Service


创建绑定式的Service    "

三种方式:

1.继承Binder
Service私有,跟客户端运行在同一个进程,
创建接口的时候,继承Binder,把Binder实例通过onBind()方法返回,
客户端拿到Binder对象之后,可以调用Binder的公有方法.
甚至操作Service方法/



1.创建Binder类(子类)
a)应该有一个共有方法.
b)

2.Binder的实例会从onBind()方法中返回
3.在客户端的onServiceConnected()中得到Binder实例


客户端---服务端在同一个app中,同一个进程中,




生命周期方法.

第一次,绑定:当Service对象不存在的时候, 
onCreate()   onBind()   
        解绑: onUnBind()    onDestory()
注意:没有onStartCommand的执行

既想跟Service交互,Activity销毁(解绑)还不想销毁

startService()    :  onCreate(),onStartCommand()
bindService()    :onBind();
onBindService():onUnBind()

停止Service  只能通过stopService()

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btnStart"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:onClick="btnClick"
        android:text="播放" />

    <Button
        android:id="@+id/btnPause"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/btnStart"
        android:onClick="btnClick"
        android:text="暂停" />

    <ImageView
        android:id="@+id/imgv"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:layout_below="@id/btnPause"
        android:src="@drawable/ic_launcher" />

    <TextView
        android:id="@+id/shichang"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/seekBar"
        android:layout_alignParentRight="true"
        android:text="4:00" />

    <SeekBar
        android:id="@+id/seekBar"
        android:layout_width="250dp"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/imgv"
        android:layout_alignParentRight="true" />

</RelativeLayout>

package com.example.day23demo07bindstartmusic;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Environment;
import android.os.IBinder;

public class Service2307 extends Service{
	private MediaPlayer player;
	
	private final MyBinder mBinder=new MyBinder();
	
	@Override
	public void onCreate() {
		super.onCreate();
		
		player=new MediaPlayer();
		//设置播放资源
		try {
			player.setDataSource(Environment.getExternalStorageDirectory()+"/a.mp3");
		
			player.prepare();
		} catch (Exception e) {
			e.printStackTrace();
		} 
	}
	//返回值--》客户端---》onServiceConnected()
	@Override
	public IBinder onBind(Intent intent) {
		return mBinder;
	}
	
	class MyBinder extends Binder{
		//提供一个获取Service对象的一个方法
		public Service2307 getService(){
			return Service2307.this;
		}
	}
	/**播放*/
	public void play(){
		player.start();
	}
	
	/**暂停*/
	public void pause(){
		if(player.isPlaying()){
			player.pause();
		}
	}
	/**获取音乐的总时长*/
	public int getTotal(){
		return player.getDuration();
	}
	
	/**获取音乐的当前播放放进度*/
	public int getCurProgress(){
		return player.getCurrentPosition();
	}
	
	/**获取音乐是否正在播放*/
	public boolean isMusicPlaying(){
		return player.isPlaying();
	}
	
}

package com.example.day23demo07bindstartmusic;

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.Handler;
import android.os.IBinder;
import android.view.View;
import android.widget.SeekBar;

import com.example.day23demo07bindstartmusic.Service2307.MyBinder;

/**
 * 启动startService--》让他活着 跟Service进行交互---》绑定上去
 * 
 * @author cj 音乐的播放暂停
 */
public class MainActivity extends Activity {
	private SeekBar seekBar;
	//Service是否处于绑定状态---》true窗体没有销毁
	private boolean isConn = false;

	private Service2307 mService;

	private MyConnection conn;
	
	
	//更新SeekBar的进度
	private Handler handler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			if(msg.what==1){//最大进度
				seekBar.setMax(mService.getTotal());
			}else if(msg.what==2){//当前进度
				seekBar.setProgress(mService.getCurProgress());
			}
		};
	};

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

		conn = new MyConnection();

		seekBar = (SeekBar) findViewById(R.id.seekBar);
		// 启动Service---》onCraete()、onStartCommand()
		startService(new Intent(MainActivity.this, Service2307.class));

		// 为了直接调用Service中的方法
		bindService(new Intent(MainActivity.this, Service2307.class), conn,
				Context.BIND_AUTO_CREATE);
	}

	// 窗体销毁的时候,解绑
	@Override
	protected void onDestroy() {
		if (isConn) {
			unbindService(conn);
			isConn=false;
		}
		super.onDestroy();
	}

	public void btnClick(View view) {
		switch (view.getId()) {
		case R.id.btnStart:
			mService.play();

			// 开启进度更新
			updateSeekBar();
			break;
		case R.id.btnPause:
			mService.pause();
			break;

		default:
			break;
		}
	}

	/** seekBar的进度更新---》Activity销毁的时候,进度不再更新 */
	private void updateSeekBar() {
		new Thread() {
			public void run() {
				
				System.out.println("Thread="+Thread.currentThread().getName());
				//更新最大进度
				handler.sendEmptyMessage(1);
				while(isConn&&mService.isMusicPlaying()&&mService.getTotal()>mService.getCurProgress()){
					//更新当前进度
					handler.sendEmptyMessage(2);
					
					try {
						Thread.sleep(10);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
		}.start();
	}

	class MyConnection implements ServiceConnection {
		// 连接上Service的时候调用--->得Service对象
		// 参数2:来自于onBind()方法的返回值--》MyBinder对象
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			isConn = true;

			MyBinder mBinder = (MyBinder) service;

			// 获取Service
			mService = mBinder.getService();
			//再次进入,如果音乐正在播放,更新进度
			if(mService.isMusicPlaying()){
				updateSeekBar();
			}
		}

		// 意外断开连接的时候会用
		@Override
		public void onServiceDisconnected(ComponentName name) {
			isConn = false;
		}

	}

}


posted @ 2015-05-21 00:44  merbng  阅读(159)  评论(0编辑  收藏  举报