RSS Reader实例开发之联网开发

来源:互联网 发布:专业网络推广 编辑:程序博客网 时间:2024/05/16 09:06

在OPhone应用程序中,如果我们要做一些费时的操作,例如,从网络获取数据,就不能将这些操作放在普通的处理UI的逻辑中,否则,主线程一旦执行耗时任务,将无法响应用户的任何操作,OPhone系统会判定该应用程序已经无法正常响应,并提示用户强行关闭该应用程序:

 

RSS Reader需要从网络获取RSS的最新内容,自然需要使用多线程来实现。由于OPhone系统基于Java 5虚拟机和标准库,因此,多线程机制和Java 5完全相同,可以直接启动一个新的Thread。
RSS Reader利用HTTP GET方式读取RSS,可以直接利用java.net包提供的URL、HttpURLConnection等类来实现该功能,不必依赖任何第三方库,一段简单的代码如下:
 

 

 

 在运行上述代码前,我们需要告诉OPhone系统,RSS Reader应用需要INTERNET权限,因此,务必在AndroidManifest.xml中添加权限声明:

请注意:没有声明INTERNET权限就运行联网代码会导致应用程序被异常关闭。
 

       当后台线程获取到数据,需要更新UI时,千万不可直接在后台线程对UI组件进行操作,否则,你会得到一个如下图所示的警告,然后,应用程序被强制关闭:

熟悉桌面UI开发的开发者应该知道,对UI操作必须严格串行化,即只能通过主线程完成。如果多个线程同时对UI进行操作,将产生不可预料的后果。在OPhone系统中,对UI操作时,会检查当前线程是否是主线程,如果不是,系统将报错,然后强行关闭应用程序。
 

使用Message更新UI
        为了能让后台线程通知主线程更新UI,OPhone系统提供了一个Handler类来处理消息,所有对UI更新的请求可以通过发送消息给Handler,在Handler的消息处理代码中,就可以安全地对UI进行操作了,因为Handler执行的消息处理代码是运行在UI主线程中的。
要异步更新UI,我们需要定义一个Handler实例,由于其无需更改,最好将其定义为final类型:
 

如果某个后台线程需要更新textView的内容,就可以发送一个消息来通知主线程更新:

在一个Activity中,可能需要处理多种自定义消息,Message.what字段就是用来区分消息类型的,消息常量可以自定义,只要保证各个常量的值唯一即可。Message还可以携带任意的Object来传递数据,例如,上述代码通过msg.obj = "Data updated!"来传递一个字符串,当Handler处理消息时,它会将TextView的内容更新。
 

使用AsyncTask
        从1.5版本开始,为了更简化异步任务的执行,OPhone系统引入了新的AsyncTask类,使用AsyncTask,我们可以更加简单地实现异步线程,并且避免了使用Handler处理Message的麻烦。
 

         AsyncTask基于Java 5的java.util.concurrent库,提供了基于线程池的调度功能,当同时运行多个小任务时,每个任务不必单独创建和销毁线程,而是通过ThreadPoolExecutor调度,重用线程池里的空闲线程,执行效率更高。
       

        要使用AsyncTask,首先从AsyncTask派生一个子类。注意到AsyncTask需要3个泛型参数,分别代表输入、进度条和结果。假定我们的输入是一个String类型的URL地址,进度条通常是ProgressDialog的实例,结果是从URL读取的网页内容,这里用一个String表示,则定义AsyncTask如下:

 

  AsyncTask必须在主线程中创建,同时必须在主线程中通过execute()方法调度,后台线程将执行doInBackground()方法,当该方法完成时,主线程将得到通知,并执行onPostExecute()方法。由于onPostExecute()方法是在主线程中执行的,因此,可以安全地在这个方法中更新UI。假定Activity包含一个id为textView的TextView,以上代码执行效果如下:

执行定时任务
      在RSS Reader中,我们需要定期从网络读取RSS的最新内容,所以需要一个定期触发的调度器,最简单的方法是使用Java标准库的Timer,我们只需要实现TimerTask,就可以完成该功能。
 

     使用Timer时需要注意,Timer本身会启动一个线程,如果在TimerTask的run()方法中抛出了任何异常,都会导致Timer线程终止,结果是无法继续执行定时任务。例如,以下代码:
  

当TimerTask执行到第10次时,将抛出RuntimeException异常,结果,Timer线程终止,你可以看到以下输出:

 

 

 

 

因此,务必使用try...catch处理TimerTask的run()方法的所有RuntimeException异常。
      

         除了Timer外,OPhone系统本身还提供了另一种定时执行任务的机制,这就是利用sendMessageDelayed(Message, long)方法,通过延迟发送消息来模拟定期调度。这种方法依赖OPhone应用程序的消息处理机制,实现起来更简单,推荐采用。
RSS Reader就采用了sendMessageDelayed(Message, long)方法,实现定期读取RSS的功能。
 

        在MainActivity中,我们定义一个MSG_TIMER常量,然后,实例化一个Handler来处理消息队列:

 

在refreshFeeds()方法中,我们通过AsyncTask在后台读取RSS。当读取到RSS后,调用sendMessageDelayed(Message, long)发送下一次MSG_TIMER的触发消息:

 

MainActivity首次运行时,需要调用一次refreshFeeds()方法,才能实现正常触发。首次调用refreshFeeds()代码可以写到MainActivity的onCreate()方法中。每隔60秒,就会触发一个MSG_TIMER消息,这样,我们就实现了定期读取Feed的功能。
updateUI()方法负责更新ListView的列表项,我们还需要解析从网络读取的XML格式的RSS,稍后,我们会编写该功能。
  

原创粉丝点击