Android服务Service使用总结资料_第1页
Android服务Service使用总结资料_第2页
Android服务Service使用总结资料_第3页
Android服务Service使用总结资料_第4页
Android服务Service使用总结资料_第5页
已阅读5页,还剩16页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Android服务Service使用总结一.Service简介Service是Android系统中的四大组件之一(Activity、Service、BroadcastReceiver、ContentProvider),它跟Activity的级别差不多,但不能页面显示只能后台运行,并且可以和其他组件进行交互。service可以在很多场合的应用中使用,比如播放多媒体的时候用户启动了其他Activity 这个时候程序要在后台继续播放,比如检测 SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务总是藏在后台的 ,例如,一个 service可能处理网络 事物,播放音乐,执行文件 I/O,或与一个内容提供者交互,所有这些都在后台进行。我们一定要知道的是这里Service的后台运行并不是子线程。Service的运行是在主线程中进行的,只是它没有界面显示而已,它的耗时操作同样需要开启子线程,否者会跟Activity 一样出现 ANR(applicationnotresponse–程序没有响应)。我们要知道的是主线程的内容包括 UI和后台。只要程序中的 UI或后台其中一个在跑,程序都算是在运行状态。(一)Service的创建和注册1.Service服务的创建必须要实现重写其中的onBind方法,可以在里面做各种操作,也可以接收传递过来的Intent的数据做处理。publicclassMyServiceextendsService{@Nullable@OverridepublicIBinderonBind(Intentintent){returnnull;}}2.Service服务的注册,在 AndroidManifest 中注册<serviceandroid:name=".MyService"/>服务的注册是四大组件中最简单的一个,一般只要设置 name属性就可以了。但是如果有其他需求还是要设置其他的属性值的。对Service服务做好创建和注册后,就可以操作服务了。(二)Service两种启动模式Service的启动有两种方式:Context.startService()和Context.bindService()。这里的Context是上下文的意思。1.startService()方式启动时的生命周期回调方法(1)启动服务 startService:–>onCreate()–>onStart()2)停止服务stopService:–>onDestroy()如果调用者直接退出而没有停止走只是关闭了UI界面。

Service,则

Service

会一直在后台运行。这里的退startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法。如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。采用startService()方法启动的服务,只能调用stopService()方法结束服务,服务结束时会调用生命周期的onDestroy()方法。2.bindService()方式启动时的生命周期回调方法1)绑定bindService:–>onCreate()–>onBind()2)解绑unbindService:–>onUnbind()3)正常停止程序服务的方法是先解绑unbindService,再停止服务stopService。4)如果绑定后调用stopService方法,这时是不能停止服务的,如果这时再调用解绑unbindService,程序后先解绑,后停止服务。用bindService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onBind()方法。这个时候调用者和服务绑定在一起,调用者退出了,系统就会先调用服务的 onUnbind()方法,接着调用 onDestroy()方法。如果调用 bindService()方法前服务已经被绑定, 多次调用bindService()方法并不会导致多次创建服务及绑定 (也就是说onCreate()和onBind()方法并不会被多次调用 )。如果调用者希望与正在绑定的服务解除绑定,可以调用unbindService()方法,调用该方法也会导致系统调用服务的onUnbind()->onDestroy()方法。绑定Service方法:bindService(intent,conn,Service.BIND_AUTO_CREA TE);三个参数的说明:第一个:Intent对象第二个: ServiceConnection

对象,创建该对象要实现它的

onServiceConnected()和

onServiceDisconnected()来判断连接成功或者是断开连接第三个:创建 Service的模式,一般指定绑定的时候自动创建(三)Service的五个生命周期的回调方法1.周期命名1)onCreate()2)onStart()3)onBind()4)onUnBind()5)onDestroy()2.生命周期图解上面展示的是没有绑定服务和有绑定服务的生命周期的不同情况的过程。3.关于几个方法的说明(1)onCreate()说明服务第一次被创建(2)onStartComand()说明服务开始工作(3)onBind()说明服务已经绑定(4)onUnBind()说明服务已经解绑(5)onDestroy()说明服务已经停止正如上面说的启动服务有两种方式,一个是使用 startService,另一个方法是使用bindService方法;使用 bindService方法没有回调到 startCommand方法;也可以先启动服务用 startService,再绑定服务用 bindService,这时的Service的回调方法的顺序是:–>onCreate()–>onStartCommand()–>onBind()二.IntentService普通的Service要创建一个线程去完成耗时操作, 因为其运行在主线程, 並且要手動停止IntentService是继承于 Service并处理异步请求的一个类,在 IntentService内有一个工作线程 来处理耗时操作,启动 IntentService的方式和启动传统 Service一样,同时,当任务执行完 后,IntentService会自动停止,而不需要我们去手动控制。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。而且,所有请求都在一个单线程中,不会阻塞应用程序的主线程(UIThread),同一时间只处理一个请求。那么,用 IntentService有什么好处呢?首先,我们省去了在 Service中手动开线程的麻烦,第二,当操作完成时,我们不用手动停止 ServiceIntentService,一个方便我们处理业务流程的类,它是一个 Service,但是比 Service更智能三.查看 Service的生命周期回调方法的简单示例本示例只是用来看看Service在服务开启时,停止时,绑定时,解绑时,生命周期方法的回调情况加深对Service生命周期的印象。(一)创建MyService类(继承 Service)/**服务的创建,测试生命周期的过程和先后五个生命周期:onCreateonStartCommandonDestroyonBindonUnBind*/publicclassMyServiceextendsService{@Nullable@OverridepublicIBinderonBind(Intentintent){returnnull;}@OverridepublicvoidonCreate(){super.onCreate();}@Overridereturnsuper.onStartCommand(intent,flags,startId);}@OverridepublicvoidonDestroy(){super.onDestroy();}@OverridepublicbooleanonUnbind(Intentintent){returnsuper.onUnbind(intent);}}(二)在AndroidManifest 中注册服务<serviceandroid:name=".MyService"/>(三)设计控制服务开启、停止、绑定、解绑状态的代码/**服务的创建和使用注意这里的服务不依赖于Activity页面,即使页面关闭了,服务没有主动去停止,是不会关闭的Service也是在主线程中执行任务的,但是为什么不会造成主线程阻塞??*因为做的不是耗时操作,如果做耗时操作一样会造成 ANR。。。这里点击绑定服务后,点击停止服务按钮是无效的,要先解绑后,才能停止服务。正常情况下,从绑定状态到解绑状态是不会停止服务的。只是一种状态改变而已。这里点击绑定服务后,点击停止服务按钮是无效的,但是解绑后,会马上停止服务。*/publicclassMainActivityextendsAppCompatActivity{@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);}//开启服务publicvoidstartService(Viewview){//开启服务需要 Intent对象,和Activity 跳转类似startService(newIntent(this,MyService.class));}//停止服务publicvoidstopService(Viewview){//停止服务的方法stopService(newIntent(this,MyService.class));}//绑定服务publicvoidbindService(Viewview){//绑定服务bindService(newIntent(this,MyService.class),conn,flags);}//解绑服务publicvoidunBindService(Viewview){//防止在没有绑定的情况下,去解除绑定,抛出异常try{解除绑定unbindService(conn);}}//服务绑定的连接对象privateServiceConnectionconn=newServiceConnection(){@OverridepublicvoidonServiceConnected(ComponentNamename,IBinderservice){}@OverridepublicvoidonServiceDisconnected(ComponentNamename){}};//服务绑定的标识//BIND_AUTO_CREA TE绑定的同时,启动 Serviceprivateintflags=Service.BIND_AUTO_CREATE;}上面是使用四个按钮来实现服务的几种状态的改变。(四)布局文件的设计<?xmlversion="1.0"encoding="utf-8"?>android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center_horizontal"android:text="Service"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="startService"android:text="启动服务"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="stopService"android:text="停止服务"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="bindService"android:text="绑定服务"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:onClick="unBindService"android:text="解绑服务"/></LinearLayout>上面布局文件代码比较简单的,只是用四个按钮搞定!程序运行后显示的界面:这里执行了两个回调方法,先启动服务,再绑定服务!在绑定服务的情况下是不能停止服务的,要解绑服务才能停止服务。在程序的服务启动 /绑定了的情况下,再点击启动服务,只会回调 onStartCommand方法,也就是说一个服务在一个生命周期内只会回调一次 onCreate方法。点击“解绑服务”按钮后显示的 Log信息:执行了两个回调方法: onUnBind和onDestroy如果是用服务做简单的事情,使用第一种方法来启动服务就可以了,但是如果需要涉及到比较复杂的数据处理和操作就用绑定服务的方法来启动服务。.IntentService的使用示例程序设计:查找手机 SD卡中的所有图片显示在 UI界面上。(一)布局文件 activity_main.xml 文件实际<?xmlversion="1.0"encoding="utf-8"?>android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"><ListViewandroid:id="@+id/main_lv"android:layout_width="match_parent"android:layout_height="match_parent"></ListView></RelativeLayout>非常简单的布局设计,使用 ListView来显示所有的图片(二)遍历文件的工具类的设计/**SD卡的路径:Environment.getExternalStorageDirectory()*/publicclassFileUtils{/**获得指定目录下的所有的图片*/publicstaticfinalArrayList<File>getAllPicture(Filedir){ArrayList<File>files=getAllFile(dir);ArrayList<File>imgList=newArrayList<>();for(Filefile:files){if(file.getName().endsWith(".png")||file.getName().endsWith(".jpg"))imgList.add(file);}returnimgList;}/**递归遍历文件夹的方法*/publicstaticfinalvoidgetFileFromDir(Filedir,List<File>fileList){File[]files=dir.listFiles();if(files==null)return;for(Filefile:files){if(file.isDirectory())getFileFromDir(file,fileList);fileList.add(file);}}/**获得根目录下的所有图片*/publicstaticfinalArrayList<File>getAllPicture(){returngetAllPicture(Environment.getExternalStorageDirectory());}}(三)简化 BaseAdapter的一个工具类/**这是一个简化BaseAdapter适配器的工具类*这是使用的是定义一个泛型 T,使用时传入什么数据, T就是什么数据实际设计中除了getVIew方法外,其他的方法基本是差不多的*所以继承这个工具类后只要重写 getView方法,就可以使用 BaseAdapter了*/publicabstractclassListItemAdapter<T>extendsBaseAdapter{List<T>list=newArrayList<>();Contextcontext;ListItemAdapter(Contextcontext,List<T>list){this.context=context;this.list=list;}ListItemAdapter(Contextcontext,T[]list){this.context=context;for(Tt:list){}}@OverridepublicintgetCount(){returnlist==null?0:list.size();}@OverridepublicTgetItem(intposition){returnlist==null?null:list.get(position);}@OverridepubliclonggetItemId(intposition){returnposition;}}(四)MyIntentService的创建/***IntentService的使用*IntentService是Service的子类,也需要在 xml中注册*它有自定义的子线程的方法*这里主要需要解决的问题是资源文件得到后怎么把数据传递给 UI线程的Activity*/publicclassMyIntentServiceextendsIntentService{/**通过构造方法,传入子线程的名字但是这里必须要创建一个无参的构造方法*/publicMyIntentService(){super("myService");}/**这是在子线程中的执行操作*/@OverrideprotectedvoidonHandleIntent(Intentintent){Log.e("TAG","子线程开始工作 ");//遍历文件夹获取图片ArrayList<File>list=FileUtils.getAllPicture();//使用handler发送信息Messagemsg=Message.obtain();//这里给handler对象传递一个对象msg.obj=list;//发送广播来传递数据Intentintent1=newIntent("filefinish");intent1.putExtra("file",list);sendBroadcast(intent1);}@OverridepublicvoidonCreate(){super.onCreate();Log.e("TAG","onCreate");}@OverridepublicvoidonDestroy(){super.onDestroy();Log.e("TAG","onDestroy");}}这里的IntentService的注册和 Intent的注册是一样的。(五)MainActivity 中的代码设计/**这里使用服务来IntentService来遍历文件夹在程序创建的使用就要启动服务在页面销毁的时候就停止服务但是Service执行完任务后还有传递数据给 MainActivity在MainActivity中才能进行UI界面的更新这就涉及到 Service和Activity 的数据传递问题了这里使用的是用广播来传递数据*/publicclassMainActivityextendsAppCompatActivity{//定义布局内的控件ListViewlistView;//定义适配器的数据的集合//一定要static???staticArrayList<File>fileList;staticMyBaseAdapteradapter;MyBroadcastReceivermbcr;@Overridembcr=newMyBroadcastReceiver();//动态注册一个广播IntentFilterfilter=newIntentFilter();filter.addAction("filefinish");registerReceiver(mbcr,filter);// 注册//创建适配器的对象adapter=newMyBaseAdapter(this,fileList);//实例化布局内的控件//给listView设置适配器listView.setAdapter(adapter);//启动服务startService(newIntent(this,MyIntentService.class));}//创建适配器的类classMyBaseAdapterextendsListItemAdapter<File>{MyBaseAdapter(Contextcontext,List<File>list){super(context,list);}@OverridepublicViewgetView(intposition,ViewconvertView,ViewGroupparent){ImageViewimage=null;if(convertView==null){image=newImageView(getBaseContext());convertView=image;}else{image=(ImageView)convertView;}设置图片资源和属性image.setImageURI(Uri.fromFile(fileList.get(position)));image.setAdjustViewBounds(true);returnimage;}}//停止服务publicvoidstop(){stopService(newIntent(MainActivity.this,MyIntentService.class));}@OverrideprotectedvoidonDestroy(){super.onDestroy();//即使之前停止了服务,再次停止服务也是不会报错的stop();//解除广播unregisterReceiver(mbcr);}//动态创建广播接收者classMyBroadcastReceiverextendsBroadcastReceiver{@OverridepublicvoidonReceive(Contextcontext,Intentintent){对接收到的广播进行处理,intent里面包含数据fileList=(ArrayList<File>)intent.getSerializableExtra("file");刷新适配器adapter.notifyDataSetChanged();停止服务,它的子线程也会停止stop();}}}程序运行前还记得加上 SD卡的访问权限;上面程序功能还是有点问题!遍历完文件后。页面没有马上更新?退出程序再进来,页面上马上显示SD卡的图片。一般的说遍历文件夹也不算是耗时操作,这里只是简单示范。一般的耗时操作是从网络下载数据,或本地移动大文件等等。五.同一个程序中 Service和Activity 通信的一些方式,这里展示主要代码。这里组件不要忘记在 AndroidManifest 中注册(一)使用 Intent来传递数据1.MainActivity 中的代码,发送数据Intentintent=newIntent(this,MyService.class);intent.putExtra("msg","activity向service传递一个helloservice");startService(intent);2.MyService中的代码,接收数据这里要使用 onStartCommand的方法来接收 Intent的数据,如果上面使用的是 bind的方法来启动服务,这里可以在 onBind方法中接收数据。@OverridepublicintonStartCommand(Intentintent,intflags,intstartId){Log.e("onStartCommand",intent.getStringExtra(msg));returnsuper.onStartCommand(intent,flags,startId);}(二)使用单例模式来传递数据这个方法算是有点麻烦的吧!这里要在MyService类中先做好单例,然后在Activity中调用MyService对象的方法1.MyService中的代码//定义一个静态的类变量,单例的使用准备privatestaticMyServiceinstance;//静态方法,返回的是一个本类对象//为了能让另一边的类调用 Myservice的方法publicstaticMyServicegetInstance(){returninstance;}@OverridepublicvoidonCreate(){super.onCreate();//单例模式变量赋值instance=this;}publicvoidprint(Stringmsg){Log.e("service",msg);}其中print方法是在 Activity 中调用的,可以达到传送数据给 MyService,但是这里要先启动过服务后才能使用单例,因为这里是在 MyService的onCreate方法中把对象赋值给instance,之后才能实现单例。2.MainActivity 中的代码:/**单例模式传参*MyService这里通过一个静态方法,来获得 MyService这里通过 MyService.getInstance()方法来获得 MyService对象

的对象*///必须保证

Myservice

对象不能为

null//静态的变量,最后释放(不用的时候,手动将

static变量=null)if(MyService.getInstance()!=null){MyService.getInstance().print("

使用单例从

activity

中调用

service的方法

");}(三)广播传参传数据弄两个广播接收者相互传数据。这里要在MyService和MyService中分别动态的创建广播接收者和动态注册广播接收者,然后在MainActivity中发送广播,在MyService中接收到广播传来递数据后,在发送广播,让MainActivity接收广播数据!1.MyService中的代码:@OverridepublicvoidonCreate(){super.onCreate();//动态注册广播接收者 ,要定义好接收的 action属性值IntentFilterfilter=newIntentFilter("service");registerReceiver(serviceReceiver,filter);}//定义一个广播接收者 BroadcastReceiverBroadcastReceiverserviceReceiver=newBroadcastReceiver(){@OverridepublicvoidonReceive(Contextcontext,Intentintent){Log.e("service","接收到了activity发送的广播:"+intent.getStringExtra("msg"));//发送广播给MainActivitysendBroadcast(newIntent("activity").putExtra("msg"," 发送给activity的消息"));}};2.MainActivity 中的代码:@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);//注册本类内的广播 ,定义好action的属性值IntentFilterfilter=newIntentFilter("activity");registerReceiver(activityReceiver,filter);}/**通过广播来传递数据*/publicvoidsendBroadcast(Viewview){//指明action属性值Intentintent=newIntent("service");intent.putExtra("msg","activity 向广播传递一个 hellobroadcast");sendBroadcast(intent);}//定义一个内部类的广播接收者,用于接收 MyService传递过来的数据BroadcastReceiveractivityReceiver=newBroadcastReceiver(){@OverridepublicvoidonReceive(Contextcontext,Intentintent){Log.e("activity",intent.getStringExtra("msg"));}};(四)

MyService

实例调用方法这个方法是最最麻烦的方法了!涉及到一个Binder类的使用!这里要被调用的方法其实不是MyService中的方法,而是里面的内部接口的抽象方法,需要在MainActivity中去实现这个方法!但是,实际这个方法实在MyService中执行的。1.MyService中的代码://定义一个接口interfaceCallback{//定义两个要实现的方法voidcall();voidstart();}//定义一个接口对象Callbackcallback;/***创建Binder类,很多很多的 Service就是通过 Binder机制来和客户端通讯交互的。*/classMybinderextendsBinder{publicMyServicegetService(){returnMyS

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论