今天看了组件之间的通信,组件之间的通信通过intent进行,intent对象不断的传递就构成了组件之间的通信。
一般intent对象包含以下几个内容:Component Name,Action,Data和Category,Extras,Flags。
组件名用于指定未来要处理Intent的对象。但这个不是Intent必须要有的内容,因为Intent分为隐式和显示,如果指定了组件名就是显示Intent。Action为一个字符串对象,描述了该Intent将要触发的动作。这个动作可以是系统预定义的,比如Action_CALL,Action_MAIN等。也可以是自己定义的Action描述。但是命名的时候最好做到见名知义。Action在很大程度上决定了一个Intent的内容。主要是因为不同的Action所对应的Data和Extras操作的数据不一样。
Date描述Intent的操作所用到的数据的URI和类型。
Category也是一个字符串对象,它包含了可以处理的Intent的组件的类别信息,Android中也预定义了Category常量,而且我么不可以自定义Category。
Extras是一组键值对,它包含了一些需要传递给目标组件的额外信息。
Intent在组件之间传递时,组件需要告诉系统自己能够处理哪些Intent,因此在这里就有一个类似于过滤器一样的机制来过滤掉那些自己不感兴趣的Intent。这就是IntentFilter。IntentFilter会像列白名单一样列出组件能接收的Intent。在这里还需要注意一下IntentFilter创建的点,只有在BroadCast时可以在代码中动态创建,其他的IntentFilter都只能在Manifest文件中进行声明。这样的筛选就像IntentFilter在把关一样,Intent需要经历三关。在这里我发现它过滤的过程有一个很有意思的点。
首先Intent只能有一个Action,IntentFilter却可以有多个Action,但是Intent只要与其中的一个匹配即可过关。IntentFilter的Action不能为空,这样会阻塞所有Intent。有意思的来了,如果Intent没有设置Action,那么IntentFilter会放过它,放过它哦!Intent会直接晋级第二关!IntentFilter又要检查Intent的Data,这里的步骤比较多,我就不赘述了。假如到了第三关,第三关可以这么概括,只有当Intent的所有Category是IntentFilter的Category的子集时才可以通过检查。这样就几乎说完了过滤的过程了。
以下是书上的例子,我觉得还挺复杂的,所以也写写回顾一下。
首先搞清楚干什么吧。这是一个应用程序内部组件之间通过Intent和Broadcast Receiver组件通信的示范。Activity中设置两个Button,用于启动和停止service服务。而这个service将会启动一个线程,线程会产生一个随机数,并封装在Intent中传递给Activity,Activity会将其显示在TextView中。
Activity部分可以分三个步骤:
step1:添加控件并设置监听器。
btnStart.setOnClickListener(new OnClickListener() {//为按钮添加点击事件监听 @Override public void onClick(View v) {//重写onClick方法 Intent myIntent = new Intent(Sample_3_6.this, wyf.wpf.MyService.class); Sample_3_6.this.startService(myIntent);//发送Intent启动Service } }); btnStop.setOnClickListener(new OnClickListener() {//为按钮添加点击事件监听 @Override public void onClick(View v) {//重写onClick方法 Intent myIntent = new Intent();//创建Intent对象 myIntent.setAction("wyf.wpf.MyService"); myIntent.putExtra("cmd", CMD_STOP_SERVICE); sendBroadcast(myIntent);//发送广播 } });
在这里我贴出了两个按钮的监听函数。第一个是用于启动一个service,所以我们可以看到代码中声明一个Intent对象,而且是显式Intent。然后调用startService函数直接启动service。第二个监控函数用于中断service。为Intent设置了自定义的action描述,还有extras。封装好作为广播发送出去。
step2:service在启动之后会开启一个线程,会向activity发Intent,所以Activity也需要注册一个BroadcastReceiver组件,,注册之前首先要实现BroadcastReceiver的子类,主要就是重写onReceive()。
private class DataReceiver extends BroadcastReceiver{//继承自BroadcastReceiver的子类 @Override public void onReceive(Context context, Intent intent) {//重写onReceive方法 double data = intent.getDoubleExtra("data", 0); tv.setText("Service的数据为:"+data); }
step3:实现子类以后应该在合适的地方对BroadcastReceiver进行注册和取消注册。分别写在Activity的onStart()和onStop()函数中。
protected void onStart() {//重写onStart方法 dataReceiver = new DataReceiver(); IntentFilter filter = new IntentFilter();//创建IntentFilter对象 filter.addAction("wyf.wpf.Sample_3_6"); registerReceiver(dataReceiver, filter);//注册Broadcast Receiver super.onStart(); } @Override protected void onStop() {//重写onStop方法 unregisterReceiver(dataReceiver);//取消注册Broadcast Receiver super.onStop();
至此,Activity部分代码完毕。开始进行service部分的开发。在开始之前我又去恶补了一下关于service的知识。真的是恶补!!
service主要在后台执行一些比较耗时的逻辑,或者执行一些需要长时间运行的任务。在android中,后台是指不依赖于UI的操作。下面是service中需要重写的方法o
nBind():当另一个组件想通过调用 bindService() 与服务绑定(例如执行 RPC)时,系统将调用此方法。在此方法的实现中,必须返回 一个IBinder 接口的实现类,供客户端用来与服务进行通信。无论是启动状态还是绑定状态,此方法必须重写,但在启动状态的情况下直接返回 null。
onCreate():首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或onBind() 之前)。如果服务已在运行,则不会调用此方法,该方法只调用一次
onStartCommand():当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。 如果自己实现此方法,则需要在服务工作完成后,通过调用 stopSelf() 或 stopService() 来停止服务。(在绑定状态下,无需实现此方法。)
onDestroy():当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的监听器、接收器等,这是服务接收的最后一个调用
好,关于基本的service的内容梳理完毕,可以开始service部分开发了。
首先要重写的就是oncreate(),在此函数中完成初始化工作。
public void onCreate() {//重写onCreate方法 flag = true; cmdReceiver = new CommandReceiver(); super.onCreate(); }
定义了一个线程启动标志位,一旦服务启动,线程就默认启动,就将标志位置位,创建一个BroadcastReceiver子类对象.
public int onStartCommand(Intent intent, int flags, int startId) {//重写onStartCommand方法 IntentFilter filter = new IntentFilter();//创建IntentFilter对象 filter.addAction("wyf.wpf.MyService"); registerReceiver(cmdReceiver, filter);//注册Broadcast Receiver doJob();//调用方法启动线程 return super.onStartCommand(intent, flags, startId);
动态注册广播,用于接收Activity发过来的命令.当然还要启动线程,不过交给doJob()完成.
private class CommandReceiver extends BroadcastReceiver{//继承自BroadcastReceiver的子类 @Override public void onReceive(Context context, Intent intent) {//重写onReceive方法 int cmd = intent.getIntExtra("cmd", -1);//获取Extra信息 if(cmd == Sample_3_6.CMD_STOP_SERVICE){//如果发来的消息是停止服务 flag = false;//停止线程 stopSelf();//停止服务 } } } @Override public void onDestroy() {//重写onDestroy方法 this.unregisterReceiver(cmdReceiver);//取消注册的CommandReceiver super.onDestroy(); }
public void doJob(){ new Thread(){ public void run(){ while(flag){ try{//睡眠一段时间 Thread.sleep(1000); } catch(Exception e){ e.printStackTrace(); } Intent intent = new Intent();//创建Intent对象 intent.setAction("wyf.wpf.Sample_3_6"); intent.putExtra("data", Math.random()); sendBroadcast(intent);//发送广播 } } }.start();
今天是11月2号,完毕.
组件之间的通信
最新推荐文章于 2022-11-20 11:18:00 发布