-onDestroy()-Servicestop 如果Service还没有运行,则android先调用onCreate()然后调用onStart();如果Service已经运行,则只调用onStart(),所以一个Service的onStart方法可能会重复调用多次。 stopService的时候直接onDestroy,如果是调用者自己直接退出而没有调用stopService的话,Service会一直在后台运行。该Service的调用者再启动起来后可以通过stopService关闭Service。 所以调用startService的生命周期为:onCreate--onStart(可多次调用)--onDestroy 使用使用context.bindService()启动Service会经历: context.bindService()-onCreate()-onBind()-Servicerunning onUnbind()-onDestroy()-Servicestop onBind将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service运行的状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind-onDestroy相应退出。 所以调用bindService的生命周期为:onCreate--onBind(只一次,不可多次绑定)--onUnbind--onDestory。 在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。而启动service,根据onStartCommand的返回值不同,有两个附加的模式: 1.START_STICKY用于显示启动和停止service。 2.START_NOT_STICKY或START_REDELIVER_INTENT用于有命令需要处理时才运行的模式。 服务不能自己运行,需要通过调用Context.startService()或Context.bindService()方法启动服务。这两个方法都可以启动Service,但是它们的使用场合有所不同。 1.使用startService()方法启用服务,调用者与服务之间没有关连,即使调用者退出了,服务仍然运行。 如果打算采用Context.startService()方法启动服务,在服务未被创建时,系统会先调用服务的onCreate()方法,接着调用onStart()方法。 如果调用startService()方法前服务已经被创建,多次调用startService()方法并不会导致多次创建服务,但会导致多次调用onStart()方法。 采用startService()方法启动的服务,只能调用Context.stopService()方法结束服务,服务结束时会调用onDestroy()方法。 2.使用bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。 onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。 采用Context.bindService()方法启动服务时只能调用onUnbind()方法解除调用者与服务解除,服务结束时会调用onDestroy()方法。 看看官方给出的比较流程示意图: 官方文档告诉我们,一个service可以同时start并且bind,在这样的情况,系统会一直保持service的运行状态如果service已经start了或者BIND_AUTO_CREATE标志被设置。如果没有一个条件满足,那么系统将会调用onDestory方法来终止service.所有的清理工作(终止线程,反注册接收器)都在onDestory中完成。 拥有service的进程具有较高的优先级 官方文档告诉我们,Android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindService)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级。 1.如果service正在调用onCreate,onStartCommand或者onDestory方法,那么用于当前service的进程则变为前台进程以避免被killed。 2.如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed. 3.如果客户端已经连接到service(bindService),那么拥有Service的进程则拥有最高的优先级,可以认为service是可见的。 4.如果service可以使用startForeground(int,Notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。三、BroadcastReceiver详解 BroadcastReceiver用于异步接收广播Intent。主要有两大类,用于接收广播的: ·正常广播Normalbroadcasts(用Context.sendBroadcast()发送)是完全异步的。它们都运行在一个未定义的顺序,通常是在同一时间。这样会更有效,但意味着receiver不能包含所要使用的结果或中止的API。 ·有序广播Orderedbroadcasts(用Context.sendOrderedBroadcast()发送)每次被发送到一个receiver。所谓有序,就是每个receiver执行后可以传播到下一个receiver,也可以完全中止传播--不传播给其他receiver。而receiver运行的顺序可以通过matchedintent-filter里面的android:priority来控制,当priority优先级相同的时候,Receiver以任意的顺序运行。 要注意的是,即使是Normalbroadcasts,系统在某些情况下可能会恢复到一次传播给一个receiver。特别是receiver可能需要创建一个进程,为了避免系统超载,只能一次运行一个receiver。 BroadcastReceiver并没有提供可视化的界面来显示广播信息。可以使用Notification和NotificationManager来实现可视化的信息的界面,显示广播信息的内容,图标及震动信息。 生命周期 一个BroadcastReceiver对象只有在被调用onReceive(Context,Intent)的才有效的,当从该函数返回后,该对象就无效的了,结束生命周期。 因此从这个特征可以看出,在所调用的onReceive(Context,Intent)函数里,不能有过于耗时的操作,不能使用线程来执行。对于耗时的操作,请startservice来完成。因为当得到其他异步操作所返回的结果时,BroadcastReceiver可能已经无效了。 发送广播 事件的广播比较简单,构建Intent对象,可调用sendBroadcast(Intent)方法将广播发出。另外还有sendOrderedBroadcast(),sendStickyBroadcast()等方法,请查阅APIDoc。 1.newIntentwithactionname Intentintent=newIntent(Stringaction); 或者只是newIntent,然后 intent.setAction(Stringaction); 2.setdata等准备好了后,inactivity, sendBroadcast(Intent);//发送广播 接收广播 通过定义一个继承BroadcastReceiver类来实现,继承该类后覆盖其onReceiver方法,并在该方法中响应事件。publicclassSMSReceiverextendsBroadcastReceiver{
OverridepublicvoidonReceive(Contextcontext,Intentintent){//getdatafromSMSintentBundlebundle=intent.getExtras();if(bundle!=null){//getmessagebypdusObject[]objArray=(Object[])bundle.get(pdus);//rebuildSMSSmsMessage[]messages=newSmsMessage[objArray.length];for(inti=0;iobjArray.length;i++){messages[i]=SmsMessage.createFromPdu((byte[])objArray[i]);StringBuilderstr=newStringBuilder(from:);str.append(messages[i].getDisplayOriginatingAddress());str.append(\nmessage:\n);str.append(messages[i].getDisplayMessageBody());Toast.makeText(context,str.toString(),Toast.LENGTH_LONG).show();}}}}复制代码 注册Receiver 注册有两种方式: 1.静态方式,在AndroidManifest.xml的application里面定义receiver并设置要接收的action。 receiverandroid:name=.SMSReceiver intent-filter actionandroid:name=android.provider.Telephony.SMS_RECEIVED/ /intent-filter /receiver复制代码2.动态方式,在activity里面调用函数来注册,和静态的内容差不多。一个形参是receiver,另一个是IntentFilter,其中里面是要接收的action。publicclassHelloDemoextendsActivity{privateBroadcastReceiverreceiver;OverrideprotectedvoidonStart(){super.onStart();receiver=newCallReceiver();registerReceiver(receiver,newIntentFilter(android.intent.action.PHONE_STATE));}OverrideprotectedvoidonStop(){unregisterReceiver(receiver);super.onStop();}}复制代码 一个receiver可以接收多个action的,即可以有多个intent-filter,需要在onReceive里面对intent.getAction(actionname)进行判断。 个人推荐使用静态注册方式,由系统来管理receiver,而且程序里的所有receiver,可以在xml里面一目了然。而动态注册方式,隐藏在代码中,比较难发现。 而且动态注册,需要特别注意的是,在退出程序前要记得调用Context.unregisterReceiver()方法。一般在activity的onStart()里面进行注册,onStop()里面进行注销。官方提醒,如果在Activity.onResume()里面注册了,就必须在Activity.onPause()注销。 Permission权限 要接收某些action,需要在AndroidManifest.xml里面添加相应的permission。例如接收SMS:uses-permissionandroid:name=android.permission.RECEIVE_SMS/复制代码 下面给出动态注册的接收来电的广播处理的CallReceiver的代码: 一种方式是直接读取intent.getStringExtra(in 在运行时,发现除了响铃时可以获取来电号码,接听和挂断都不能成功获取的,显示为null。 另一种方式是通过PhoneStateListener的onCallStateChanged来监听状态的变化:publicclassCallReceiverextendsBroadcastReceiver{privateContextm_context;OverridepublicvoidonReceive(Contextcontext,Intentintent){m_context=context;TelephonyManagerteleManager=(TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);teleManager.listen(newPhoneStateListener(){OverridepublicvoidonCallStateChanged(intstate,Stringin 因为这里监听的是通话的状态变化,所以这个receiver会被调用3次。 监听通话状态需要加上权限:uses-permissionandroid:name=android.permission.READ_PHONE_SATE/复制代码小结: 1.对于sendBroadCast的intent对象,需要设置其actionname; 2.推荐使用显式指明receiver,在配置文件AndroidManifest.xml指明; 3.一个receiver可以接收多个action; 4.每次接收广播都会重新生成一个接收广播的对象,再次调用onReceive; 5.在BroadCast中尽量不要处理太多逻辑问题,建议复杂的逻辑交给Activity或者Service去处理。四、ContentProvider详解 ContentProvider(内容提供者)是Android中的四大组件之一。主要用于对外共享数据,也就是通过ContentProvider把应用中的数据共享给其他应用访问,其他应用可以通过ContentProvider对指定应用中的数据进行操作。ContentProvider分为系统的和自定义的,系统的也就是例如联系人,图片等数据。 android中对数据操作包含有: file,sqlite3,Preferences,ContectResolver与ContentProvider前三种数据操作方式都只是针对本应用内数据,程序不能通过这三种方法去操作别的应用内的数据。 android中提供ContectResolver与ContentProvider来操作别的应用程序的数据。 使用方式: 一个应用实现ContentProvider来提供内容给别的应用来操作, 一个应用通过ContentResolver来操作别的应用数据,当然在自己的应用中也可以。 以下这段是GoogleDoc中对ContentProvider的大致概述: 内容提供者将一些特定的应用程序数据供给其它应用程序使用。内容提供者继承于ContentProvider基类,为其它应用程序取用和存储它管理的数据实现了一套标准方法。然而,应用程序并不直接调用这些方法,而是使用一个ContentResolver对象,调用它的方法作为替代。ContentResolver可以与任意内容提供者进行会话,与其合作来对所有相关交互通讯进行管理。 1.ContentProvider Android提供了一些主要数据类型的ContentProvider,比如音频、视频、图片和私人通讯录等。可在android.provider包下面找到一些Android提供的ContentProvider。通过获得这些ContentProvider可以查询它们包含的数据,当然前提是已获得适当的读取权限。 主要方法: publicbooleanonCreate()在创建ContentProvider时调用 publicCursorquery(Uri,String[],String,String[],String)用于查询指定Uri的ContentProvider,返回一个Cursor publicUriinsert(Uri,ContentValues)用于添加数据到指定Uri的ContentProvider中 publicintupdate(Uri,ContentValues,String,String[])用于更新指定Uri的ContentProvider中的数据 publicintdelete(Uri,String,String[])用于从指定Uri的ContentProvider中删除数据 publicStringgetType(Uri)用于返回指定的Uri中的数据的MIME类型 *如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头。 例如:要得到所有person记录的Uri为content://contacts/person,那么返回的MIME类型字符串为vnd.android.cursor.dir/person。 *如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头。 例如:要得到id为10的person记录的Uri为content://contacts/person/10,那么返回的MIME类型字符串应为vnd.android.cursor.item/person。 2.ContentResolver 当外部应用需要对ContentProvider中的数据进行添加、删除、修改查询操作时,可以使用ContentResolver类来完成,要获取ContentResolver对象,可以使用Context提供的getContentResolver()方法。 ContentResolvercr=getContentResolver(); ContentResolver提供的方法和ContentProvider提供的方法对应的有以下几个方法。 publicUriinsert(Uriuri,ContentValuesvalues)用于添加数据到指定Uri的ContentProvider中。 publicintdelete(Uriuri,Stringselection,String[]selectionArgs)用于从指定Uri的ContentProvider中删除数据。 publicintupdate(Uriuri,ContentValuesvalues,Stringselection,String[]selectionArgs)用于更新指定Uri的ContentProvider中的数据。 publicCursorquery(Uriuri,String[]projection,Stringselection,String[]selectionArgs,StringsortOrder)用于查询指定Uri的ContentProvider。 3.Uri Uri指定了将要操作的ContentProvider,其实可以把一个Uri看作是一个网址,我们把Uri分为三部分。 第一部分是content://。可以看作是网址中的 第二部分是主机名或authority,用于唯一标识这个ContentProvider,外部应用需要根据这个标识来找到它。可以看作是网址中的主机名,比如blog.csdn.net。 第三部分是路径名,用来表示将要操作的数据。可以看作网址中细分的内容路径。(本文来源网络,版权归原作者所有,如有侵权问题请联系我们!)重要的事情说三遍求北京白癜风北京白癜风最好的医院