您的位置:首页 > 移动开发 > Android开发

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

2016-04-13 23:45 513 查看
在初学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发送消息相关的方法有:<
4000
/p>
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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: