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

服務(wù)器之家:專(zhuān)注于服務(wù)器技術(shù)及軟件下載分享
分類(lèi)導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Android - Android 捕獲錯(cuò)誤日志的方法

Android 捕獲錯(cuò)誤日志的方法

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

這篇文章主要介紹了Android 捕獲錯(cuò)誤日志的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

前提

今天在群里聊天的時(shí)候有群友問(wèn)如何捕獲錯(cuò)誤日志,我說(shuō)可以自己寫(xiě),也可以用第三方的比如騰訊的bugly,友盟的錯(cuò)誤統(tǒng)計(jì)等等,但是那些是別人的東西,作為一個(gè)程序員當(dāng)然是要知其然,并且要知其所以然。因此今天就在此寫(xiě)一下關(guān)于捕獲錯(cuò)誤日志的文章,希望可以給新手指導(dǎo),大佬請(qǐng)繞行。

首先

要捕獲錯(cuò)誤日志當(dāng)然是調(diào)用系統(tǒng)的了,這樣最方便,也是大家常用的了,廢話不多說(shuō),直接上圖,no pic say a xx.

Android 捕獲錯(cuò)誤日志的方法

錯(cuò)誤日志.png

其次

上面的圖是日志信息,下面來(lái)看看代碼如何編寫(xiě)。

捕獲錯(cuò)誤日志信息類(lèi)

?
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();
 
// 系統(tǒng)默認(rèn)的異常處理(默認(rèn)情況下,系統(tǒng)會(huì)終止當(dāng)前的異常程序)
private UncaughtExceptionHandler mDefaultCrashHandler;
 
private Context mContext;
//log路徑
private String mLogPath=null;
 
// 構(gòu)造方法私有,防止外部構(gòu)造多個(gè)實(shí)例,即采用單例模式
private CrashHandler() {
}
 
public static CrashHandler getInstance() {
 return sInstance;
}
 
// 這里主要完成初始化工作
public void init(Context context,String logPath) {
 // 獲取系統(tǒng)默認(rèn)的異常處理器
 mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
 // 將當(dāng)前實(shí)例設(shè)為系統(tǒng)默認(rèn)的異常處理器
 Thread.setDefaultUncaughtExceptionHandler(this);
 // 獲取Context,方便內(nèi)部使用
 mContext = context.getApplicationContext();
 this.mLogPath=logPath;
}
 
/**
 * 這個(gè)是最關(guān)鍵的函數(shù),當(dāng)程序中有未被捕獲的異常,系統(tǒng)將會(huì)自動(dòng)調(diào)用#uncaughtException方法
 * thread為出現(xiàn)未捕獲異常的線程,ex為未捕獲的異常,有了這個(gè)ex,我們就可以得到異常信息。
 */
@Override
public void uncaughtException(Thread thread, Throwable ex) {
 try {
  // 導(dǎo)出異常信息到SD卡中
  dumpExceptionToSDCard(ex);
  // 這里可以通過(guò)網(wǎng)絡(luò)上傳異常信息到服務(wù)器,便于開(kāi)發(fā)人員分析日志從而解決bug
  uploadExceptionToServer();
 } catch (IOException e) {
  e.printStackTrace();
 }
 
 // 打印出當(dāng)前調(diào)用棧信息
 ex.printStackTrace();
 
 // 如果系統(tǒng)提供了默認(rèn)的異常處理器,則交給系統(tǒng)去結(jié)束我們的程序,否則就由我們自己結(jié)束自己
 if (mDefaultCrashHandler != null) {
  mDefaultCrashHandler.uncaughtException(thread, ex);
 } else {
  Process.killProcess(Process.myPid());
 }
 
}
 
/**
 * 寫(xiě)入SD卡
 *
 * @param ex
 * @throws IOException
 */
@SuppressLint("SimpleDateFormat")
private void dumpExceptionToSDCard(Throwable ex) throws IOException {
 // 如果SD卡不存在或無(wú)法使用,則無(wú)法把異常信息寫(xiě)入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));
 // 以當(dāng)前時(shí)間創(chuàng)建log文件
 File file = new File(mLogPath + FILE_NAME + time
   + FILE_NAME_SUFFIX);
 
 try {
  PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(
    file)));
  // 導(dǎo)出發(fā)生異常的時(shí)間
  pw.println(time);
 
  // 導(dǎo)出手機(jī)信息
  dumpPhoneInfo(pw);
 
  pw.println();
  // 導(dǎo)出異常的調(diào)用棧信息
  ex.printStackTrace(pw);
 
  pw.close();
 } catch (Exception e) {
  Log.e(TAG, "dump crash info failed");
 }
}
 
private void dumpPhoneInfo(PrintWriter pw) throws NameNotFoundException {
 // 應(yīng)用的版本名稱(chēng)和版本號(hào)
 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版本號(hào)
 pw.print("OS Version: ");
 pw.print(Build.VERSION.RELEASE);
 pw.print("_");
 pw.println(Build.VERSION.SDK_INT);
 
 // 手機(jī)制造商
 pw.print("Vendor: ");
 pw.println(Build.MANUFACTURER);
 
 // 手機(jī)型號(hào)
 pw.print("Model: ");
 pw.println(Build.MODEL);
 
 // cpu架構(gòu)
 pw.print("CPU ABI: ");
 pw.println(Build.CPU_ABI);
}
 
/**
 * 上傳到服務(wù)器(這里需要實(shí)現(xiàn))
 */
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以下版本(系統(tǒng)自動(dòng)申請(qǐng)) 不會(huì)彈框
 * 有些廠商修改了6.0系統(tǒng)申請(qǐng)機(jī)制,他們修改成系統(tǒng)自動(dòng)申請(qǐng)權(quán)限了
 */
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,"存儲(chǔ)空間",R.drawable.permission_ic_storage))
 HiPermission.create(this)
   .title("親愛(ài)的上帝")
   .msg("為了能夠正常使用,請(qǐng)開(kāi)啟這些權(quán)限吧!")
   .permissions(permissionItems)
   .style(R.style.PermissionDefaultBlueStyle)
   .animStyle(R.style.PermissionAnimScale)
   .checkMutiPermission(object : PermissionCallback {
    override fun onClose() {
     Toast.makeText(this@MainActivity,"用戶(hù)關(guān)閉了權(quán)限",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 捕獲錯(cuò)誤日志的方法

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,"出現(xiàn)異常了",Toast.LENGTH_LONG).show();
    throw new RuntimeException(toUtf8("出現(xiàn)異常了"));
  }
 });
}
 
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 捕獲錯(cuò)誤日志的方法

CrashActivity.png

最后

這里需要注意的是,在MainActivity中用的是Kotlin寫(xiě)的權(quán)限控制,也就是運(yùn)行時(shí)權(quán)限

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

要保存日志當(dāng)然需要SD卡的讀寫(xiě)權(quán)限。

項(xiàng)目地址:https://gitee.com/1032200695/CrashException

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 娇妻终于接受了3p的调教 | 91在线高清视频 | 日本动漫打扑克动画片樱花动漫 | 色中色破解版 | 欧美精品一区二区三区免费 | 催奶师小说| 波多野结衣中文字幕在线 | 日韩色综合 | 成人伊在线影院 | 日本加勒比一区 | 亚洲日本中文字幕天天更新 | 国产趴着打光屁股sp抽打 | 麻豆网站视频国产在线观看 | 操破苍穹小说 | ass性强迫rape| 青草草视频在线观看 | 亚洲国产福利精品一区二区 | 欧美一区二区三区四区在线观看 | 亚洲乱码一二三四区国产 | 范冰冰性xxxxhd| 色777777女人色 | 男人与雌性宠物交啪啪小说 | 高清视频一区二区三区 | 波多野结衣作品在线观看 | videodesexo中国妞 | 久久re视频精品538在线 | 免费午夜剧场 | 国产亚洲一欧美一区二区三区 | 免费久久久久 | 欧美视频一区二区专区 | 久久精品亚洲牛牛影视 | 久久久久影视 | 婷婷影院在线观看 | 大肥臀风间由美 中文字幕 大东北chinesexxxx露脸 | 欧美同性猛男videos | 日本免费不卡在线一区二区三区 | 白丝出水 | 亚洲视频日韩 | 169pp美女| 色香婷婷 | 99视频有精品视频免费观看 |