如何优化Thread代码,使EditText失焦时的图片请求后台运行不卡顿?
问题分析
- UI线程被阻塞:
getImageLogo方法里调用googleList.join()会强制UI线程等待子线程执行完毕,直接导致界面卡顿甚至无响应——UI线程必须持续处理用户交互,绝对不能被阻塞。 - Bitmap内存未优化:直接解码原始尺寸的图片会占用大量内存,拖慢界面渲染速度,还可能引发内存溢出。
- 无重复请求处理:用户多次切换EditText焦点时,会重复发起网络请求,浪费网络资源和CPU算力。
优化方案
1. 用协程替代Thread+Join(Android官方推荐)
协程可以在不阻塞UI线程的前提下执行后台任务,还能自动切换到主线程更新UI,同时支持取消未完成的请求,避免无效操作。
2. 优化Bitmap解码
通过采样率缩小图片尺寸,减少内存占用,提升RecyclerView的渲染流畅度。
3. 加入请求取消逻辑
当用户再次触发请求时,取消之前未完成的任务,避免资源浪费。
优化后的代码
Activity类
public class AddItem extends AppCompatActivity { private LoadingDialog loadingDialog; private RecyclerView imgList; private ArrayList<Bitmap> bitmapList = new ArrayList<>(); private BitmapAdapter adapter; private Job searchJob; // 管理搜索任务,支持取消 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 初始化视图、adapter等代码... et_title.setOnFocusChangeListener((v, hasFocus) -> { if (!hasFocus) { String serviceName = et_title.getText().toString().trim(); if (!TextUtils.isEmpty(serviceName)) { startImageSearch(serviceName); } else { bitmapList.clear(); adapter.notifyDataSetChanged(); } } }); } private void startImageSearch(String serviceName) { // 取消之前未完成的请求 if (searchJob != null && searchJob.isActive()) { searchJob.cancel(); } // 显示加载弹窗 if (loadingDialog != null && !loadingDialog.isShowing()) { loadingDialog.show(); } // 协程执行后台任务 searchJob = lifecycleScope.launch(Dispatchers.IO) { try { ArrayList<Bitmap> imageList = fetchGoogleImages(serviceName); // 切换到主线程更新UI withContext(Dispatchers.Main) { bitmapList.clear(); if (imageList != null) { bitmapList.addAll(imageList); } adapter.notifyDataSetChanged(); } } catch (Exception e) { Log.e("ImageSearchError", "搜索图片失败", e); withContext(Dispatchers.Main) { bitmapList.clear(); adapter.notifyDataSetChanged(); } } finally { // 关闭加载弹窗 withContext(Dispatchers.Main) { if (loadingDialog != null && loadingDialog.isShowing()) { loadingDialog.dismiss(); } } } }; } private ArrayList<Bitmap> fetchGoogleImages(String keyword) throws IOException { String newKeyword = keyword.toLowerCase(Locale.ROOT).replace(' ', '+'); String url = "https://www.google.gr/search?bih=427&biw=1835&hl=el&gbv=1&tbm=isch&og=&ags=&q=" + newKeyword; Document document = Jsoup.connect(url).get(); Elements imgElements = document.select("img"); ArrayList<Bitmap> bitmapList = new ArrayList<>(); for (int i = 1; i < imgElements.size() && i <= 7; i++) { // 取前7张图 String imgSrc = imgElements.get(i).absUrl("src"); if (TextUtils.isEmpty(imgSrc)) continue; try (InputStream inputStream = new URL(imgSrc).openStream()) { Bitmap bitmap = decodeBitmapFromStream(inputStream); bitmapList.add(bitmap); } catch (Exception e) { Log.w("ImageDecodeError", "解码图片失败: " + imgSrc, e); } } return bitmapList; } // 优化Bitmap解码,缩小图片尺寸 private Bitmap decodeBitmapFromStream(InputStream inputStream) throws IOException { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; // 先读取图片尺寸,不加载到内存 BitmapFactory.decodeStream(inputStream, null, options); // 计算采样率,将图片缩小到200dp宽高(可按需调整) int targetSize = dpToPx(200); options.inSampleSize = calculateInSampleSize(options, targetSize, targetSize); options.inJustDecodeBounds = false; // 重置流,重新读取 inputStream.reset(); return BitmapFactory.decodeStream(inputStream, null, options); } // 计算采样率,确保图片不超过目标尺寸 private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= 2; } } return inSampleSize; } // dp转px private int dpToPx(int dp) { return (int) (dp * getResources().getDisplayMetrics().density); } @Override protected void onDestroy() { super.onDestroy(); // 取消任务+回收Bitmap避免内存泄漏 if (searchJob != null) { searchJob.cancel(); } for (Bitmap bitmap : bitmapList) { if (!bitmap.isRecycled()) { bitmap.recycle(); } } bitmapList.clear(); } }
必要配置
- 在build.gradle中添加协程依赖:
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"(版本可按需更新) - 在AndroidManifest.xml中添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />
内容的提问来源于stack exchange,提问作者DjAs
相关产品推荐
相关产品推荐

