Android应用软件开发

194课时
1.7K学过
8分

课程评价 (0)

请对课程作出评价:
0/300

学员评价

暂无精选评价
3分钟

4.3 案例分析

案例分析

表4-3-1 ICounterService.java是接口文件,定义计数器的服务接口ICounterService,这个接口很简单,它只有两个成员函数,分别用来启动和停止计数器;启动计数时,还可以指定计数器的初始值。

表4-3-2 CounterService.java ,实现计数器服务CounterService。这个计数器服务实现了ICounterService接口。当这个服务被binderService函数启动时,系统会调用它的onBind函数,这个函数返回一个Binder对象给系统。

当MainActivity调用bindService函数来启动计数器服务器时,系统会调用MainActivity的ServiceConnection实例serviceConnection的onServiceConnected函数通知MainActivity,这个服务已经连接上了,并且会通过这个函数传进来一个Binder远程对象,这个Binder远程对象就是来源于CounterService的onBind的返回值。

函数onBind返回的Binder对象是一个自定义的CounterBinder实例,它实现了一个getService成员函数。当系统通知MainActivity,计数器服务已经启动起来并且连接成功后,并且将这个Binder对象传给MainActivity时,MainActivity就会把这个Binder对象强制转换为CounterBinder实例,然后调用它的getService函数获得服务接口。这样,MainActivity就通过这个Binder对象和CounterService关联起来了。

表4-3-3 MainActivity.java是默认Activity,完成主要功能。 MainActivity在创建(onCreate)的时候,会调用bindService函数启动计数器服务(CounterService),它的第二个参数serviceConnection是一个ServiceConnection实例。启动计数器服务后,系统会调用这个实例的onServiceConnected函数将一个Binder对象传回来,通过调用这个Binder对象的getService函数,就可以获得计数器服务接口。把这个计数器服务接口保存在MainActivity的counterService成员变量中。当我们调用unbindService停止计数器服务时,系统会调用这个实例的onServiceDisconnected函数告诉MainActivity,它与计数器服务的连接断开了。

注意,通过调用bindService函数来启动Service时,这个Service与启动它的Activity是位于同一个进程中,没有在新的进程中启动服务。

在MainActivity的onResume函数中,通过调用registerReceiver函数注册了一个广播接收器counterActionReceiver,它是一个BroadcastReceiver实例,并且指定了这个广播接收器只对CounterService.BROADCAST_COUNTER_ACTION类型的广播感兴趣。当CounterService发出一个CounterService.BROADCAST_COUNTER_ACTION类型的广播时,系统就会把这个广播发送到counterActionReceiver实例的onReceiver函数中去。在onReceive函数中,从参数intent中取出计数器当前的值,显示在界面上。

界面上有两个按钮,分别是Start Counter和Stop Counter按钮,点击前者开始计数,而点击后者则停止计数。

当MainActivity调用计数器服务接口的startCounter函数时,计数器服务并不是直接进入计数状态,而是通过使用异步任务(AsyncTask)在后台线程中进行计数。这里为什么要使用异步任务来在后台线程中进行计数呢?计数过程是一个耗时的计算型逻辑,不能把它放在界面线程中进行,因为CounterService启动时,并没有在新的进程中启动,它与MainActivity一样,运行在应用程序的界面线程中,因此,这里需要使用异步任务在在后台线程中进行计数。

异步任务AsyncTask的大概用法是,当我们调用异步任务实例的execute(task.execute)方法时,当前调用线程就返回了,系统启动一个后台线程来执行这个异步任务实例的doInBackground函数,用来执行耗时计算,它会进入到一个循环中,每隔1秒钟就把计数器加1,然后进入休眠(Thread.sleep),醒过来,再重新这个计算过程。在计算的过程中,可以通过调用publishProgress函数来通知调用者当前计算的进度,好让调用者来更新界面,调用publishProgress函数的效果最终就是直入到这个异步任务实例的onProgressUpdate函数中,就可以把这个进度值以广播的形式(sendBroadcast)发送出去,这里的进度值就定义为当前计数服务的计数值。

当MainActivity调用计数器服务接口的stopCounter函数时,会告诉函数doInBackground停止执行计数(stop = true),于是,函数doInBackground就退出计数循环,然后将最终计数结果返回,返回的结果最后进入到onPostExecute函数中,这个函数同样通过广播的形式(sendBroadcast)把这个计数结果广播出去。

表4-3-4 activity_main.xml是布局文件,定义了一个TextView和两个按钮。TextView显示计数值,两个按钮分别用于启动和停止计数。

表4-3-5string.xml定义了字符串资源文件。

表4-3-6 AndroidManifest.xml中完成了Service的声明。

程序运行后的界面如图4-3-1所示,有两个按钮,一个启动计数,一个停止计数,还有一个计数值。

当启动后,通过图4-3-2的LogCat信息看,计数服务被创建起来,然后也连接到了服务器上。

当单击“START COUNTER”后启动了程序,获得返回来的计数值,如图4-3-3所示。

运行时的LogCat信息如图4-3-4所示,COUNTER的数值在不断的变化,LogCat也在不断的输出提示信息。

若停止计数,点击“STOP COUNTER”按钮后,计数值保持不变,如图4-3-5所示。

停止计数后,LogCat输出的信息如图4-3-6所示,从图中可以看到,停止计数后Service依然发送了一个计数值,并被客户端接收到了。

若退出APP,LogCat输出的信息如图4-3-7所示,从图中可以看到,当APP退出后 ,Service也被销毁了。