【边做项目边学Android】异常处理:android.os.NetworkOnMainThreadException--多线程问题

一切搞定。以为高枕无忧了,结果还是有问题!

log開始报错了,获取更新信息异常。。!debug一下。发现Exception:android.os.NetworkOnMainThreadException

这个异常大概意思是在主线程訪问网络时出的异常。 Android在4.0之前的版本号 支持在主线程中訪问网络。可是在4.0以后对这部分程序进行了优化,也就是说訪问网络的代码不能写在主线程中了。

查看网上的解决方法。在Android中实现异步任务机制有两种方式,Handler和AsyncTask。

Handler模式须要为每个任务创建一个新的线程,任务完毕后通过Handler实例向UI线程发送消息,完毕界面的更新,这样的方式对于整个过程的控制比較精细,但也是有缺点的。比如代码相对臃肿,在多个任务同一时候运行时,不易对线程进行精确的控制。

为了简化操作。Android1.5提供了工具类android.os.AsyncTask。它使创建异步任务变得更加简单,不再须要编写任务线程和Handler实例就可以完毕同样的任务。

这里我们採用AsyncTask的处理方式。

先来看看AsyncTask的定义:

public abstract class AsyncTask<Params, Progress, Result> {

三种泛型类型分别代表“启动任务运行的输入參数”、“后台任务运行的进度”、“后台计算结果的类型”。

在特定场合下。并非全部类型都被使用。假设没有被使用。能够用java.lang.Void类型取代。

AsyncTask的运行分为四个步骤

每一步都相应一个回调方法,这些方法不应该由应用程序调用。开发人员须要做的就是实现这些方法。

1) 子类化AsyncTask

2) 实现AsyncTask中定义的以下一个或几个方法

onPreExecute(), 该方法将在运行实际的后台操作前被UI thread调用。

能够在该方法中做一些准备工作,如在界面上显示一个进度条。

doInBackground(Params...), 将在onPreExecute 方法运行后立即运行。该方法运行在后台线程中。这里将主要负责运行那些非常耗时的后台计算工作。能够调用 publishProgress方法来更新实时的任务进度。

该方法是抽象方法,子类必须实现。

onProgressUpdate(Progress...),在publishProgress方法被调用后,UI thread将调用这种方法从而在界面上展示任务的进展情况,比如通过一个进度条进行展示。

onPostExecute(Result), 在doInBackground 运行完毕后,onPostExecute 方法将被UI thread调用。后台的计算结果将通过该方法传递到UI thread.

为了正确的使用AsyncTask类。下面是几条必须遵守的准则:

1) Task的实例必须在UI thread中创建

2) execute方法必须在UI thread中调用

3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法

4) 该task仅仅能被运行一次。否则多次调用时将会出现异常

doInBackground方法和onPostExecute的參数必须相应。这两个參数在AsyncTask声明的泛型參数列表中指定。第一个为 doInBackground接受的參数,第二个为显示运行进度的參数。第第三个为doInBackground返回和onPostExecute传入的參数。

以下是项目中详细的处理方法:

package com.liuhao.mobilesafe.engine;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.content.Context;
import android.os.AsyncTask;

import com.liuhao.mobilesafe.domain.UpdateInfo;

public class UpdateInfoService {

	private Context context; //应用程序环境的上下文信息

	public UpdateInfoService(Context context) {
		this.context = context;
	}

	// 将与网络通信的过程封装在ServiceInBackGround的doInBackground方法中
	private class ServiceInBackGround extends AsyncTask<Integer, Void, UpdateInfo>{

		@Override
		protected UpdateInfo doInBackground(Integer... params) {
			String path = context.getResources().getString(params[0]); //依据urlId获取资源文件里相应的内容
			UpdateInfo info = new UpdateInfo();
			URL url;
			try {
				url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setConnectTimeout(20000);
				conn.setRequestMethod("GET");

				InputStream is = conn.getInputStream(); //得到url相应的文件流。应该是xml文件流,须要对其进行解析

				info = UpdateInfoParser.getUpdateInfo(is); //对xml文件流进行解析,获取到更新信息实体
			} catch (Exception e) {
				e.printStackTrace();
			}
			return info;
		}

		@Override
		protected void onPostExecute(UpdateInfo result) {
			super.onPostExecute(result);
		}

	}

	/**
	 * @param urlId
	 *            server资源路径相应的id
	 * @return 更新信息
	 * @throws Exception
	 */
	public UpdateInfo getUpdateInfo(int urlId) throws Exception {
//		new serviceInBackGround().execute(urlId).get();
		return new ServiceInBackGround().execute(urlId).get();
	}

}

最后须要说明AsyncTask不能全然代替线程,在一些逻辑较为复杂或者须要在后台重复运行的逻辑就可能须要线程来实现了。

异常都解决后。再次执行程序:

点击进入程序,会弹出升级对话框:

查看日志:

用户点击确定:

点击取消:



參考:

http://www.cnblogs.com/dawei/archive/2011/04/18/2019903.html

http://daoshud1.iteye.com/blog/1843655

时间: 2024-10-23 18:10:30

【边做项目边学Android】异常处理:android.os.NetworkOnMainThreadException--多线程问题的相关文章

【边做项目边学Android】小白会遇到的问题--Appcompat_V7问题

问题描写叙述: 首先遇到的问题就是adt版本号的选择,sdk版本号的选择: adt按非小白朋友说的选了最新的ADT-22.3.0,同一时候我也把sdk更新到了最新的(嗯.这个要fanqiang,或者找离线包). 非常开心啊,认为能够開始啦.于是新建Android项目.next-->next...finish!项目生成! (当然中间要填写东西) 项目建成了,发现Eclipse自己主动生成了一个奇怪的项目Appcompat_V7项目,再创建一个Android项目时,又会再多出一个appcompat_

【边做项目边学Android】手机安全卫士03:获取更新的服务器配置,显示更新对话框

配置应用程序在手机桌面显示的名称和图标-AndroidManifest.xml: <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.liuhao.mobilesafe" android:versionCode="

【边做项目边学Android】知识点:Intent

一. Intent的介绍 Android中提供了Intent机制来协助应用间的交互与通讯,或者采用更准确的说法是,Intent不仅可用于应用程序之间,也可用于应用程序内部的activity, service和broadcast receiver之间的交互. Intent是一种运行时绑定(runtime binding)机制,它能在程序运行的过程中连接两个不同的组件.通过Intent,你的程序可以向Android表达某种请求或者意愿,Android会根据意愿的内容选择适当的组件来响应. Inten

【边做项目边学Android】手机安全卫士08-一些布局和显示的细节:State List

我们注意到有些应用里的按钮在点击时的显示状态和普通状态是不一样的,比如: 普通状态下: 选中状态下: 那这种效果是如何实现的呢?在Android系统中提供给我们一种方便与实现这种功能的方法即:state list drawable. StateListDrawable是在XML中定义的drawable对象,我们可以通过设置不同item下的图片来显示不同状态,这取决于 drawable对象的状态.例如,一个Button控件可以有不同的状态(点击.聚焦等),通过一系列的drawable对象,可以为每

【边做项目边学Android】手机安全卫士09-手机防盗界面设置向导1

本次主要做手机防盗界面的设置向导功能界面的设计. 需求: 当用户进入手机防盗界面时,判断用户是否已经进行过设置向导: 如果用户已经设置过手机防盗,则不再提示用户进入手机向导 若还没有设置,则提示用户进入设置向导界面. 具体实现: 1.当用户输入"手机防盗"密码正确时,进行判断用户是否进行过设置向导 /** * 判断用户是否进行过设置向导 * @return */ private boolean isSetup(){ return sp.getBoolean("isAlread

【边做项目边学Android】知识点:Adapter适配器

1.概念 Adapter是连接后端数据和前端显示的适配器接口,是数据和UI(View)之间一个重要的纽带.在常见的 View(ListView,GridView)等地方都需要用到Adapter.如下图直观的表达了Data.Adapter.View三者的关系: Android中所有的Adapter一览: 由图可以看到在Android中与Adapter有关的所有接口.类的完整层级图.在我们使用过程中可以根据自己的需求实现接口或者继承类进行一定的扩展.比较常用的有 BaseAdapter,Simple

【边做项目边学Android】手机安全卫士04_02:从服务器下载并安装新版本安装包

文件下载 1. 下载文件业务类 下载文件的操作也属于业务方法,所以在com.liuhao.mobilesafe.engine中创建一个DownloadFileTask下载文件的类. 其中的getFile方法,用于从服务器文件路径上下载文件至本地文件目录. package com.liuhao.mobilesafe.engine; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; im

【边做项目边学Android】手机安全卫士10-设置向导之绑定SIM卡

上回主要做了设置向导界面的界面设计,主要涉及到界面的布局和一些控件的使用.这次要做设置向导界面的功能具体实现. 首先,4个界面分别是(重复度很大,这里就不再贴到正文中了) /mobilesafe/res/layout/setup_wizard1.xml /mobilesafe/res/layout/setup_wizard2.xml /mobilesafe/res/layout/setup_wizard3.xml /mobilesafe/res/layout/setup_wizard4.xml

【边做项目边学Android】手机安全卫士01:splash界面ui

手机安全卫士项目是跟着黑马的视频做的. splash是飞洒.飞溅的意思,主要是用于完成一个产品logo显示,期间可以: 后台完成数据库初始化的操作 联网访问服务器,获取服务器最新信息(升级提示) 不同的日期显示出来不同logo,判断当前系统时间,素材一般从服务器上下载下来. 判断时间,根据不同时间显示不同的加载页面 布局文件:splash.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayou