一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Android - Android 捕獲錯誤日志的方法

Android 捕獲錯誤日志的方法

2022-03-07 14:49Silence瀟湘夜雨 Android

這篇文章主要介紹了Android 捕獲錯誤日志的方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

前提

今天在群里聊天的時候有群友問如何捕獲錯誤日志,我說可以自己寫,也可以用第三方的比如騰訊的bugly,友盟的錯誤統計等等,但是那些是別人的東西,作為一個程序員當然是要知其然,并且要知其所以然。因此今天就在此寫一下關于捕獲錯誤日志的文章,希望可以給新手指導,大佬請繞行。

首先

要捕獲錯誤日志當然是調用系統的了,這樣最方便,也是大家常用的了,廢話不多說,直接上圖,no pic say a xx.

Android 捕獲錯誤日志的方法

錯誤日志.png

其次

上面的圖是日志信息,下面來看看代碼如何編寫。

捕獲錯誤日志信息類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
public class CrashHandler implements UncaughtExceptionHandler {
 
 private static final String TAG = "CrashHandler";
 private static final boolean DEBUG = true;
 
 private static final String FILE_NAME = "crash";
 
// log文件的后綴名
private static final String FILE_NAME_SUFFIX = ".txt";
 
private static CrashHandler sInstance = new CrashHandler();
 
// 系統默認的異常處理(默認情況下,系統會終止當前的異常程序)
private UncaughtExceptionHandler mDefaultCrashHandler;
 
private Context mContext;
//log路徑
private String mLogPath=null;
 
// 構造方法私有,防止外部構造多個實例,即采用單例模式
private CrashHandler() {
}
 
public static CrashHandler getInstance() {
 return sInstance;
}
 
// 這里主要完成初始化工作
public void init(Context context,String logPath) {
 // 獲取系統默認的異常處理器
 mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
 // 將當前實例設為系統默認的異常處理器
 Thread.setDefaultUncaughtExceptionHandler(this);
 // 獲取Context,方便內部使用
 mContext = context.getApplicationContext();
 this.mLogPath=logPath;
}
 
/**
 * 這個是最關鍵的函數,當程序中有未被捕獲的異常,系統將會自動調用#uncaughtException方法
 * thread為出現未捕獲異常的線程,ex為未捕獲的異常,有了這個ex,我們就可以得到異常信息。
 */
@Override
public void uncaughtException(Thread thread, Throwable ex) {
 try {
  // 導出異常信息到SD卡中
  dumpExceptionToSDCard(ex);
  // 這里可以通過網絡上傳異常信息到服務器,便于開發人員分析日志從而解決bug
  uploadExceptionToServer();
 } catch (IOException e) {
  e.printStackTrace();
 }
 
 // 打印出當前調用棧信息
 ex.printStackTrace();
 
 // 如果系統提供了默認的異常處理器,則交給系統去結束我們的程序,否則就由我們自己結束自己
 if (mDefaultCrashHandler != null) {
  mDefaultCrashHandler.uncaughtException(thread, ex);
 } else {
  Process.killProcess(Process.myPid());
 }
 
}
 
/**
 * 寫入SD卡
 *
 * @param ex
 * @throws IOException
 */
@SuppressLint("SimpleDateFormat")
private void dumpExceptionToSDCard(Throwable ex) throws IOException {
 // 如果SD卡不存在或無法使用,則無法把異常信息寫入SD卡
 if (!Environment.getExternalStorageState().equals(
   Environment.MEDIA_MOUNTED)) {
  if (DEBUG) {
   Log.e(TAG, "sdcard unmounted,skip dump exception");
   return;
  }
 }
 
 File dir = new File(mLogPath);
 if (!dir.exists()) {
  dir.mkdirs();
 }
 long current = System.currentTimeMillis();
 String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
   .format(new Date(current));
 // 以當前時間創建log文件
 File file = new File(mLogPath + FILE_NAME + time
   + FILE_NAME_SUFFIX);
 
 try {
  PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(
    file)));
  // 導出發生異常的時間
  pw.println(time);
 
  // 導出手機信息
  dumpPhoneInfo(pw);
 
  pw.println();
  // 導出異常的調用棧信息
  ex.printStackTrace(pw);
 
  pw.close();
 } catch (Exception e) {
  Log.e(TAG, "dump crash info failed");
 }
}
 
private void dumpPhoneInfo(PrintWriter pw) throws NameNotFoundException {
 // 應用的版本名稱和版本號
 PackageManager pm = mContext.getPackageManager();
 PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(),
   PackageManager.GET_ACTIVITIES);
 pw.print("App Version: ");
 pw.print(pi.versionName);
 pw.print('_');
 pw.println(pi.versionCode);
 
 // android版本號
 pw.print("OS Version: ");
 pw.print(Build.VERSION.RELEASE);
 pw.print("_");
 pw.println(Build.VERSION.SDK_INT);
 
 // 手機制造商
 pw.print("Vendor: ");
 pw.println(Build.MANUFACTURER);
 
 // 手機型號
 pw.print("Model: ");
 pw.println(Build.MODEL);
 
 // cpu架構
 pw.print("CPU ABI: ");
 pw.println(Build.CPU_ABI);
}
 
/**
 * 上傳到服務器(這里需要實現)
 */
private void uploadExceptionToServer() {
}
 
}

APP(自定義的Application)

?
1
2
3
4
5
6
7
8
9
10
11
12
public class APP extends Application {
 //log路徑
 private static final String LOG_PATH= Environment
  .getExternalStorageDirectory().getPath() + File.separator + "Live" + File.separator
  + "log" + File.separator;
 
 @Override
public void onCreate() {
 super.onCreate();
 CrashHandler.getInstance().init(this,LOG_PATH);
}
}

MainActivity

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
class MainActivity : AppCompatActivity(){
 
var mBtnSecond:Button?=null;
 
override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 checkPermission()
 initView()
}
 
 
fun initView(){
 mBtnSecond=findViewById(R.id.btn_second)
 mBtnSecond?.setOnClickListener{
  var intent= Intent(this,SecondActivity::class.java)
  startActivity(intent)
 }
}
 
/**
 * 6.0以下版本(系統自動申請) 不會彈框
 * 有些廠商修改了6.0系統申請機制,他們修改成系統自動申請權限了
 */
private fun checkPermission(){
 val permissionItems = ArrayList<PermissionItem>()
 permissionItems.add(PermissionItem(Manifest.permission.READ_EXTERNAL_STORAGE, "讀取空間", R.drawable.permission_ic_phone))
 permissionItems.add(PermissionItem(Manifest.permission.WRITE_EXTERNAL_STORAGE,"存儲空間",R.drawable.permission_ic_storage))
 HiPermission.create(this)
   .title("親愛的上帝")
   .msg("為了能夠正常使用,請開啟這些權限吧!")
   .permissions(permissionItems)
   .style(R.style.PermissionDefaultBlueStyle)
   .animStyle(R.style.PermissionAnimScale)
   .checkMutiPermission(object : PermissionCallback {
    override fun onClose() {
     Toast.makeText(this@MainActivity,"用戶關閉了權限",Toast.LENGTH_LONG).show();
    }
 
    override fun onFinish() {
     Toast.makeText(this@MainActivity,"初始化完畢!",Toast.LENGTH_LONG).show();
    }
 
    override fun onDeny(permission: String, position: Int) {
    }
 
    override fun onGuarantee(permission: String, position: Int) {
    }
   })
}
 
 }

Android 捕獲錯誤日志的方法

MainActivity.png

CrashActivity

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class CrashActivity extends AppCompatActivity {
 
Button mBtnCrash;
 
@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_second);
 mBtnCrash=findViewById(R.id.btn_crash);
 mBtnCrash.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View v) {
   Toast.makeText(CrashActivity.this,"出現異常了",Toast.LENGTH_LONG).show();
    throw new RuntimeException(toUtf8("出現異常了"));
  }
 });
}
 
public static String toUtf8(String str) {
 String result = null;
 try {
  result = new String(str.getBytes("UTF-8"), "UTF-8");
 } catch (UnsupportedEncodingException e) {
  e.printStackTrace();
 }
 return result;
}
}

Android 捕獲錯誤日志的方法

CrashActivity.png

最后

這里需要注意的是,在MainActivity中用的是Kotlin寫的權限控制,也就是運行時權限

implementation 'me.weyye.hipermission:library:1.0.7'

要保存日志當然需要SD卡的讀寫權限。

項目地址:https://gitee.com/1032200695/CrashException

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://www.jianshu.com/p/d231e62e4e6c

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: a级免费观看| 性肥胖BWBWBW| 日韩精品一区二三区中文 | 四虎1515hh.com| 欧美brazzers| 成人18视频在线观看 | 久久er国产精品免费观看2 | 久久亚洲免费视频 | 国产网站免费观看 | 亚洲国产精品无圣光一区二区 | 国产精品久久香蕉免费播放 | 国产日韩欧美在线一二三四 | 99视频一区 | 高清在线观看免费入口 | 日本成人免费在线视频 | 超级碰在线视频 | 17岁俄罗斯csgo| 国产精品酒店视频免费看 | 久久黄色免费 | 久久日韩精品无码一区 | 国产精品亚洲w码日韩中文 国产精品香蕉在线观看不卡 | 能免费观看的韩剧 | 日韩国产成人资源精品视频 | 被黑人日 | 欧美肥胖老妇做爰变态 | 果冻传媒天美传媒网址入口 | 99久久香蕉国产综合影院 | 91热国内精品永久免费观看 | 国产在线精品成人一区二区三区 | 99任你躁精品视频 | bbox撕裂bass孕妇 | 青青青在线视频播放 | 成人免费视频播放 | 日韩日b视频 | 小仙夜晚慰自催眠mp3护士篇 | 亚洲娇小videos | 调教全程肉动画片在线观看 | 猛操女人 | a级毛片毛片免费观看永久 a级黄色片免费 | pregnantxxx孕交 | 无人区在线观看免费国语完整版 |