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

Android Handler多线程技术 个人心得

2016-07-28 05:51 429 查看
这里有一篇详细介绍的文章:http://www.111cn.net/sj/android/95458.htm
在进行解析URL往app中加载图片时,我首先引发了android.os.NetworkOnMainException的异常,原因在于在主线程中进行了网络请求的操作(真的是太菜了~),一般来说这种操作会导致UI线程堵塞,从而引起极差的用户体验,所以一般都是在子线程中异步加载。然而还有一个坑是,若要加载图片,必定会引发修改UI的操作(ImageView),但我们又知道更新UI的操作必须在UI线程或者说主线程中进行,所以综合下来我们考虑Handler通信的方式(其实AsyncTask也一样)来完成这个功能。
那么这里我们需要利用Handler同时完成主线程子线程的信息互换:主线程要把从EditText输入的URL的String发送给子线程去网络请求,子线程处理之后要把相应的bitmap传回给主线程来更新UI。主线程给子线程传递信息很简单,因为自身有默认的MessageQueue,无需调用Looper.prepare()以及Looper.loop()方法来维护MessageQueue,自动轮询。所以,在主线程中初始化的Handler就直接通过子线程发送过来的Message的what,通过switch-case判断来完成对应的功能。那么在子线程中,需要相应的操作来完成消息队列的轮询,并且在自己的线程中初始化自己的handler,同时Looper.prepare()才能把这个Handler同自己绑定,以实现传输信息的作用。

那么由于是个人心得,Handler内部机制就不多说啦,直接上代码配合注释希望能让你看懂!

public class MainActivity extends AppCompatActivity {
private EditText editText;
private Button preview_btn;
private Button post_btn;
private ImageView image;
private Bitmap bitmap;
private String path;
private PreviewThread previewThread;
private PostThread postThread;
/**
* 主线程的Handler对象,更新UI
*/
private Handler myHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case 1:
image.setImageBitmap((Bitmap) msg.obj);
break;
case 2:
image.setImageBitmap((Bitmap) msg.obj);
break;
}
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = (EditText) findViewById(R.id.edit);
preview_btn = (Button) findViewById(R.id.preview);
post_btn = (Button) findViewById(R.id.post);
image = (ImageView) findViewById(R.id.image);
/*
千万不要忘记打开线程!!
*/
previewThread = new PreviewThread();
previewThread.start();
postThread = new PostThread();
postThread.start();
/**
* 在对应的按钮事件中,我们发送给子线程path,也就是主线程与子线程通信
*/
preview_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
path = editText.getText().toString();
if (path.equals("")) {
setDialog("preview-operation denied.");
} else {
Message msg = new Message();
msg.obj = path;
previewThread.myHandler1.sendMessage(msg);
}
}
});
/**
* 在对应的按钮事件中,我们发送给子线程path,也就是主线程与子线程通信
*/
post_btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
path = editText.getText().toString();
if (path.equals("")) {
setDialog("Post-operation denied.");
} else {
Message msg = new Message(); //也可以选用obtainMessage()那个方法
msg.obj = path; //直接装载path
postThread.myHandler2.sendMessage(msg); //发送给子线程
}
}
});
// post_btn.setEnabled(false);
}

/**
*弹窗提醒
*/
public void setDialog(String msg) {
new AlertDialog.Builder(MainActivity.this)
.setTitle("Warning")
.setMessage(msg)
.setNegativeButton("Okay",
new DialogInterface.OnClickListener() {

@Override
public void onClick(DialogInterface dialogInterface, int i) {

}
}).show();
}

/**
* 预览,加载图片网络请求的子线程,拥有自己独立的handler以收发信息
* 在哪个线程中初始化Handler,这个Handler就是谁的,不过还需要跟Looper绑定才能完成收发信息
*/
class PreviewThread extends Thread{
private Handler myHandler1;
@Override
public void run() {
Looper.prepare();
myHandler1 = new Handler(){
@Override
public void handleMessage(Message msg) {
String path = (String) msg.obj;
URL httpUrl = null;
try {
httpUrl = new URL(path);
HttpURLConnection connection = (HttpURLConnection) httpUrl.openConnection();
connection.connect();
bitmap = BitmapFactory.decodeStream(connection.getInputStream());
// post_btn.setEnabled(true);
Message toMain = new Message();
toMain.obj = bitmap; //直接把bitmap向上转型,赋给obj以完成信息装载
toMain.what = 1; //设置what以便于主线程Handler的switch-case
myHandler.sendMessage(toMain); //发送给谁就引用谁的sendMessage()
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
};
Looper.loop(); //启动消息循环
}
}

/**
* 设置背景的子线程,与上面的子线程类似不再赘述
*/
class PostThread extends Thread{
private Handler myHandler2;

@Override
public void run() {
Looper.prepare();
myHandler2 = new Handler() {
@Override
public void handleMessage(Message msg) {
String path2 = (String) msg.obj;
URL httpUrl = null;
try {
httpUrl = new URL(path2);
HttpURLConnection connection = (HttpURLConnection) httpUrl.openConnection();
connection.connect();
MainActivity.this.setWallpaper(connection.getInputStream());
bitmap = null;
post_btn.setEnabled(true);
Message toMain = new Message();
toMain.obj = bitmap;
toMain.what = 2;
myHandler.sendMessage(toMain);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
};
}
}
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android handler