| 異常 | 典型原因 | 排查方向 |
| NullPointerException | findViewById 找不到、Intent 取值為空 | 檢查布局 ID、Intent Extra 鍵名一致性 |
| SecurityException | 缺少權限(相機、儲存、定位等) | Manifest 聲明 + 6.0+ 動態申請 |
| ClassNotFoundException | 多 dex 未配置、ProGuard 過度混淆 | 啟用 MultiDex、keep 關鍵類 |
| NetworkOnMainThreadException | 主線程發起網路請求 | 遷移至子線程/協程/Flow |
2. 版本適配檢查清單
- targetSdkVersion:真機 Android 版本 ≤ targetSdkVersion 否則行為差異大
- 權限模型:Android 6.0+ 必須動態申請危險權限,模擬器常自動授權
- 分區儲存:Android 10+
requestLegacyExternalStorage 臨時緩解,11+ 必須用 MediaStore
- 隱式 Intent 限制:Android 11+ 需
<queries> 聲明可見套件
- 前台服務:Android 14+ 前台服務類型強制聲明
3. 針對引導頁閃退的專項排查
// SplashActivity 典型錯誤模式
public class SplashActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
// 錯誤 1:未判斷權限直接跳轉
new Handler().postDelayed(() -> {
startActivity(new Intent(this, MainActivity.class));
finish();
}, 2000);
}
}
修正版:
public class SplashActivity extends AppCompatActivity {
private static final int REQ_PERMISSION = 100;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkAndRequestPermissions();
} else {
navigateToMain();
}
}
private void checkAndRequestPermissions() {
List needed = new ArrayList<>();
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
needed.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
// 添加其他必要權限...
if (needed.isEmpty()) {
navigateToMain();
} else {
ActivityCompat.requestPermissions(this,
needed.toArray(new String[0]), REQ_PERMISSION);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQ_PERMISSION) {
boolean allGranted = true;
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
allGranted = false;
break;
}
}
if (allGranted) navigateToMain();
else showPermissionDeniedDialog(); // 引導用戶去設定開啟
}
}
private void navigateToMain() {
startActivity(new Intent(this, MainActivity.class));
finish();
}
}
進階除錯技巧
- StrictMode:開發階段開啟
StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build() 捕獲檔案洩漏
- LeakCanary:自動檢測記憶體洩漏(引導頁常因持有 Context 導致)
- Firebase Crashlytics:線上崩潰自動上報分組,無需連線即可分析
- ADB 命令:
adb logcat -d | grep -i "exception\|error\|crash" 快速抓取歷史日誌
總結
「模擬器正常、真機閃退」90% 是權限缺失或版本適配問題。養成習慣:真機調試為主,模擬器為輔;每次升級 targetSdkVersion 必跑全量真機回歸;引導頁作為啟動入口,務必做權限預檢與優雅降級。Logcat 是神燈,善用之,百病消。
- 上一篇文章: Android ListView 項目內按鈕點擊事件完美處理:getView 綁定與項目點擊共存方案
- 下一篇文章: 8086 汇编语言:字符串小寫轉大寫完整實現與錯誤修正
Copyright ©
程式碼之家 All Rights Reserved