android学习——handler的学习及实现封装下载图片功能

在初学handler的时候不得不说自己当时真是毫无悟性,硬是把handler和开通子线程混为一谈,当时脑子混乱的不行,也是看了一些博客后理清了头脑。

android是不允许在主线程中进行耗时操作的,否则会报错,出现ANR(Application Not Responding)现象,这时候必须开一个子线程,此时是不需要必须有handler的,而如果我们在子线程中去操作UI,那么程序就回给我们抛出异常。这时候我们就需要在子线程中通过handler来更新UI。

现在小小总结一下,自己都觉得可笑。

现在通过一个点击按钮下载一张图片的demo来详解一下handler。


Handler可以把一个Message对象或者Runnable对象压入到消息队列中,进而在UI线程中获取Message或者执行Runnable对象,所以Handler把压入消息队列有两大体系,Post和Message。

Post

  对于Handler的Post方式来说,它会传递一个Runnable对象到消息队列中,在这个Runnable对象中,重写run()方法。一般在这个run()方法中写入需要在UI线程上的操作。

  在Handler中,关于Post方式的方法有:

  • boolean post(Runnable r):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,立即执行。
  • boolean postAtTime(Runnable r,long uptimeMillis):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,在特定的时间执行。
  • boolean postDelayed(Runnable r,long delayMillis):把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,延迟delayMills秒执行
  • void removeCallbacks(Runnable r):从消息队列中移除一个Runnable对象。

Message

  Handler如果使用sendMessage的方式把消息入队到消息队列中,需要传递一个Message对象,而在Handler中,需要重 写handleMessage()方法,用于获取工作线程传递过来的消息,此方法运行在UI线程上。

     对于Message对象,一般使用Message.obtain()这个静态的方法或者 Handler.obtainMessage()获取。Message.obtain()会从消息池中获取一个Message对象,如果消息池中是空的, 才会使用构造方法实例化一个新Message,这样有利于消息资源的利用。并不需要担心消息池中的消息过多,它是有上限的,上限为10个。 Handler.obtainMessage()具有多个重载方法,如果查看源码,会发现其实Handler.obtainMessage()在内部也是 调用的Message.obtain()。 

    Message.obtain()方法具有多个重载方法,大致可以分为为两类,一类是无需传递Handler对象,对于这类的方法,当填充好消息后,需要调用Handler.sendMessage()方法来发送消息到消息队列中。第二类需要传递一个Handler对象,这类方法可以直接使用 Message.sendToTarget()方法发送消息到消息队列中,这是因为在Message对象中有一个私有的Handler类型的属性 Target,当时obtain方法传递进一个Handler对象的时候,会给Target属性赋值,当调用sendToTarget()方法的时候,实 际在它内部还是调用的Target.sendMessage()方法。


Handler中,与Message发送消息相关的方法有:

  • Message obtainMessage():获取一个Message对象。
  • boolean sendMessage():发送一个Message对象到消息队列中,并在UI线程取到消息后,立即执行。
  • boolean sendMessageDelayed():发送一个Message对象到消息队列中,在UI线程取到消息后,延迟执行。
  • boolean sendEmptyMessage(int what):发送一个空的Message对象到队列中,并在UI线程取到消息后,立即执行。
  • boolean sendEmptyMessageDelayed(int what,long delayMillis):发送一个空Message对象到消息队列中,在UI线程取到消息后,延迟执行。
  • void removeMessage():从消息队列中移除一个未响应的消息。
Handler的基本介绍差不多就是这些,接下来上代码,进行了封装:

DownloadContent.java

<span style="font-size:14px;">public class DownloadContent {
	private ProgressDialog dialog;
	private static int IS_FINISH = 1;

	public DownloadContent(Context context) {
		dialog = new ProgressDialog(context);
		dialog.setTitle("提示");
		dialog.setMessage("正在玩命加载数据......");
	}

	@SuppressLint("HandlerLeak")
	public void downLoad(final String path, final DownloadCallback callback) {
		final Handler handler = new Handler() {
			public void handleMessage(Message msg) {
				super.handleMessage(msg);
				byte[] result = (byte[]) msg.obj;
				callback.loadContent(result);
				if (msg.what == IS_FINISH) {
					dialog.dismiss();
				}
			}
		};

</span>
<span style="font-size:14px;">/*开通子线程有两种方法:<span style="font-family: verdana, 'ms song', Arial, Helvetica, sans-serif;">用 Runnable 或者 Thread </span><p>创建线程哪种方式更好呢?什么情况下使用它?这个问题很容易回答,如果你知道Java不支持类的多重继承,但允许你调用多个接口。所以如果你要继承其他类,当然是调用Runnable接口更好了。*/</p>
//调用Runnable接口,写法一
//		class MyThread implements Runnable {

		//			@Override
		//public void run() {
		//	HttpClient httpClient = new DefaultHttpClient();
		//	HttpGet httpGet = new HttpGet(path);
		//	HttpResponse response;
		//	try {
		//		response = httpClient.execute(httpGet);
		//		if (response.getStatusLine().getStatusCode() == 200) {
		//			byte[] result = EntityUtils.toByteArray(response
		//					.getEntity());
		//			Message message = Message.obtain();
		//			message.obj = result;
		//			message.what = IS_FINISH;
		//			handler.sendMessage(message);
		//		}
		//	} catch (Exception e) {
		//
		//		e.printStackTrace();
		//	} finally {
		//		httpClient.getConnectionManager().shutdown();
		//	}

		//}
		//}
		//new Thread(new MyThread()).start();</span>
</pre><pre name="code" class="java"><span style="font-size:14px;"><pre name="code" class="java" style="color: rgb(57, 57, 57); font-size: 14px; line-height: 21px;">	/*<span style="font-family: verdana, 'ms song', Arial, Helvetica, sans-serif;">调用Runnable接口,写法二</span></span>
<span style="font-size:14px;">	new Thread() {
			public void run() {

				HttpClient httpClient = new DefaultHttpClient();
				HttpGet httpGet = new HttpGet(path);
				HttpResponse response;
				try {
					response = httpClient.execute(httpGet);
					if (response.getStatusLine().getStatusCode() == 200) {
						byte[] result = EntityUtils.toByteArray(response
								.getEntity());
						Message message = Message.obtain();
						message.obj = result;
						message.what = IS_FINISH;
						handler.sendMessage(message);
					}
				} catch (Exception e) {

					e.printStackTrace();
				} finally {
					httpClient.getConnectionManager().shutdown();
				}

			};
		}.start();*/</span>

 
<span style="font-size:14px;">//继承Thread</span>
<span style="font-size:14px;">		class MyThread extends Thread{
			public void run() {

				HttpClient httpClient = new DefaultHttpClient();
				HttpGet httpGet = new HttpGet(path);
				HttpResponse response;
				try {
					response = httpClient.execute(httpGet);
					if (response.getStatusLine().getStatusCode() == 200) {
						byte[] result = EntityUtils.toByteArray(response
								.getEntity());
						Message message = Message.obtain();
						message.obj = result;
						message.what = IS_FINISH;
						handler.sendMessage(message);
					}
				} catch (Exception e) {

					e.printStackTrace();
				} finally {
					httpClient.getConnectionManager().shutdown();
				}	
				
			};
		}
		
		MyThread myThread = new MyThread();
		myThread.start();
</span>
<span style="font-size:14px;">		dialog.show();
	}

	public interface DownloadCallback {

		public void loadContent(byte[] result);
	}
}</span>

MainActivity:

<span style="font-size:14px;">public class MainActivity extends ActionBarActivity {
	private final String pathString = "http://attachments.gfan.com/forum/attachments2/day_120709/120709183388fdedffcd0878e9.jpg";
	private Button button;
	private ImageView image;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		button = (Button) findViewById(R.id.btn);
		image = (ImageView) findViewById(R.id.img);
		
		button.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				DownloadContent donwContent = new DownloadContent(MainActivity.this);
				donwContent.downLoad(pathString, new DownloadCallback() {
					
					@Override
					public void loadContent(byte[] result) {
						Bitmap bitmap = BitmapFactory.decodeByteArray(result, 0, result.length);
						image.setImageBitmap(bitmap);
					}
				});
			}
		});
		
	}


}</span>


贴一下用POST和HttpURLConnection的方法,这里没有用到封装,直接在一个Activity钟写的:

<span style="font-size:14px;">public class PostActivity extends Activity {

	private Button btn;
	private ImageView img;
	private ProgressDialog dialog;
	private static Handler handler = new Handler();
	private String path="http://img5.imgtn.bdimg.com/it/u=3829988479,3729798728&fm=21&gp=0.jpg";
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		btn = (Button) findViewById(R.id.btn);
		img = (ImageView) findViewById(R.id.img);
		
		
		dialog = new ProgressDialog(getApplicationContext());
		dialog.setTitle("提示");
		dialog.setMessage("正在努力下载");
		dialog.setCancelable(false);
		
		btn.setOnClickListener(new View.OnClickListener() {
			
			@Override
			public void onClick(View v) {
				new Thread(new MyThread()).start();
				
			}
		});
		
		
	}
	

	public class MyThread implements Runnable{
		private Bitmap bitmap;
		private InputStream is;

		public void run(){
			
			
			try {
				URL url = new URL(path);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setRequestMethod("GET");
				
				conn.setReadTimeout(5000);
				int code = conn.getResponseCode();
				
				if(code==200){
					
					is = conn.getInputStream();  
		            bitmap = BitmapFactory.decodeStream(is);
					
					handler.post(new Runnable() {
						public void run() {
							img.setImageBitmap(bitmap);
						}
					});
					
				}
			} catch (IOException e) {
				
				e.printStackTrace();
			}
		}
	}
	
}</span>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值