查看网络图片

本文详细阐述了在Android开发中遇到的网络请求导致主线程阻塞的问题,通过使用Handler和子线程实现了网络请求的异步处理,避免了应用无响应的情况。同时介绍了如何在子线程中进行UI操作的正确方式,防止了`CalledFromWrongThreadException`异常的发生。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

访问网络需要添加访问网络的权限

Android not responding(应用程序无响应)阻塞了主线程 ANR异常

Android4.0以后的版本,只要发现请求网络的操作,都不允许放到主线程中。若放到主线程中会报异常。防止阻塞主线程。所以请求网络的操作要放到子线程中。

异常:
CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
只有原始的线程(主线程, ui线程)才能修改view对象.
在子线程中修改view的显示状态, 会报上面异常.


public class MainActivity extends Activity implements OnClickListener {

	private static final String TAG = "MainActivity";
	private ImageView iv;
	private EditText et;
	private HttpURLConnection conn;
	private final int SUCCESS = 0;
	private final int ERROR = 1;
	private Handler handler = new Handler() {

		/**
		 * 接收消息
		 */
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			Log.i(TAG, "what=" + msg.what);

			if (msg.what == SUCCESS) {
				iv.setImageBitmap((Bitmap) msg.obj);// 设置ImageView显示的图片
			} else if (msg.what == ERROR) {
				Toast.makeText(MainActivity.this, "抓取失败!", 0).show();
			}
		}

	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		iv = (ImageView) findViewById(R.id.iv);
		et = (EditText) findViewById(R.id.et);

		findViewById(R.id.btn).setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		final String url = et.getText().toString();

		new Thread(new Runnable() {

			@Override
			public void run() {
				Bitmap bitmap = getImageFromNet(url);
				if (bitmap != null) {
					Message msg = new Message();
					msg.what = SUCCESS;
					msg.obj = bitmap;
					handler.sendMessage(msg);
				} else {
					Message msg = new Message();
					msg.what = ERROR;
					handler.sendMessage(msg);
				}
			}
		}).start();
	}

	/**
	 * 根据url到网络获取图片
	 * 
	 * @param url
	 * @return
	 */
	private Bitmap getImageFromNet(String url) {
		try {
			URL myUrl = new URL(url);// 创建一个URL对象
			// 得到HTTP的连接对象
			conn = (HttpURLConnection) myUrl.openConnection();

			conn.setRequestMethod("GET");// 设置请求方法为get
			conn.setConnectTimeout(10 * 1000);// 设置连接服务器的超时时间,如果超时没有连接成功,会抛异常
			conn.setReadTimeout(5 * 1000);// 设置读取数据时的超时时间,如果超时没有成功,抛异常

			conn.connect();// 开始连接

			int code = conn.getResponseCode();// 得到服务器的响应码
			if (code == 200) {
				// 访问成功
				InputStream is = conn.getInputStream();// 获得服务器返回的数据流

				Bitmap bitmap = BitmapFactory.decodeStream(is);// 根据流数据创建一个bitmap位图对象
				return bitmap;
			} else {
				Log.i(TAG, "访问失败!访问码为:" + code);
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (conn != null) {
				conn.disconnect();// 关闭连接
			}
		}
		return null;
	}
}

除了Handler方法外,在子线程中调用runOnUiThread();方法,也可以实现程序在主线程中执行。比如在子线程中想要弹出吐司,就可以用该方法。

// 执行任务在主线程中
runOnUiThread(new Runnable() {
	@Override
	public void run() {
		// 就是在主线程中操作
		Toast.makeText(MainActivity.this, "操作成功!", 0).show();
	}
});


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值