版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Android主要开发组件目标学员:学习目标:
课程时长:Android中级开发者ActivityIntentContentProviderServiceBroadcastReceiver6学时,270分钟1Activity2Intent4Service3ContentProvider课程目录4BroadcastReceiver5理解Android应用中四大重要组件及BroadcastReceiver熟练使用Android四大组件及BroadcastReceiver进行项目开发Activity生命周期Intent的传输机制ContentProvider的存储机制Service的使用AIDL服务1Activity2Intent4Service3ContentProvider课程目录4BroadcastReceiver5Activity对开发者而言,Activity是Android应用程序的入口。在Activity类中定义了一系列的生命周期方法,比如onCreate()、onResume()、onStart()、onPause()、onStop()和onDestroy(),Android系统会在适当的时候调用对应的生命周期方法。
Activity的状态运行
当Activity位于堆栈的顶部时,它就处于运行状态(active)。暂停
当Activity失去了焦点,但是依然可见时,Activity就处于暂停状态(paused),维持着成员信息和所有状态。停止
当Activity完全被其他的Activity覆盖时,它就处于停止状态(stopped),处于停止状态的Activity依然维持着成员信息和所有状态,只是变得不可见了。销毁
当Activity处于停止或者暂停状态时,系统可能要求它结束生命周期,或者直接把它所在的进程杀死,进而从内存中删除它,此时的Activity就被销毁了。Activity的生命周期图publicclassActivityextendsApplicationContext{protectedvoidonCreate(){}protectedvoidonStart(){}protectedvoidonRestart(){}protectedvoidonResume(){}protectedvoidonPause(){}protectedvoidonStop(){}protectedvoidonDestroy(){}}创建Activitypackagecom.chinasofti.etc;importandroid.app.Activity;importandroid.os.Bundle;publicclassHelloActivityextendsActivity{@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);}}注册Activity<xmlversion="1.0"encoding="utf-8"><manifestxmlns:android="/apk/res/android"package="com.chinasofti.etc"android:versionCode="1"android:versionName="1.0"><applicationandroid:icon="@drawable/icon"android:label="@string/app_name"><activityandroid:name=".HelloActivity"android:label="@string/app_name"><intent-filter><actionandroid:name="ent.action.MAIN"/><categoryandroid:name="ent.category.LAUNCHER"/></intent-filter></activity></application><uses-sdkandroid:minSdkVersion="7"/></manifest>启动ActivitystartActivity(Intent)方法用于启动一个新的Activity
当Activity位于堆栈的顶部时,它就处于运行状态(active)。startActivityForResult(Intent,int)可以用于启动Activity并返回结果
其中参数int代表本次调用 onActivityResult(int,int,Intent)方法返回数据
ActivityAintentActivityBActivity之间传递数据protectedvoidonListItemClick(ListViewl,Viewv,intposition,longid){ super.onListItemClick(l,v,position,id); Intentintent=newIntent(this,DetailActivity.class); intent.putExtra("name",peoples[position]); startActivity(intent);} protectedvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); //获得Intent并从中读取附带的数据
Intentintent=getIntent(); Stringname=intent.getStringExtra("name"); TextViewview=newTextView(this); view.setText("您选择了"+name); setContentView(view); }演示Activity生命周期演示Activity的生命周期本节的例子代码是demo\activity运行此案例,ContactsActivity和DetailActivity界面分别如下图所示,我们可以在Eclipse开发工具中切换到DDMS页面查看ContactsActivity及DetailActivity的生命周期情况。演示Activity生命周期处理配置变化Activity是与用户交互最主要的机制,当设备的配置(屏幕方向、语言)等发生变化时,系统应该采取必要的措施处理此状况。在AndroidManifest.xml中通过定义android:configChanges属性来指明监听的配置变化,当配置发生变化时,Activity的onConfigurationChanged()方法会被调用,开发者可以在这里处理。如果未做任何处理,由于设备的配置变化往往需要应用重新装载资源,因此系统会销毁Activity并重新启动。Configuration类简介Configuration类专门用于描述手机设备上的配置信息,这些配置信息既包括用户特定配置项,也包括系统的动态设备配置.
获取Configuration对象的方法:getResources().getConfiguration();
该类的一些描述系统信息的属性:floatfontScale:字体缩放因子intkeyBoard:键盘类型.KEYBOARD_NOKEYS,KEYBOARD_QWERTY,KEYBOARD_12KEYintkeyboardHidden:当前键盘是否可用.Localelocale:intmcc:移动信号国家码intmnc:移动信号网络码intnavigation:方向导航设备的类型.NAVIGATION_NONAV,NAVIGATION_DPADNAGIVATION_TRACKBALL,VAGIVATION_WHEELintorientation:ORIENTATION_LANDSCAPE(横向),ORIENTATION_PORTRAIT(竖向),ORIENTATION_SQUARE(方形)inttouchscreen:TOUCHSCREEN_NOTOUCH,TOUCHSCREEN_STYLUSTOUCHSCREEN_FINGER案例1:获取系统设备状态Configurationc=MainActivity.this.getResources().getConfiguration();Stringscreen=c.orientation==Configuration.ORIENTATION_LANDSCAPE"横向屏幕":"竖向屏幕";StringmncCode=c.mcc+"";StringnaviName=c.orientation==c.NAVIGATION_NONAV"没有方向控制":c.orientation==c.NAVIGATION_WHEEL"滚轮控制方向":c.orientation==c.NAVIGATION_TRACKBALL"轨迹球控制方向":c.orientation==c.NAVIGATION_DPAD"dpad控制方向盘":"未指定";Stringtouchname=c.touchscreen==c.TOUCHSCREEN_FINGER"指控":c.touchscreen==c.TOUCHSCREEN_STYLUS"手写笔":"无触摸屏";
参见案例:test_configuration1案例2:重写onConfigurationChanged响应系统设置更改需求说明:调用Activity中的setRequestedOrientation(int)方向来修改屏幕的方向,在onConfigurationChanged()中监听这个变化。
步骤:1.配置:
<!--授予程序修改系统设置的权限--><uses-permissionandroid:name="android.permission.CHANGE_CONFIGURATION"/>
<activityandroid:name=".MainActivity"android:label="@string/app_name"
android:configChanges="orientation"
>2.使用一个按钮来改变屏幕方向
publicvoidonClick(Viewv){ Configurationc=MainActivity.this.getResources().getConfiguration(); if(c.orientation==Configuration.ORIENTATION_LANDSCAPE){ MainActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } if(c.orientation==Configuration.ORIENTATION_PORTRAIT){ MainActivity.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } }
案例2:重写onConfigurationChanged响应系统设置更改步骤三:重写onConfigurationChanged方法.@Override//重写onConfigurationChanged方法用于监听publicvoidonConfigurationChanged(ConfigurationnewConfig){super.onConfigurationChanged(newConfig);Stringscreen=newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE"横向":"竖向";Toast.makeText(MainActivity.this,screen,Toast.LENGTH_LONG).show();}常见面试问题1.横竖屏切换时候activity的生命周期
1、不设置Activity的android:configChanges时,切屏会重新调用各个生命周期
2、设置Activity的android:configChanges="orientation"时,不会重走生命周期.
案例:test_configuration3如何将一个Activity设置成窗口的样式。
在AndroidManifest.xml中定义Activity的地加方一句话android:theme="@android:style/Theme.Dialog"常见面试问题如果后台的Activity由于某原因被系统回收了,如何在被系统回收之前保存当前状态
onSaveInstanceState()
当你的程序中某一个ActivityA在运行时,主动或被动地运行另一个新的ActivityB,这个时候A会执行onSaveInstanceState()。B完成以后又会来找A,这个时候就有两种情况:一是A被回收,二是A没有被回收,被回收的A就要重新调用onCreate()方法,不同于直接启动的是这回onCreate()里是带上了参数savedInstanceState;而没被收回的就直接执行onResume(),跳过onCreate()了。Handler消息传递机制Android平台不允许Activity新启动的线程访问该Activity里的界面组件,会导致新启动的线程无法动态改变界面组件的属性值。这时就要采用Handler的消息传递机制来实现了.Handler的作用:1.在新启动的线程中发送消息2.在主线程中获取,处理消息.
开发者只要重写Handler类中处理消息的方法,当新启动的线程发送消息(调用handler对象的sendMessage()方法)时,Handler类中处理消息的方法会被自动回调.Handler类的常用方法:voidhandleMessage(Messagemsg);finalbooleanhasMessage(intwhat):finalbooleanhasMessages(intwhat,Objectobject):MessageobtainMessage():sendEmptyMessage(intwhat):finalbooleansendEmptyMessageDelayed(intwhat,longdelayMillis):finalbooleansendMessage(Messagemsg):Handler案例案例要求:通过一个线程来周期性地修改ImageView所显示的图片.参考源代码:test_handler1finalImageViewimageview=(ImageView)this.findViewById(R.id.imageview);finalHandlerhandler=newHandler(){
publicvoidhandleMessage(Messagemsg){ if(msg.what==1){ imageview.setImageResource(imageids[currentid++]); if(currentid>=4){ currentid=0; } } } };newTimer().schedule(newTimerTask(){ publicvoidrun(){
Messagem=newMessage(); m.what=1; handler.sendMessage(m); }
},0,800);1Activity2Intent与IntentFilter4Service3ContentProvider课程目录4BroadcastReceiver5Intent简介问题:假如甲Activity要启动另一个Activity,为何不直接使用一个形如startActivity(ClassactivityClass)的方法,这样比较直接
实际上android使用Intent来封装程序的调用意图,不管程序想启动一个Activity,Service,还是broadcastReceiver,android使用统一的Intent对象来封装这种”意图”,提供了一致的编程模型.
另外采用意图也实现解耦.使用Intent启动系统组件类型启动方法ActivitystartActivity(Intent)startActivityForResult(Intent,int)serviceComponentNamestartService(Intent)BooleanbindService(Intent,ServiceConnection,int)broadcastreceiversendBroadcast(Intent)sendBroadcast(Intent,String)sendOrderedBroadcast(Intent,String,BraodcastREceiver,Handler,int,String,Bundle)sendStickyBroadcast(Intent)sendStickyOrderedBroadcast(Intent,BroadcastReceiver,Handler,int,String,Bundle);IntentIntent可以看做是Activity之间的桥梁
Action:ACTION_VIEW,ACTION_EDIT,ACTION_MAIN Data:封装的数据,以Uri格式表示 Category:标志动作执行的分类,例如CATEGORY_LAUNCHER Type:MIME Component:标明Intent指向的组件class Extras:用于在Intent中携带一些数据信息
Intent的成员-ComponentNameIntent中的Component属性需要接受一个ComponentName对象,该对象的构造方法如下:ComponentName(Stringpkg,Stringcls):ComponentName(Contextpkg,Stringcls):ComponentName(Contextpkg,Class<>cls):ComponentName是处理此Intent的组件的名字,例如 com.chinasofti.etc.HelloActivity。 ComponentName是可选的,如果被设定,那么系统将直接将其
值作为处理Intent的组件。
可以通过Intent.setClass(),Intent.setComponent()等方法设置 ComponentName。
如果没有设置ComponentName,那么系统根据Intent_Filter的定义去匹配处理Intent组件onConfigurationChanged响应系统设置更改地么那么案例1-示范Component1.事件绑定open.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){ComponentNamecn=newComponentName(MainActivity.this,SecondActivity.class);Intentintent=newIntent();intent.setComponent(cn);//为Intent设置ComponentName属性startActivity(intent);}});配置<activityandroid:name=".SecondActivity"android:label="第二个窗口"/>3.第二个窗口
TextViewresult=(TextView)this.findViewById(R.id.result);ComponentNamecn=this.getIntent().getComponent();result.setText("包名:"+cn.getPackageName()+"\n类名:"+cn.getClassName());Intent之ActionAction本质上就是一个字符串常量,代表intent要完成的一个抽象”动作”.这个动作具体由哪个组件(Activity或是BoardcastReceiver)来完成,action并不管.如Android提供的标准动作:
Intent.ACCTION_VIEW,它只表示一个抽象的查看操作,但具体看什么,启动哪个Activity来看,它并不知道,而取决于Activity中的<intent-filter…/>配置,只要某个Activity配置中包含了该Action_view动作,则该Activity就可能启动.Action案例1步骤一:打开新窗口代码:open.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){ Intentintent=newIntent(); //注意:在这里并没有设置一个具体的要打开的activity组件 //而只是一个字符串.
intent.setAction("com.icss.myaction");//一个Intent对象只能设置一个Action //在没有设置Category类别的情况下,相当于设置了默认类别,//一个intent对象可以设置多个category //intent.addCategory(Intent.CATEGORY_DEFAULT); //因此在Intent-filter中,要设置对应的category startActivity(intent); }});Action案例1步骤二:新窗口的配置文件:
注意:在这里,intent-filter通常可以包含如下元素:0-N个<action…/>子元素0-N个<category…/>子元素0-N个<data…/>子元素<activityandroid:name=".SecondActivity"android:label="新窗口"><intent-filter><actionandroid:name="com.icss.myaction"/><categoryandroid:name="ent.category.DEFAULT"/></intent-filter></activity>Intent的成员-CategoryCategory的含义与Action类似,Category也是一段字符串常量不同的是一个Intent对象可以加多个CategoryCategory描述的信息可以帮助系统确定处理Intent的组件调用Intent.addCategory()可以在Intent中增加一个Category常量含义CATEGORY_HOME当设备启动后,用户看到的第一个Activity或者当用户按下HOME键时显示给用户的Activity。CATEGORY_LAUNCHERActivity是一个task的初始Activity,并且此Activity会被显示在启动面板上。系统标准Action系统标准CategoriesIntent的成员-Data,TypeData的含义Data属性用于向Action属性提供操作的数据.Data属性接受一个Uri对象,形式如下:content://com.android.contacts/contacts/1tel:123Data是以URI代表的数据和MIME代表的数据类型的集合Type属性用于明确指定Data属性的类型或MIME型.通常当Intent不指定Data属性时Type属性才会起作用.Intent的成员-Data,Type.一旦为Intent同时指定了Action,Data属性,那么Android将可根据指定的数据类型来启动特定的应用程序,并对指定数据执行相应的操作.
下面是一些Action与Data属性的组合.ACTION_VIEW:content://com.android.contacts/contacts/1:ACTION_EDIT:content://com.android.contacts/contacts/1ACTION_DIAL:content://com.android.contacts/contacts/1ACTION_VIEW:tel:123案例-Action,Data案例publicvoidonClick(Viewv){ Intentintent=newIntent(); Stringdata=""; Uriuri=Uri.parse(data); intent.setAction(Intent.ACTION_VIEW); intent.setData(uri); startActivity(intent);}Intent的成员-ExtrasExtras的含义Extras包含了键-值数据对,用于向目标组件传递数据。Intent中包含了一系列的putExtra()和getExtra()方法用于存储和读取相关的数据类型。//存储一个nameintent.putExtra("name",peoples[position]);//读取存入的nameStringname=intent.getStringExtra("name");Intent解析显式解析,调用setComponent(Component)或setClass(Context,Class)设置Intent指定的运行类。Intentintent=newIntent(this,DetailActivity.class);intent.putExtra("name",peoples[position]);startActivity(intent);隐式解析,未直接标注组件,但是需要提供足够的信息以便系统能够确定运行哪个class。Intentintent=newIntent();intent.setAction(Intent.ACTION_MAIN);intent.addCategory(Intent.CATEGORY_HOME);startActivity(intent);使用Intent调用系统组件浏览器调用Uriuri=Uri.parse("");Intentit=newIntent(Intent.ACTION_VIEW,uri);context.startActivity(it);电话功能调用Uriuri=Uri.parse("tel:2125551212");Intentit=newIntent(Intent.ACTION_CALL,uri);context.startActivity(it);演示Intent启动Activity用Intent启动Activity,并在Activity之间传递数据本节的例子代码是demo\intent在同一个应用程序中往往会使用Intent对象来指定一个Activity,并通过startActivity或startActivityForResult方法启动这个Activity。除此之外,通过Intent还可以调用其他应用程序中的Activity。在AndroidSDK中甚至还允许开发人员自定义ActivityAction。运行本节的例子,单击【开始另一个Activity】按钮,会显示Brower,输出的信息如下图所示。用Intent启动Activity,并在Activity之间传递数据演示调用其他应用程序中的Activity调用其他应用程序中的Activity本节的例子代码是demo\invokeotherapp运行本节的例子,界面如下图所示。1Activity2Intent4Service3ContentProvider课程目录4BroadcastReceiver5ContentProviderAndroid平台主要提供了文件,SharedPreference,数据库和ContentProvider四种持久化存储方案。ContentProvider是唯一一种能在应用程序之间共享数据的方案。Android上内置的ContentProvider。
音频
视频
联系人
通话记录ContentProvider数据的存储方式ContentProvider不限制底层数据的存储方式,子类可以通过扩展以下抽象方式实现自己的ContentProviderquery(Uri,String[],String,String[],String)insert(Uri,ContentValues)update(Uri,ContentValues,String,String[])delete(Uri,String,String[])getType(Uri)使用ContentResolver接口对ContentProvider进行数据操作ContentResolverresolver=getContentResolver创建一个ContentProvider选择存储数据的方案,通常使用SQLite数据库来存储数据扩展ContentProvider类,实现其中定义的抽象方法,实现数据访问。在AndroidManifest.xml中声明ContentProvider:<providerandroid:name="ContactContentProvider" android:authorities="com.A.mobile.contactcontentprovider"</provider> 使用ContentProvider获取音频数据使用ContentProvider获取SD卡中音频数据本节的例子代码是demo\musicActivity在本例子中,由于需要挂载SD卡,所以需要首先创建一个SD卡,并向SD卡上传输一些MP3歌曲。向模拟器的SD卡中传输文件的方式如下:使用ContentProvider获取音频数据本例运行后的界面如下图所示:1Activity2Intent4Service3ContentProvider课程目录4BroadcastReceiver5Service介绍让程序在后台运行Service与线程常用的系统服务Service标题:ArialUnicodeMS,32,红色目录菜单(将要讲解):
ArialUnicodeMS,28,加粗,深红目录菜单(未讲解的):ArialUnicodeMS,24,黑ServiceService是一段在后台长期运行的代码,与用户不直接交互。Service不是单独的进程,一般来说,Service运行在所在应用程序的进程中。Service不是单独的线程,因此如果在Service中处理耗时的工作,应该放到新线程中,避免堵塞主线程。子类需要继承android.app.Service来实现自己的service。Service简介Service是什么
Service是Android平台重要的组件之一,运行于后台,不直接与用户交互。启动后的Service具有较高的优先级,系统一般会优先保证Service的正常运行。只有当前台的Activity的正常运行资源被Service占用时,系统才会暂停Service;一旦重新获得空闲资源,系统会自动重启之前被停掉的Service。为何要用Service Service为Android平台上的应用提供了一种在后台运行而不影响用户操作的机制,例如媒体播放器在后台播放音乐。Service还为Android应用提供了一种向其他应用暴露接口的能力。这也为应用间的交互提供了便利。Service开发步骤类似于Activity,分为两步:定义一个类继承自Service.在AndroidManifest.xml文件中配置该ServiceService中的方法:onCreate():onDestroy():AbstractIbinderonBind(Intentintent):该方法返回一个Ibind对象,应用程序可通过该对象与Service组件通信.BooleanonUnbind(Intentintent):当该Service上绑定的所有客户端都断开连接时将会回调该方法.VoidonStartCommand(Intentintent,intflags,intstartId):早期是onStart()方法,每次客户端调用startService(Intent)方法启动该Service时都会回调该方法.案例1-service的使用步骤步骤一:写一个类继承自Service
publicclassFirstServiceextendsService{ publicvoidonCreate(){ super.onCreate(); System.out.println("serviceoncreate()"); } publicvoidonStart(Intentintent,intstartId){ System.out.println("serviceonstart()"); super.onStart(intent,startId); }}步骤二:Service配置在项目清单文件<serviceandroid:name=".FirstService"> <intent-filter> <actionandroid:name="com.icss.myservice"/> </intent-filter></service>案例1-service的使用步骤在android系统中运行Service有如下两种方式:1.通过Context的startService()方法:这样启动service,访问者与service之间没有关联,即使访问者退出了,service仍然运行.2.通过Context的bindService()方法:这样启用service,访问者与service绑定在了一起,访问者一旦退出,service也就终止了.这样就可以通信了.第一种方案测试:
finalIntentintent=newIntent();intent.setAction("com.icss.myservice");start.setOnClickListener(newView.OnClickListener(){ publicvoidonClick(Viewv){ startService(intent);}});stop.setOnClickListener(newView.OnClickListener(){ publicvoidonClick(Viewv){ stopService(intent); }});第一种方案分析Context.startService()当其他组件通过Context.startService()方法启动Service时,系统会创建一个Service对象,并顺序调用onCreate()方法和onStartCommand()方法。在调用Context.stopService()或者stopSelf()之前,Service一直处于运行的状态。如果多次调用startService()方法,系统只会多次调用onStartCommand()方法,而不会重复调用onCreate()方法。无论调用了多少次startService(),只需要调用一次stopService()就可以停止Service。Service对象在销毁之前,onDestroy()会被调用,因此与资源释放相关的工作应该在此方法中完成。onCreate()onStart()onDestroy()案例1-service的使用步骤案例1-service的使用步骤第二种方案测试:如果service和访问者之间需要进行方法调用或数据交换时,应该使用bindService()和unbindService()方法启动,关闭服务.Context.bindService(Intentintent,ServiceConnectioncon,intflag)方法参数有:intent:指定要启动的servicecon:一个ServiceConnection对象,用于监听访问者与service之间的连接情况。当访问者与Service之间连接成功地将回调该ServiceConnection对象的onServiceConnected(ComponentNamename,Ibinderservice)方法;
当访问者与Service之间断开连接时将回调该ServiceConnection对象的onServiceDisconnected(ComponentNamename)方法.flags:指定绑定时是否自动创建Service.
当开发Service类中,该Service类必须提供一个IBinderonBind(Intentintent)方法,在绑定本地Service的情况下,onBind(Intentintent)方法所返回的Ibinder对象将会传给ServiceConnection对象里onServiceConnected(ComponentNamename,Ibinderservice)方法的service参数,这样访问者就可以通过该Ibinder对象
与Service进行通信.
案例1-service的使用步骤第二种测试方案:publicclassBindServiceextendsService{ privateintcount; privatebooleanquit;//是否退出
privateMyBinderbinder=newMyBinder(); publicclassMyBinderextendsBinder{//用于交换数据的Binder对象 publicintgetCount(){ returncount; } } publicIBinderonBind(Intentintent){//注意当调用者使用时bindService时,回调此方法,它返回一个Binder对象 System.out.println("serviceonBind"); returnbinder; } publicvoidonCreate(){ super.onCreate(); System.out.println("serviceonCreate"); newThread(){ publicvoidrun(){ while(!quit){ try{ Thread.sleep(1000); }catch(InterruptedExceptione){ e.printStackTrace(); } count++; } } }.start(); } publicvoidonDestroy(){ this.quit=true; System.out.println("serviceonDestroy()"); super.onDestroy(); } publicbooleanonUnbind(Intentintent){ System.out.println("serviceonUnbind"); returnsuper.onUnbind(intent); }}
案例1-service的使用步骤第二种测试方案:主界面
定义一个对象ServiceConnection,当服务绑定后,则回调其中的onServiceConnectedBindService.MyBinderbinder;ServiceConnectioncon=newServiceConnection(){ @Override publicvoidonServiceConnected(ComponentNamename,IBinderservice){ System.out.println("serviceconnected"); binder=(BindService.MyBinder)service; } @Override publicvoidonServiceDisconnected(ComponentNamename){ System.out.println("servicedisconnected"); }};
在按钮中调用bindService方法bindService(intent,con,Service.BIND_AUTO_CREATE);Service的生命周期系统服务跨进程(AIDL服务)Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。Activity和Broadcast都可以跨进程通信,除此之外,还可以使用ContentProvider进行跨进程通信。现在我们已经了解了4个Android应用程序组件中的3个(Activity、Broadcast和ContentProvider)都可以进行跨进程访问,另外一个Android应用程序组件Service同样可以。这就是本节要介绍的AIDL服务。跨进程调用Service(AIDL服务)Android系统中,各应用程序都运行在自己的进程中,进程之间一般无法直接进行数据交换。以前,Corba可实现跨进程的调用;在java技术中,RMI也可实现跨进程调用;在Android中,可采用AIDL.AIDL实现原理:
在前面的绑定本地Service的案例中,本地Service将一个回调对象(Ibinder对象)通过onBind()方法返回给客户端,因此AIDL远程接口的实现类就是Ibinder的实现类.不过与绑定本地Service不同的是,本地Service是直接返回的Ibinder对象本身给客户端的ServiceConnection的onServiceConnected方法的第二个参数。但远程Service的onBind()方法只是将Ibinder对象的代理传给客户端的ServiceConnection的onServiceConnected方法的第二个参数.跨进程调用Service(AIDL服务)-创建步骤创建AIDL接口文件实现AIDL接口,将接口暴露给客户端客户端访问AIDLService案例:test_service5跨进程调用Service(AIDL服务)AIDL接口:android需要AIDL(androidinterfacedefinitionlanguage)来定义远程接口.AIDL特点:注意文件名的后缀必须是.aidlADT工具会自动在包目录上生成一个Icolor.java接口,该接口中包含一个Stub内部类,该内部类实现了Ibinder,Icolor两个接口,这个Stub类将会作为远程Service的回调类作为Service的onBind()方法的返回值.在Android开发中,远程调用的接口需要定义在.aidl文件中。AIDL文件中只能声明方法,可包含参数和返回值。AIDL支持的类型包括Java基本数据类型(char、int等)、String、CharSequence、List和Map。如果应用程序需要定义自己的数据类型,该类型必须实现Parcelable接口。publicinterfaceIColor{StringgetColor();}返回跨进程调用Service(AIDL服务)定义一个Service类,该Servicer的onBind()方法所返回的Ibinder对象应该是ADT所生成的Icolor.Stub的子类的实例.privateStringcolor; privateString[]colors=newString[]{"red","blue"}; privateColorBinderbinder; privateTimertimer=newTimer(); //继承Stub,它实现了IColor接口,并实现了IBinder接口
publicclassColorBinderextendsStub{ publicStringgetColor()throwsRemoteException{ returncolor; } } publicvoidonCreate(){ super.onCreate(); binder=newColorBinder(); timer.schedule(newTimerTask(){ @Override publicvoidrun(){ intrand=(int)(Math.random()*2); color=colors[rand]; System.out.println(rand); }},0,800); } //在绑定的是本地service的情况下,该binder对象会直接传给客户端的ServiceConnection对象的onServiceConnected方法的第二个参数
//在绑定的是远程service的情况下,只将该binder对象的代理传给客户端的ServiceConnection对象的onServiceConnected方法的第二个参数. publicIBinderonBind(Intentintent){ returnbinder; } @Override publicvoidonDestroy(){ timer.cancel(); }跨进程调用Service(AIDL服务)接下来,在项目清单文件中进行配置.<serviceandroid:name=".AidlSerivce"><intent-filter><actionandroid:name="myservice"/></intent-filter></service>至此服务端已经完成,下面将布置项目到模拟器上.返回跨进程调用Service(AIDL服务)如前所述,AIDL接口定义了两个进程之间的通信接口,因此客户端也需要定义前面的AIDL接口.
客户端开发步骤:1.将服务器端的AIDL文件复制到客户端:
特别注意:AIDL文件的包也要一起复制过来,不然运行的时候会出现Binderinvocationtoanincorrectinterface异常2.创建ServiceConnection对象3.以ServiceConnection对象作为参数,调用Context的bindService()方法绑定远程Service即可.但这里ServiceConnection并不能直接获得远程Service的onBind()方法所返回的对象,它只是获得了这个对象的代理,所以必须进行以下处理:colorService=Icolor.Stub.asInterface(service);
参见下面备注的代码:Service与线程Service、进程与线程Android平台多线程编程的一些基本概念Service、进程与线程Service是独立的进程么 Service并不是一个独立的进程。除非专门指定,默认情况下,Service对象本身是作为应用程序的一部分,在其进程空间内运行的。Service是线程么
同样,Service也不是线程,所以Service并不是一种在主线程之外进行一些工作的方法。在默认情况下,Service恰恰运行在应用程序所在进程的主线程上,因此,直接在Service内运行耗时操作会直接导致主线程阻塞、应用程序无响应的现象。开发者如果想指定一个Service运行在某个特定的进程中,可在AndroidManifest.xml中对应的<service>标签中添加android:process并指定,例如:<serviceandroid:name=".MusicService“android:process=“example.remote”/>。系统服务概述Android平台提供了很多系统级的服务,以便应用程序能够使用Android系统的基础功能,如电话、窗口、通知、定位等通过Activity.getSystemService(Stringname)获得系统服务:name:唯一的系统服务ID(在android.content.Context中定义)返回系统服务对象(通常定义为xxxManager)声明使用系统服务所需的权限<uses-permission>标签获得系统服务系统服务实际上可以看作是一个对象,通过Activity类的getSystemService方法可以获得指定的对象(系统服务)。getSystemService方法只有一个String类型的参数,表示系统服务的ID,这个ID在整个Android系统中是唯一的。例如,audio表示音频服务,window表示窗口服务,notification表示通知服务。案例1-获取网络和SIM卡信息通过TelephonyManager提供的系列方法即可获取手机网络,SIM卡的相关信息。案例:test_service_telephonyManager常用的系统服务简介—TelephonyServiceTelephonyService能够为应用提供电话相关的功能和信息,例如电话的状态,或者一些相关的运营商信息等。如果应用希望在电话状态发生变化时收到通知,也可通过注册PhoneStateListener,并按需实现其中的一些方法。//获取TelephonyService的对象TelephonyManagertm=(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);//创建PhoneStateListener对象并按需实现其中定义的方法PhoneStateListenerphoneStateListener=newPhoneStateListener(){ …};//监听电话状态tm.listen(phoneStateListener,PhoneStateListener.LISTEN_CALL_STATE);//取消监听tm.listen(phoneStateListener,PhoneStateListener.LISTEN_NONE);案例2-监听手机来电将来电信息记录到一个手机文件中.开发步骤:创建一人PhoneStateListener,它是一个通话状态监听器,当手机来电时,程序会将来电号码记录到文件中去.
案例:test_service_telephonyManager2常用的系统服务简介——SMSServiceSmsManager是Android提供了系统sendXXXMessage()方法用于发送短信,但最常用的是sendTextMessage()方法发送.//创建PendingIntent,设置执行动作Intentintent=newIntent(this,MyActivity.class);PendingIntentpendingActivityIntent=PendingIntent.getActivity(this,0,intent,0);//获取AlarmService的对象AlarmManageram=(AlarmManager) context.getSystemService(Context.ALARM_SERVICE);//设置定时器,时间到达后AlarmService会发出Intentam.setRepeating(AlarmManager.RTC,0,5000,pendingActivityIntent);//取消定时器alarmManager.cancel(pendingActivityIntent);案例1-发送短信PendingIntent是对Intent的包装,一般通过调用PendingIntent的getActivity(),getService(),getBroadcastReceiver()静态方法来获得PendingIntent对象。与Intent不同的是:PendingIntent通常会传给其他应用组件。参考代码:test_smsmanager步骤:1.权限<uses-permissionandroid:name="android.permission.SEND_SMS"/>2.代码:
finalSmsManagersm=SmsManager.getDefault();
//创建一个PendingIntentPendingIntentpi=PendingIntent.getActivity(MainActivity.this,0,newIntent(),0);//发送短信sm.sendTextMessage(tel.getText().toString(),null,content.getText().toString(),pi,null);案例2-短信群发参考代码:test_smsmanager2常用的系统服务简介——AudioManager调用getSystemService()方法来获取系统的音频管理器AudioManager.AudioManager常用方法:adjustStreamVolume(intstreamType,intdirection,intflags):调整手机指定类型的声音.streamType声音类型包括:STREAM_ALARM:手机闹铃STREAM_DTMF:DTMF音调的声音STREAM_MUSIC:STREAM_NOTIFICATION:STREAM_RING:STREAM_SYSTEM:手机系统的声音STREAM_VOICE_CALL:语言电话的声音第二个参数表示对声音增大/减少,第三个参数是调整声音时的标志.常用的系统服务简介——AudioManagerAudioManager常用方法:setMicrophoneMute(booleanon):是否静音setMode(intmode):声音模式,NORMAL,RINGTONE,IN_CALLsetRingerMode(intringerMode):电话铃声模式RINGER_MODE_NORMALRINGER_MODE_SILENTRINGER_MODE_VIBRATE:setSpeakerphoneOn(booleanon):是否开扩音器setStreamMute(intstreamType,booleanstate):
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024-2030年中国润滑脂油项目可行性研究报告
- 2024-2030年中国测绘行业发展模式投资规划分析报告
- 2024-2030年中国汽车转向系统产业战略规划及未来趋势发展分析报告
- 2024-2030年中国汽车模具钢行业应用动态与投资前景预测报告
- 2024-2030年中国汽车底盘贮气筒总成行业市场运营模式及未来发展动向预测报告
- 2024年渗透剂项目立项申请报告
- 2024年制药整机项目提案报告
- 2022年大学海洋工程专业大学物理下册期中考试试题-附解析
- 2022年大学数学专业大学物理二开学考试试题A卷-附解析
- 2022年大学生物工程专业大学物理下册期末考试试卷C卷-附解析
- 2024年甘肃省职业院校技能大赛物联网应用开发赛项样题2
- 《精益生产之ECRS分析法》课件
- 老年个人健康状况分析报告模板5-12-16
- 2024注册安全工程师《安全生产法律法规》考点总结
- 新《事业单位财务规则》培训讲义0
- 2024土石坝安全监测技术规范
- 【课件】2024届高三英语高考前指导最后一课(放松心情)课件
- 食管癌围手术期护理教学查房
- 2024年河南投资集团有限公司招聘笔试冲刺题(带答案解析)
- 2024年院感安全注射培训
- 孩子分为四种:认知型、模仿型、逆思型、开放型
评论
0/150
提交评论