Android Handler多线程技术 个人心得
来源:互联网 发布:淘宝日本直邮可信吗 编辑:程序博客网 时间:2024/06/06 21:47
这里有一篇详细介绍的文章: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(); } } }; } }}
0 0
- Android Handler多线程技术 个人心得
- 【Android技术整理】Handler以及Handler如何实现多线程
- 多线程个人心得
- Android Handler个人见解
- 多线程个人技术总结
- android looper handler 多线程
- android handler 多线程demo
- android handler 多线程
- Handler与Android多线程
- android handler 多线程demo
- android handler 多线程demo
- Android--多线程之Handler
- Android 多线程通信Handler
- Android--多线程之Handler
- Android--多线程之Handler
- Android--多线程之Handler
- Android--多线程之Handler
- Android--多线程之Handler
- 85.You want to configure and schedule offline database backups to run automatically. Which tool or u
- 完整java开发中JDBC连接数据库代码和步骤
- 86.View the Exhibit to examine the output for the CROSSCHECK BACKUP command. Which statement is true
- Java中通过JDBC操作MySQL数据库
- 程序员使用Node的十个技巧
- Android Handler多线程技术 个人心得
- TuneLayer 实现 stacked denoising autoencoder
- lareval操作
- 如何在 MNIST 实现 CNN (tensorlayer, TuneLayer 实现)
- Eclipse连接MySQL数据库(傻瓜篇)
- dropout 的快熟实现笔记 --tensorlayer
- 87.You are managing an Oracle Database 11g database running in ARCHIVELOG mode. The Flash Recovery A
- 如何解决 TuneLayer read the docs API 不可见问题
- [leetcode] 310.Minimum Height Trees