php抓取网页数据实例(为什么需要线程假设需要开发一个联网应用程序,需要从一个网址网页内容)

优采云 发布时间: 2022-03-07 16:22

  php抓取网页数据实例(为什么需要线程假设需要开发一个联网应用程序,需要从一个网址网页内容)

  为什么需要线程

  假设您需要开发一个联网的应用程序,并且您需要从一个网址中抓取网页内容。这里读取的网页地址是作者在本地机器上创建的服务器地址。当然,在阅读网页内容时,可以使用 HttpClient 提供的 API,但这不是本文的重点。在开发网络程序方面经验不足的程序员可能会编写以下代码。

  网络连接通常比较耗时,尤其是在目前GPRS等低速网络情况下,因此connect()方法可能需要3-5秒,

  返回页面内容的时间更长。如果直接在主线程(即 UI 线程)中处理此连接操作会发生什么?

  为了更好的模拟模拟器中缓慢的网络读取速度,

  作者在阅读过程中将线程休眠50秒,

  运行 NetworkActivity 并单击“连接”按钮。事故发生,

  按钮久久没有反应,整个界面仿佛“死”了。然后系统显示 ANR(应用程序无响应)

  错误信息,如图1:

  

  线程中的网络

  为什么会出现 ANR?答案是联网动作被阻塞在主线程中,很久没有返回,所以OPhone弹出了ANR错误。这个错误提示我们,

  如果一个任务可能需要很长时间运行才能返回,则必须将该任务放在单独的线程中运行,

  避免阻塞 UI 线程。Java 语言具有对线程的内置支持。您可以使用 Thread 类创建一个新线程,然后在 run() 方法中读取网页的内容。

  获取页面内容后,调用TextView.setText()更新界面。修改连接()

  该方法如下所示:

  重新运行 NetworkActivity 并单击“连接”按钮。程序没有按预期获取到网页的内容,并显示在TextView上。查看日志,可以看到在执行connect的过程中抛出了异常。其次,分析问题。

  使用Handler更新界面

  实际上,connect()方法中抛出的异常是接口更新引起的。Connect() 方法在新启动的线程中直接调用 message.setText() 方法是不正确的。OPhone平台只允许在主线程调用相关View的方法来更新界面。如果在新线程中获取返回结果,则必须借助 Handler 更新接口。为此,请在 NetworkActivity 中创建一个 Handler 对象并在 handleMessage() 中更新 UI。

  通过connect()方法获取网页内容后,使用如下方法更新界面。

  重新运行NetworkActivity,点击“连接”按钮,结果如图2所示,网页内容被正确读取。

  

  异步任务

  看起来修改后的connect()方法已经可以使用了,但是这种匿名进程方法存在缺陷:首先,线程的开销很大。如果每个任务都需要创建一个线程,就会降低应用程序的效率。二是线程无法管理,匿名线程在创建启动后不受程序控制。如果发送的请求很多,那么就会启动很多线程,系统就会不堪重负。另外,前面我们已经看到,在新线程中更新UI还必须引入一个handler,这使得代码看起来很臃肿。

  为了解决这个问题,OPhone 在 1.5 版本中引入了 AsyncTask。AsyncTask的特点是任务运行在主线程之外,回调方法在主线程中执行,有效避免了使用Handler带来的麻烦。阅读 AsyncTask 的源码可知,AsyncTask 使用 java.util.concurrent 框架来管理线程和任务的执行。并发框架是经过严格测试的非常成熟高效的框架。这说明AsyncTask的设计很好的解决了匿名线程的问题。

  AsyncTask是一个抽象类,子类必须实现抽象方法doInBackground(Params...p),在其中实现任务执行工作,如连接网络获取数据。onPostExecute(Result r) 方法通常也应该实现,因为应用程序关心的结果会在这个方法中返回。需要注意的是,AsyncTask 必须在主线程中创建一个实例。AsyncTask 定义了三个泛型类型 Params、Progress 和 Result。

  PageTask 扩展 AsyncTask 并在 doInBackground() 方法中读取网页内容。PageTask 的源代码如下所示:

  执行PageTask很简单,调用如下代码即可。重新运行NetworkActivity,不仅可以抓取网页内容,还可以实时更新阅读进度。读者尝试阅读更大的页面以查看百分比是如何更新的。

  总结

  本文介绍了OPhone联网应用开发中需要注意的两个问题:线程管理和接口更新。不仅分析问题,还给出了多种解决方案。这里笔者推荐使用AsyncTask来处理联网、播放大型媒体文件等耗时的任务,不仅执行效率高,而且还节省了代码。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线