是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线程.:
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;
}
}
}