【Android应用开发】 Android 崩溃日志 本地存储 与 远程保存
示例代碼下載 :?http://download.csdn.net/detail/han1202012/8638801;
一. 崩潰日志本地存儲(chǔ)
1. 保存原理解析
崩潰信息本地保存步驟 :?
-- 1. 自定義類實(shí)現(xiàn)?UncaughtExceptionHandler :?public class CrashHandler implements UncaughtExceptionHandler;
-- 2. 設(shè)置該自定義的?CrashHandler?類為單例模式 :?
// 單例模式private static CrashHandler INSTANCE = new CrashHandler();private CrashHandler() {}public static CrashHandler getInstance() {return INSTANCE;}-- 重寫 uncaughtException?方法 :? @Overridepublic void uncaughtException(Thread thread, Throwable ex)-- 自定義?handleException 方法處理異常信息 : 在該方法中進(jìn)行設(shè)備信息收集, 以及將信息保存到文件中;(1) UncaughtExceptionHandler 類解析
UncaughtExceptionHandler 作用 : 該類處理以下情況, 如果有未捕獲的異常發(fā)生, 出現(xiàn)了程序崩潰閃退的情況, 此時(shí)會(huì)回調(diào)該類的?uncaughtException 方法;
(2) 線程相關(guān)
線程相關(guān) : 每個(gè)線程都對(duì)應(yīng)有響應(yīng)的默認(rèn)的未捕獲異常處理器;
-- 獲取線程默認(rèn)的未捕獲異常處理器 :?Thread.getDefaultUncaughtExceptionHandler();
-- 設(shè)置線程默認(rèn)的未捕獲異常處理器 :?Thread.setDefaultUncaughtExceptionHandler(this);
(3)?uncaughtException 方法
uncaughtException 方法解析 :?
-- 回調(diào)時(shí)機(jī) : 出現(xiàn)未定義的異常時(shí);
-- 回調(diào)參數(shù) : 回調(diào)時(shí)會(huì)傳入 線程對(duì)象 和 要拋出的異常信息, 我們可以在程序中拿到這兩個(gè)信息;
public void uncaughtException(Thread thread, Throwable ex)
(4) 手機(jī)設(shè)備信息
手機(jī)設(shè)備信息手機(jī)步驟 :?
-- 1. 獲取包信息 :?
//獲取包管理器PackageManager pm = ctx.getPackageManager();//獲取包信息PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),PackageManager.GET_ACTIVITIES);-- 2. 獲取版本號(hào)信息 :?
if (pi != null) {//版本號(hào)String versionName = pi.versionName == null ? "null": pi.versionName;//版本代碼String versionCode = pi.versionCode + "";//將版本信息存放到 成員變量 Map<String, String> mInfos 中this.mInfos.put("versionName", versionName);this.mInfos.put("versionCode", versionCode);}
-- 3. 使用反射獲取 Build 類成員變量變量 , 并遍歷獲取這些變量內(nèi)容:?
//獲取 Build 中定義的變量, 使用反射方式獲取, 該類中定義了設(shè)備相關(guān)的變量信息Field[] fields = Build.class.getDeclaredFields();//遍歷獲取額變量, 將這些信息存放到成員變量 Map<String, String> mInfos 中for (Field field : fields) {try {//設(shè)置 Build 成員變量可訪問field.setAccessible(true);//將 設(shè)備相關(guān)的信息存放到 mInfos 成員變量中mInfos.put(field.getName(), field.get(null).toString());Log.d(TAG, field.getName() + " : " + field.get(null));} catch (Exception e) {Log.e(TAG, "an error occured when collect crash info", e);}}
(4) 保存崩潰信息到文件
保存文件步驟 : 這些步驟就很簡單了, 使用 IO流即可;
-- 1. 將之前獲取的 Build 設(shè)備信息, 版本信息, 崩潰信息轉(zhuǎn)為字符串 :?
//存儲(chǔ)相關(guān)的字符串信息StringBuffer sb = new StringBuffer();//將成員變量 Map<String, String> mInfos 中的數(shù)據(jù) 存儲(chǔ)到 StringBuffer sb 中for (Map.Entry<String, String> entry : this.mInfos.entrySet()) {String key = entry.getKey();String value = entry.getValue();sb.append(key + "=" + value + "\n");}-- 2. 在 Logcat 中打印崩潰信息 : 之前的默認(rèn)操作就是打印崩潰信息到 Logcat 中, 我們?cè)谶@里繼續(xù)執(zhí)行完這個(gè)步驟, 否則Logcat 中沒有數(shù)據(jù)的;
//將 StringBuffer sb 中的字符串寫出到文件中Writer writer = new StringWriter();PrintWriter printWriter = new PrintWriter(writer);ex.printStackTrace(printWriter);Throwable cause = ex.getCause();while (cause != null) {cause.printStackTrace(printWriter);cause = cause.getCause();}printWriter.close();-- 3. 寫出數(shù)據(jù)到文件中 : IO 流知識(shí)點(diǎn), 不再做過多贅述;
String result = writer.toString();sb.append(result);try {long timestamp = System.currentTimeMillis();String time = formatter.format(new Date());String fileName = "crash-" + time + "-" + timestamp + ".txt";if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {//獲取文件輸出路徑String path = Environment.getExternalStorageDirectory()+ "/crashinfo/";//創(chuàng)建文件夾和文件File dir = new File(path);if (!dir.exists()) {dir.mkdirs();}//創(chuàng)建輸出流FileOutputStream fos = new FileOutputStream(path + fileName);//向文件中寫出數(shù)據(jù)fos.write(sb.toString().getBytes());fos.close();}return fileName;} catch (Exception e) {Log.e(TAG, "an error occured while writing file...", e);}
2. 代碼及示例
(1) 相關(guān)代碼示例
故意發(fā)生錯(cuò)誤的代碼 :?
public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void onClick(View view) {int i = 3;i = i / 0;}}
CrashHandler 注冊(cè)代碼 : 在 Activity 或者 Application 中注冊(cè)該代碼;
CrashHandler.getInstance().init(getApplicationContext());
CrashHandler 代碼 :?
package cn.org.octpus.crash;import java.io.File; import java.io.FileOutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.Thread.UncaughtExceptionHandler; import java.lang.reflect.Field; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.Map;import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Build; import android.os.Environment; import android.os.Looper; import android.util.Log; import android.widget.Toast;/*** UncaughtExceptionHanlder 作用 : 處理 線程被未捕獲的異常終止 的情況, 一旦出現(xiàn)了未捕獲異常崩潰, 系統(tǒng)就會(huì)回調(diào)該類的* uncaughtException 方法;*/ public class CrashHandler implements UncaughtExceptionHandler {// 用于打印日志的 TAG 標(biāo)識(shí)符public static final String TAG = "octopus.CrashHandler";// 系統(tǒng)默認(rèn)的UncaughtException處理類private Thread.UncaughtExceptionHandler mDefaultHandler;// 程序的Context對(duì)象private Context mContext;// 用來存儲(chǔ)設(shè)備信息和異常信息private Map<String, String> mInfos = new HashMap<String, String>();// 用于格式化日期,作為日志文件名的一部分private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");// 單例模式private static CrashHandler INSTANCE = new CrashHandler();private CrashHandler() {}public static CrashHandler getInstance() {return INSTANCE;}/*** 初始化該類, 向系統(tǒng)中注冊(cè)* @param context*/public void init(Context context) {mContext = context;// 獲取系統(tǒng)默認(rèn)的 UncaughtException 處理器mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 設(shè)置該 CrashHandler 為程序的默認(rèn)處理器Thread.setDefaultUncaughtExceptionHandler(this);}/** 出現(xiàn)未捕獲的異常時(shí), 會(huì)自動(dòng)回調(diào)該方法* (non-Javadoc)* @see java.lang.Thread.UncaughtExceptionHandler#uncaughtException(java.lang.Thread, java.lang.Throwable)*/@Overridepublic void uncaughtException(Thread thread, Throwable ex) {/** 調(diào)用 handleException() 方法處理該線程* 如果返回 true 說明處理成功, 如果返回 false 則調(diào)用默認(rèn)的異常處理器來處理* 一般情況下該方法都會(huì)成功處理*/if (!handleException(ex) && mDefaultHandler != null) {// 如果用戶沒有處理則讓系統(tǒng)默認(rèn)的異常處理器來處理mDefaultHandler.uncaughtException(thread, ex);} else {try {Thread.sleep(3000);} catch (InterruptedException e) {Log.e(TAG, "error : ", e);}// 退出程序android.os.Process.killProcess(android.os.Process.myPid());System.exit(1);}}/*** 自定義錯(cuò)誤處理,收集錯(cuò)誤信息 發(fā)送錯(cuò)誤報(bào)告等操作均在此完成.* @param ex * 異常信息* @return * true:如果處理了該異常信息;否則返回false.*/private boolean handleException(Throwable ex) {if (ex == null) {return false;}/** 使用Toast來顯示異常信息, * 由于在主線程會(huì)阻塞, * 不能實(shí)時(shí)出現(xiàn) Toast 信息, * 這里我們?cè)谧泳€程中處理 Toast 信息*/new Thread() {@Overridepublic void run() {Looper.prepare();Toast.makeText(mContext, "很抱歉,程序出現(xiàn)異常,即將退出.", Toast.LENGTH_LONG).show();Looper.loop();}}.start();// 收集設(shè)備參數(shù)信息collectDeviceInfo(mContext);// 保存日志文件saveCrashInfo2File(ex);return true;}/*** 收集設(shè)備參數(shù)信息, 將手機(jī)到的信息存儲(chǔ)到* @param ctx* 上下文對(duì)象*/public void collectDeviceInfo(Context ctx) {try {//獲取包管理器PackageManager pm = ctx.getPackageManager();//獲取包信息PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),PackageManager.GET_ACTIVITIES);if (pi != null) {//版本號(hào)String versionName = pi.versionName == null ? "null": pi.versionName;//版本代碼String versionCode = pi.versionCode + "";//將版本信息存放到 成員變量 Map<String, String> mInfos 中this.mInfos.put("versionName", versionName);this.mInfos.put("versionCode", versionCode);}} catch (NameNotFoundException e) {Log.e(TAG, "an error occured when collect package info", e);}//獲取 Build 中定義的變量, 使用反射方式獲取, 該類中定義了設(shè)備相關(guān)的變量信息Field[] fields = Build.class.getDeclaredFields();//遍歷獲取額變量, 將這些信息存放到成員變量 Map<String, String> mInfos 中for (Field field : fields) {try {//設(shè)置 Build 成員變量可訪問field.setAccessible(true);//將 設(shè)備相關(guān)的信息存放到 mInfos 成員變量中mInfos.put(field.getName(), field.get(null).toString());Log.d(TAG, field.getName() + " : " + field.get(null));} catch (Exception e) {Log.e(TAG, "an error occured when collect crash info", e);}}}/*** 保存錯(cuò)誤信息到文件中* @param ex* @return 返回文件名稱,便于將文件傳送到服務(wù)器*/private String saveCrashInfo2File(Throwable ex) {//存儲(chǔ)相關(guān)的字符串信息StringBuffer sb = new StringBuffer();//將成員變量 Map<String, String> mInfos 中的數(shù)據(jù) 存儲(chǔ)到 StringBuffer sb 中for (Map.Entry<String, String> entry : this.mInfos.entrySet()) {String key = entry.getKey();String value = entry.getValue();sb.append(key + "=" + value + "\n");}//將 StringBuffer sb 中的字符串寫出到文件中Writer writer = new StringWriter();PrintWriter printWriter = new PrintWriter(writer);ex.printStackTrace(printWriter);Throwable cause = ex.getCause();while (cause != null) {cause.printStackTrace(printWriter);cause = cause.getCause();}printWriter.close();String result = writer.toString();sb.append(result);try {long timestamp = System.currentTimeMillis();String time = formatter.format(new Date());String fileName = "crash-" + time + "-" + timestamp + ".txt";if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {//獲取文件輸出路徑String path = Environment.getExternalStorageDirectory()+ "/crashinfo/";//創(chuàng)建文件夾和文件File dir = new File(path);if (!dir.exists()) {dir.mkdirs();}//創(chuàng)建輸出流FileOutputStream fos = new FileOutputStream(path + fileName);//向文件中寫出數(shù)據(jù)fos.write(sb.toString().getBytes());fos.close();}return fileName;} catch (Exception e) {Log.e(TAG, "an error occured while writing file...", e);}return null;} }
(2) 結(jié)果示例
崩潰日志存放文件路徑 :?/storage/sdcard0/crashinfo/crash-2015-04-27-19-31-41-1430134301642.txt;
-- 說明 : 其中?/storage/sdcard0/ 是系統(tǒng)默認(rèn)的 SD 卡路徑,?crashinfo/crash-2015-04-27-19-31-41-1430134301642.txt 是我們創(chuàng)建的文件;
崩潰日志內(nèi)容 :?
1430134301642.txt < HARDWARE=pxa1088 RADIO=unknown versionCode=1 HOST=SWDA2601 TAGS=release-keys ID=JDQ39 MANUFACTURER=samsung TYPE=user IS_TRANSLATION_ASSISTANT_ENABLED=false IS_SECURE=false TIME=1416298944000 FINGERPRINT=samsung/wilcoxdszn/wilcoxds:4.2.2/JDQ39/G3812ZNUANK1:user/release-keys UNKNOWN=unknown BOARD=PXA1088 PRODUCT=wilcoxdszn versionName=1.0 DISPLAY=JDQ39.G3812ZNUANK1 USER=se.infra DEVICE=wilcoxds MODEL=SM-G3812 BOOTLOADER=unknown CPU_ABI=armeabi-v7a CPU_ABI2=armeabi IS_SYSTEM_SECURE=false IS_DEBUGGABLE=false SERIAL=5202889565301100 BRAND=samsung java.lang.IllegalStateException: Could not execute method of the activityat android.view.View$1.onClick(View.java:3804)at android.view.View.performClick(View.java:4439)at android.widget.Button.performClick(Button.java:142)at android.view.View$PerformClick.run(View.java:18395)at android.os.Handler.handleCallback(Handler.java:725)at android.os.Handler.dispatchMessage(Handler.java:92)at android.os.Looper.loop(Looper.java:176)at android.app.ActivityThread.main(ActivityThread.java:5319)at java.lang.reflect.Method.invokeNative(Native Method)at java.lang.reflect.Method.invoke(Method.java:511)at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.reflect.InvocationTargetExceptionat java.lang.reflect.Method.invokeNative(Native Method)at java.lang.reflect.Method.invoke(Method.java:511)at android.view.View$1.onClick(View.java:3799)... 12 more Caused by: java.lang.ArithmeticException: divide by zeroat cn.org.octpus.crash.MainActivity.onClick(MainActivity.java:20)... 15 more java.lang.reflect.InvocationTargetExceptionat java.lang.reflect.Method.invokeNative(Native Method)at java.lang.reflect.Method.invoke(Method.java:511)at android.view.View$1.onClick(View.java:3799)at android.view.View.performClick(View.java:4439)at android.widget.Button.performClick(Button.java:142)at android.view.View$PerformClick.run(View.java:18395)at android.os.Handler.handleCallback(Handler.java:725)at android.os.Handler.dispatchMessage(Handler.java:92)at android.os.Looper.loop(Looper.java:176)at android.app.ActivityThread.main(ActivityThread.java:5319)at java.lang.reflect.Method.invokeNative(Native Method)at java.lang.reflect.Method.invoke(Method.java:511)at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.ArithmeticException: divide by zeroat cn.org.octpus.crash.MainActivity.onClick(MainActivity.java:20)... 15 more java.lang.ArithmeticException: divide by zeroat cn.org.octpus.crash.MainActivity.onClick(MainActivity.java:20)at java.lang.reflect.Method.invokeNative(Native Method)at java.lang.reflect.Method.invoke(Method.java:511)at android.view.View$1.onClick(View.java:3799)at android.view.View.performClick(View.java:4439)at android.widget.Button.performClick(Button.java:142)at android.view.View$PerformClick.run(View.java:18395)at android.os.Handler.handleCallback(Handler.java:725)at android.os.Handler.dispatchMessage(Handler.java:92)at android.os.Looper.loop(Looper.java:176)at android.app.ActivityThread.main(ActivityThread.java:5319)at java.lang.reflect.Method.invokeNative(Native Method)at java.lang.reflect.Method.invoke(Method.java:511)at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)at dalvik.system.NativeStart.main(Native Method)
二. 崩潰日志保存到遠(yuǎn)程服務(wù)器
實(shí)現(xiàn)途徑 :?
-- 1. 自己開發(fā)服務(wù)器端 : 在上面的保存文件的基礎(chǔ)上, 在開發(fā)一個(gè)服務(wù)器端, 使用網(wǎng)絡(luò)編程接口將打印到文件的內(nèi)容上傳到服務(wù)器端;
-- 2. 使用第三方服務(wù) : 使用 Testin 的崩潰大師, 地址?http://crash.testin.cn/app?scnavbar ;
1. 集成崩潰大師步驟
(1) 創(chuàng)建應(yīng)用 獲取 key 值
創(chuàng)建應(yīng)用步驟 :?
-- 1. 創(chuàng)建界面 :?http://crash.testin.cn/apm/task/create ;
-- 2. 填寫一個(gè)應(yīng)用信息 :?
-- 3. 獲取 key : 點(diǎn)擊"提交并獲取 Appkey" 按鈕, 獲取到了 AppKey "0da6263ca1f5b84a2dd405b07227f483";
(2) 設(shè)置類型
第二步設(shè)置類型, 選擇默認(rèn)的應(yīng)用即可 :?
(3) 下載 jar 包
jar 包簡介 : 集成崩潰大師, 只需要集成一個(gè) jar 包即可, 點(diǎn)擊如下按鈕即可下載 該 jar 包;
-- jar 包內(nèi)容 : 下載后解壓, jar 包名稱是?testinagent.jar ;
(4) 導(dǎo)入 SDK?
導(dǎo)入 SDK : 在應(yīng)用下 創(chuàng)建一個(gè) libs 目錄, 將jar 包拷貝進(jìn)去即可;
(5) 配置 AndroidManifest.xml 文件?
在配置文件中添加如下用戶權(quán)限即可 :?
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.READ_LOGS" /><uses-permission android:name="android.permission.GET_TASKS" />
(6) 初始化設(shè)置
在代碼中注冊(cè) :?
//初始化 Testin 崩潰大師TestinAgent.init(getApplicationContext(), "0da6263ca1f5b84a2dd405b07227f483", "octopus");
2. 測試示例
(1) 日志信息
測試成功會(huì)打印如下信息 :?
04-27 20:11:40.890: E/TestinAgent(16432): **************************************** 04-27 20:11:40.890: E/TestinAgent(16432): A Java crash caught by TestinAgent, pkg=cn.org.octpus.crash 04-27 20:11:40.890: E/TestinAgent(16432): ---------------------------------------- 04-27 20:11:40.890: E/TestinAgent(16432): reason: java.lang.IllegalStateException: Could not execute method of the activity 04-27 20:11:40.890: E/TestinAgent(16432): ---------------------------------------- 04-27 20:11:40.890: E/TestinAgent(16432): stacktrace: 04-27 20:11:40.890: E/TestinAgent(16432): at android.view.View$1.onClick(View.java:3804) 04-27 20:11:40.890: E/TestinAgent(16432): at android.view.View.performClick(View.java:4439) 04-27 20:11:40.890: E/TestinAgent(16432): at android.widget.Button.performClick(Button.java:142) 04-27 20:11:40.890: E/TestinAgent(16432): at android.view.View$PerformClick.run(View.java:18395) 04-27 20:11:40.890: E/TestinAgent(16432): at android.os.Handler.handleCallback(Handler.java:725) 04-27 20:11:40.890: E/TestinAgent(16432): at android.os.Handler.dispatchMessage(Handler.java:92) 04-27 20:11:40.890: E/TestinAgent(16432): at android.os.Looper.loop(Looper.java:176) 04-27 20:11:40.890: E/TestinAgent(16432): at android.app.ActivityThread.main(ActivityThread.java:5319) 04-27 20:11:40.890: E/TestinAgent(16432): at java.lang.reflect.Method.invokeNative(Native Method) 04-27 20:11:40.890: E/TestinAgent(16432): at java.lang.reflect.Method.invoke(Method.java:511) 04-27 20:11:40.890: E/TestinAgent(16432): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102) 04-27 20:11:40.890: E/TestinAgent(16432): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869) 04-27 20:11:40.890: E/TestinAgent(16432): at dalvik.system.NativeStart.main(Native Method) 04-27 20:11:40.890: E/TestinAgent(16432): Caused by: java.lang.reflect.InvocationTargetException 04-27 20:11:40.890: E/TestinAgent(16432): at java.lang.reflect.Method.invokeNative(Native Method) 04-27 20:11:40.890: E/TestinAgent(16432): at java.lang.reflect.Method.invoke(Method.java:511) 04-27 20:11:40.890: E/TestinAgent(16432): at android.view.View$1.onClick(View.java:3799) 04-27 20:11:40.890: E/TestinAgent(16432): ... 12 more 04-27 20:11:40.890: E/TestinAgent(16432): Caused by: java.lang.ArithmeticException: divide by zero 04-27 20:11:40.890: E/TestinAgent(16432): at cn.org.octpus.crash.MainActivity.onClick(MainActivity.java:20) 04-27 20:11:40.890: E/TestinAgent(16432): ... 15 more 04-27 20:11:40.890: E/TestinAgent(16432): ---------------------------------------- 04-27 20:11:40.890: E/TestinAgent(16432): deviceinfo: 04-27 20:11:40.890: E/TestinAgent(16432): Device: samsung/SM-G3812 04-27 20:11:40.890: E/TestinAgent(16432): OS: 4.2.2 04-27 20:11:40.890: E/TestinAgent(16432): AppVersion: 1.0 04-27 20:11:40.890: E/TestinAgent(16432): PackageName: cn.org.octpus.crash 04-27 20:11:40.890: E/TestinAgent(16432): Activity: MainActivity 04-27 20:11:40.890: E/TestinAgent(16432): Total Disk Space: 2328 MB ; Free Disk Space: 1688 MB 04-27 20:11:40.890: E/TestinAgent(16432): Total SD Space: 2308 MB ; Free SD Space: 1668 MB 04-27 20:11:40.890: E/TestinAgent(16432): CPU Usage: 17.742 % 04-27 20:11:40.890: E/TestinAgent(16432): Memory Usage: 12 MB 04-27 20:11:40.890: E/TestinAgent(16432): Userinfo: 04-27 20:11:40.890: E/TestinAgent(16432): ****************************************
(2) 后臺(tái)信息
后臺(tái)崩潰數(shù)據(jù) :?
-- 控制臺(tái)信息 : 進(jìn)入崩潰大師的控制臺(tái), 就會(huì)看到剛看到的 CrashInfoDemo 應(yīng)用, 此時(shí)我們估計(jì)產(chǎn)生的異常已經(jīng)打印出來了;
-- 點(diǎn)擊進(jìn)入該應(yīng)用的詳情 :?
-- 詳細(xì)的崩潰信息查看 :?
總結(jié)
以上是生活随笔為你收集整理的【Android应用开发】 Android 崩溃日志 本地存储 与 远程保存的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【流媒体开发】VLC Media Pla
- 下一篇: 【OpenGL ES】 Android