Android非主线程更新UI
16lz
2021-01-23
说明:
本文不是讲怎么通过Handler机制来进行UI的更新,而是绕过Android更新UI的线程判断机制,来进行UI更新的。
正文:
Android要求我们在主线程更新UI,如果在非主线程更新UI,就出出现如下异常:
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6462)
进入ViewRootImpl.checkThead()源码:
void checkThread() { if (mThread != Thread.currentThread()) { throw new CalledFromWrongThreadException( "Only the original thread that created a view hierarchy can touch its views."); } }
Android UI更新的时候在这里进行的线程判断,如果不是主线程,就不能更新UI,即抛出异常CalledFromWrongThreadException
。所以我们只要在其他线程里把这个异常给捕获了,就可以在别的线程里更新UI了。代码如下:
class Test implements Runnable { private TextView textView; public Test(TextView textView) { this.textView = textView; } @Override public void run() { try { textView.setText("new thread set textview"); } catch (RuntimeException e) { e.printStackTrace(); } } }
当然这种方式违法了Android官方本意,也没有什么技术含量。我为什么会想到这种方式呢?还是因为看了何红辉的《Android源码设计模式解析与实践》一书中的一个Demo产生了疑问。
大致代码如下(加入了我的一部分调试代码):
public class ImageLoader { private static final String TAG = "ImageLoader"; LruCache mImageCache; ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); public Thread mThread; public ImageLoader() { initImageCache(); } private void initImageCache() { final int maxMermory = (int) (Runtime.getRuntime().maxMemory() / 1024); final int cacheSize = maxMermory / 4; mImageCache = new LruCache(cacheSize) { @Override protected int sizeOf(String url, Bitmap bitmap) { return bitmap.getRowBytes() * bitmap.getHeight() / 1024; } }; } public void displayImage(final String url, final ImageView imageView, final TextView textView) { imageView.setTag(url); mExecutorService.submit(new Runnable() { @Override public void run() { Bitmap bitmap = downloadImage(url); if (bitmap == null) { Log.e(TAG, "bitmap is null!!!!"); return; } if (imageView.getTag().equals(url)) { textView.setText("线程池中的数据");// if (Looper.myLooper() == Looper.getMainLooper()) imageView.setImageBitmap(bitmap);// if (mThread == Thread.currentThread()) {//// } else { System.out.println("啦啦啦啦德玛西"); throw new IllegalArgumentException("你必须在主线程调用该方法");// } } bitmap.recycle(); mImageCache.put(url, bitmap); } }); } public Bitmap downloadImage(String imageUrl) { Bitmap bitmap = null; try { URL url = new URL(imageUrl); final URLConnection conn = url.openConnection();// final HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.connect(); bitmap = BitmapFactory.decodeStream(conn.getInputStream()); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return bitmap; }}
我发现一个问题:在线程池中竟然可以更新UI,而我又试了在普通的线程了确不行,并且在线程池中的run()方法里,竟然无法抛出异常。所以我又试了如下代码:
public class TestExecutor { public static void main(String[] args) { ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); mExecutorService.submit(new Runnable() { @Override public void run() { throw new IllegalStateException("啦啦啦啦德玛西亚"); } }); }}
这里边的异常也如法抛出。于是看了看源码,上网查看了线程池的使用,发现在线程池自动捕获了我们在run()方法里抛出的异常,所以程序能够正常执行。
具体请参考,Java线程池异常处理最佳实践
说到底还是涉及到了Java线程池的使用问题,希望通过这个例子加深大家对Java线程池的理解。
更多相关文章
- 移动网站开发中常用的10段JavaScript代码
- Android Studio制作简易计算器源代码及详解
- Android 代码实现logcat输出到文件
- Java(Android)线程池
- Android代码中运行shell命令
- android中 代码实现截图功能(静态+动态视频)
- Android获取cpu和内存信息、网址的代码
- Android Studio 配置SVN 及 代码管理