Android 8+设备触发NullPointerException:调用Drawable.isProjected()对象为空求助
解决Android 8.0+三星/华为设备上的AdaptiveIconDrawable NullPointerException问题
从你描述的情况和Fabric日志来看,这个异常是Android 8.0引入自适应图标(AdaptiveIconDrawable)后,三星、华为这类定制ROM在图标处理上的边界case导致的——当系统调用AdaptiveIconDrawable.isProjected()时,Drawable对象为空,触发了空指针异常。下面是几个经过验证的解决方案:
1. 安全获取应用图标,添加兜底逻辑
首先要确保从PackageManager获取应用图标时不会返回null,并且在获取失败时用默认图标兜底:
public Drawable getAppIcon(Context context, String packageName) { PackageManager pm = context.getPackageManager(); Drawable appIcon = null; try { ApplicationInfo info = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA); appIcon = info.loadIcon(pm); } catch (PackageManager.NameNotFoundException e) { Log.e("AppIconLoader", "Failed to load icon for " + packageName, e); } // 兜底:如果获取到的图标为空,使用默认图标替代 if (appIcon == null) { appIcon = ContextCompat.getDrawable(context, R.drawable.ic_default_app_icon); } return appIcon; }
2. 将AdaptiveIconDrawable转换为BitmapDrawable
部分定制ROM的AdaptiveIconDrawable实现存在缺陷,直接使用容易触发内部空指针。把它转换成BitmapDrawable可以绕过系统的特殊处理逻辑:
private Drawable convertAdaptiveIconToBitmap(Context context, Drawable icon) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && icon instanceof AdaptiveIconDrawable) { Bitmap bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); icon.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); icon.draw(canvas); return new BitmapDrawable(context.getResources(), bitmap); } return icon; }
在给RecyclerView的ImageView设置图标前,调用这个转换方法:
Drawable icon = getAppIcon(context, appInfo.packageName); icon = convertAdaptiveIconToBitmap(context, icon); holder.appIconImageView.setImageDrawable(icon);
3. 检查RecyclerView Item布局的背景设置
如果你的Item布局中某个View的background使用了自适应图标或动态设置Drawable,要确保不会设置为null。比如避免直接调用view.setBackgroundDrawable(null),而是替换为设置透明背景或默认背景。
额外建议
- 优先在三星、华为的Android 8.0+设备上做针对性测试,覆盖系统应用、第三方应用、带自适应图标的应用等不同场景
- 可以尝试用
PackageManager.getDrawable()替代loadIcon(),部分ROM下这个方法的稳定性更好
内容的提问来源于stack exchange,提问作者Reza
相关产品推荐
相关产品推荐

