码迷,mamicode.com
首页 > 编程语言 > 详细

主线程阻塞、消息队列机制和图片下载

时间:2016-07-22 19:24:05      阅读:152      评论:0      收藏:0      [点我收藏+]

标签:

# 主线程阻塞

public class SleepActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.message_test);
}
public void click(View v){
try {
Thread.sleep(7000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Toast.makeText(this, "点击了按钮", 1).show();
}
}

* 当点下按钮时,UI停顿7s,这时其它操作是无效的。这就是主线程阻塞。我们为了防止阻塞,一般耗时操作放到其它线程中。可以参考我的线程相关博文。

# 下载网络图片

* 如果我们这样写

public class MessageTestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.message_test);
}
public void click(View v){
String path = "";
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//对连接对象初始化
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.connect();
if(conn.getResponseCode() == 200){
InputStream in = conn.getInputStream();
Bitmap bm = BitmapFactory.decodeStream(in);
ImageView image = (ImageView) findViewById(R.id.image);
image.setImageBitmap(bm);
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下载图片"
android:onClick="click"/>
<ImageView
android:id="@+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
 
</LinearLayout>
* 这样在Android4.0之前是可以的,4.0之后,为防止主线程阻塞,像下载图片这样的耗时操作是不允许在主线程中运行
* 另外,上边代码还有一个问题。主线程又称UI线程,因为只有在主线程中,才能刷新UI,上边的bm是不会加载到界面的。
* 所以我们要用到伟大的:消息队列机制

# 消息队列机制
* 主线程创建时,系统会同时创建消息队列对象(MessageQueue)和消息轮询器对象(Looper)
* 轮询器的作用,就是不停的检测消息队列中是否有消息(Message)
* 消息队列一旦有消息,轮询器会把消息对象传给消息处理器(Handler),处理器会调用handleMessage方法来处理这条消息,handleMessage方法运行在主线程中,所以可以刷新ui
* 总结:只要消息队列有消息,handleMessage方法就会调用
* 子线程如果需要刷新ui,只需要往消息队列中发一条消息,触发handleMessage方法即可
* 子线程使用处理器对象的sendMessage方法发送消息
* 我们这样改就可以了:
public class MessageTestActivity extends Activity {
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
ImageView image = (ImageView) findViewById(R.id.image);
image.setImageBitmap((Bitmap) msg.obj);//msg.obj是Object类型,所以必须强转
};
};
 
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.message_test);
}
public void click(View v){
String path = "";
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//对连接对象初始化
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.connect();
if(conn.getResponseCode() == 200){
InputStream in = conn.getInputStream();
Bitmap bm = BitmapFactory.decodeStream(in);
Message msg = new Message();
msg.obj = bm;//Message是可以携带任何Object对象
handler.sendMessage(msg);
} else {
// 这个也属于主线程的操作,所以也不能放到这里
// Toast.makeText(MessageTestActivity.this, "请求失败", 1).show();
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
* 如果下载完成,就会发送消息到消息队列,轮询器Looper检查到消息就会调用handleMessage,但是如果我们有很多不同消息,如何区分?
* 一般我们会设置Message.what,让Message携带一个整型数据,做判断

public class MessageTestActivity extends Activity {
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 1:
ImageView image = (ImageView) findViewById(R.id.image);
image.setImageBitmap((Bitmap) msg.obj);//msg.obj是Object类型,所以必须强转
break;
case 0:
Toast.makeText(MessageTestActivity.this, "请求失败", 1).show();
break;
}
};
};
 
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.message_test);
}
public void click(View v){
String path = "http://f.hiphotos.baidu.com/zhidao/pic/item/1e30e924b899a90129bad66e1d950a7b0308f5df.jpg";
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//对连接对象初始化
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.connect();
if(conn.getResponseCode() == 200){
InputStream in = conn.getInputStream();
Bitmap bm = BitmapFactory.decodeStream(in);
Message msg = new Message();
msg.obj = bm;//Message是可以携带任何Object对象
msg.what = 1;
handler.sendMessage(msg);
} else {
// 这个也属于主线程的操作,所以也不能放到这里
// Toast.makeText(MessageTestActivity.this, "请求失败", 1).show();
Message msg = handler.obtainMessage();
msg.what = 0;
handler.sendMessage(msg);
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
* 上边程序还是报错,前边说了,要建新线程:
public class MessageTestActivity extends Activity {
	Handler handler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case 1:
				ImageView image = (ImageView) findViewById(R.id.image);
				image.setImageBitmap((Bitmap) msg.obj);//msg.obj是Object类型,所以必须强转
				break;
			case 0:
				Toast.makeText(MessageTestActivity.this, "请求失败", 1).show();
				break;
			}
		};
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.message_test);
	}
	public void click(View v){
		Thread t = new Thread(){
			public void run() {
				
				String path = "http://f.hiphotos.baidu.com/zhidao/pic/item/1e30e924b899a90129bad66e1d950a7b0308f5df.jpg";
				try {
					URL url = new URL(path);
					HttpURLConnection conn = (HttpURLConnection) url.openConnection();
					//对连接对象初始化
					conn.setRequestMethod("GET");
					conn.setConnectTimeout(5000);
					conn.setReadTimeout(5000);
					conn.connect();
					if(conn.getResponseCode() == 200){
						InputStream in = conn.getInputStream();
						Bitmap bm = BitmapFactory.decodeStream(in);
						Message msg = new Message();
						msg.obj = bm;//Message是可以携带任何Object对象
						msg.what = 1;
						handler.sendMessage(msg);
					} else {
						Message msg = handler.obtainMessage();
						msg.what = 0;
						handler.sendMessage(msg);
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			};
		};
		t.start();
	}
}
* 这次可以运行了,但是Handler是报警告的,我们应该把handler定义成静态变量,这样,程序任何类都可以调用,以后开发中,会发现相当方便。
* 最终的代码
public class MessageTestActivity extends Activity {
	static ImageView image;
	static MessageTestActivity mta;
	static Handler handler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			switch (msg.what) {
			case 1:
				image.setImageBitmap((Bitmap) msg.obj);//msg.obj是Object类型,所以必须强转
				break;
			case 0:
				Toast.makeText(mta, "请求失败", 1).show();
				break;
			}
		};
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.message_test);
		image = (ImageView) findViewById(R.id.image);
		mta = this;
	}
	public void click(View v){
		Thread t = new Thread(){
			public void run() {
				
				String path = "http://f.hiphotos.baidu.com/zhidao/pic/item/1e30e924b899a90129bad66e1d950a7b0308f5df.jpg";
				try {
					URL url = new URL(path);
					HttpURLConnection conn = (HttpURLConnection) url.openConnection();
					//对连接对象初始化
					conn.setRequestMethod("GET");
					conn.setConnectTimeout(5000);
					conn.setReadTimeout(5000);
					conn.connect();
					if(conn.getResponseCode() == 200){
						InputStream in = conn.getInputStream();
						Bitmap bm = BitmapFactory.decodeStream(in);
						Message msg = new Message();
						msg.obj = bm;//Message是可以携带任何Object对象
						msg.what = 1;
						handler.sendMessage(msg);
					} else {
						Message msg = handler.obtainMessage();
						msg.what = 0;
						handler.sendMessage(msg);
					}
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			};
		};
		t.start();
	}
}







主线程阻塞、消息队列机制和图片下载

标签:

原文地址:http://blog.csdn.net/u013475983/article/details/51993553

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!