Android开发常见疑难问题及解决方案

425 阅读3分钟

在 Android 开发中,常见的疑难问题及代码解决方案如下:


1. 内存泄漏(Memory Leak)

问题场景:非静态内部类(如 Handler)隐式持有外部类(如 Activity)的引用。

// 错误写法:Handler 导致 Activity 无法回收
public class MainActivity extends Activity {
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // 更新 UI
        }
    };
}

解决方案:使用静态内部类 + WeakReference

public class MainActivity extends Activity {
    private static class SafeHandler extends Handler {
        private final WeakReference<MainActivity> mActivity;

        SafeHandler(MainActivity activity) {
            mActivity = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = mActivity.get();
            if (activity != null) {
                // 更新 UI
            }
        }
    }

    private final Handler mHandler = new SafeHandler(this);
}

2. ANR(Application Not Responding)

问题场景:主线程执行耗时操作(如网络请求或数据库查询)。

// 错误写法:在主线程执行耗时操作
fun loadData() {
    Thread.sleep(5000) // 模拟耗时操作
    updateUI()
}

解决方案:使用协程(Coroutine)异步处理

// 使用 Kotlin 协程
fun loadData() {
    CoroutineScope(Dispatchers.Main).launch {
        val result = withContext(Dispatchers.IO) {
            // 在后台线程执行耗时操作
            delay(5000)
            "Data Loaded"
        }
        updateUI(result) // 回到主线程更新 UI
    }
}

3. UI 卡顿(UI Jank)

问题场景:复杂布局导致渲染性能下降。

<!-- 错误写法:多层嵌套的 LinearLayout -->
<LinearLayout>
    <LinearLayout>
        <LinearLayout>
            <!-- 复杂子视图 -->
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

解决方案:使用 ConstraintLayout 扁平化布局

<androidx.constraintlayout.widget.ConstraintLayout>
    <TextView
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"/>
    <Button
        app:layout_constraintTop_toBottomOf="@id/textView"
        app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

4. 兼容性问题(API 差异)

问题场景:不同 Android 版本行为不一致(如通知渠道在 Android 8.0+ 强制要求)。

// 错误写法:未处理 API 26+ 的通知渠道
NotificationManager manager = getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification.Builder(context)
    .setContentTitle("Title")
    .build();
manager.notify(1, notification);

解决方案:动态判断 API 版本

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    // 创建通知渠道(仅需执行一次)
    NotificationChannel channel = new NotificationChannel("channel_id", "Channel Name", IMPORTANCE_DEFAULT);
    manager.createNotificationChannel(channel);
}

Notification.Builder builder = new Notification.Builder(context);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    builder.setChannelId("channel_id");
}
manager.notify(1, builder.build());

5. 数据存储安全(SharedPreferences)

问题场景:明文存储敏感数据。

// 错误写法:明文存储密码
SharedPreferences prefs = getSharedPreferences("user", MODE_PRIVATE);
prefs.edit().putString("password", "123456").apply();

解决方案:使用 EncryptedSharedPreferences(Jetpack Security 库)

// 添加依赖:implementation "androidx.security:security-crypto:1.1.0-alpha03"
val masterKey = MasterKey.Builder(context)
    .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
    .build()

val prefs = EncryptedSharedPreferences.create(
    context,
    "secret_shared_prefs",
    masterKey,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

prefs.edit().putString("password", "encrypted_data").apply()

6. 多线程并发问题

问题场景:多线程访问共享数据导致状态不一致。

// 错误写法:非线程安全的单例模式
public class Singleton {
    private static Singleton instance;

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

解决方案:使用双重检查锁定(Double-Checked Locking)

public class Singleton {
    private static volatile Singleton instance;

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

7. Bitmap OOM(Out of Memory)

问题场景:加载大图导致内存溢出。

// 错误写法:直接加载原图
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
imageView.setImageBitmap(bitmap);

解决方案:使用 inSampleSize 压缩图片

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imagePath, options);

// 计算缩放比例
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(imagePath, options);
imageView.setImageBitmap(bitmap);

总结

通过合理使用弱引用、协程/线程池、性能优化工具(如 Profiler)、版本兼容检查以及加密存储等手段,可以解决大部分 Android 开发中的疑难问题。同时建议结合 Android Studio 的 LintMemory ProfilerStrictMode 等工具进行深度排查。