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