本文实例讲述了Android编程实现项目中异常捕获及对应Log日志文件保存功能。分享给大家供大家参考,具体如下:
做程序开发,肯定离不开与BUG打交道,更加离不开程序异常的出现。在开发的时候,我们可以通断点调试,日志打印,异常捕获工具等方式发现或处理程序中的Exception。那客户在使用我们的应用时,程序了问题,我们怎么可以知道呢?当然,我们可以加上友盟统计等第三方工具。另外还能怎么做呢?那就是把异常信息通过文档地形式保存下来,如果用户在使用的时候程序出了异常,可以让用户把对应的日志信息发给我们或客服人员,更好的是在程序中做好处理,把日志发到指定服务器(程序中记得添加网络权限哦)中,我们也可以拿到日志,我们就能发现问题,处理问题啦。
异常捕获的关键代码:
/**
* UncaughtExceptionHandler:线程未捕获异常控制器是用来处理未捕获异常的。 实现该接口并注册为程序中的默认未捕获异常处理
* 这样当未捕获异常发生时,就可以做些异常处理操作 例如:收集异常信息,发送错误报告 等。
*
* @description:
* @author ldm
* @date 2016-4-18 上午11:31:19
*/
public class MyExceptionHandler implements UncaughtExceptionHandler {
// 上下文
private Context mContext;
// 是否打开上传
public boolean openUpload = true;
// Log文件路径
private static final String LOG_FILE_DIR = "log";
// log文件的后缀名
private static final String FILE_NAME = ".log";
private static MyExceptionHandler instance = null;
// 系统默认的异常处理(默认情况下,系统会终止当前的异常程序)
private UncaughtExceptionHandler mDefaultCrashHandler;
private MyExceptionHandler(Context cxt) {
// 获取系统默认的异常处理器
mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
// 将当前实例设为系统默认的异常处理器
Thread.setDefaultUncaughtExceptionHandler(this);
// 获取Context,方便内部使用
this.mContext = cxt.getApplicationContext();
}
public synchronized static MyExceptionHandler create(Context cxt) {
if (instance == null) {
instance = new MyExceptionHandler(cxt);
}
return instance;
}
/**
* 当程序中有未被捕获的异常,系统将会自动调用#uncaughtException方法
* thread为出现未捕获异常的线程,ex为未捕获的异常,有了这个ex,我们就可以得到异常信息。
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
try {
// 保存导出异常日志信息到SD卡中
saveToSDCard(ex);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 如果系统提供了默认的异常处理器,则交给系统去结束我们的程序,否则就由我们自己结束自己
Toast.makeText(mContext,
"很抱歉,程序出错,即将退出:\r\n" + ex.getLocalizedMessage(),
Toast.LENGTH_LONG).show();
if (mDefaultCrashHandler != null) {
mDefaultCrashHandler.uncaughtException(thread, ex);
} else {
ex.printStackTrace();
}
}
}
/**
* 保存文件到SD卡
*
* @description:
* @author ldm
* @date 2016-4-18 上午11:37:17
*/
private void saveToSDCard(Throwable ex) throws Exception {
File file = FileUtil.getAppointFile(mContext.getPackageName()
+ File.separator + LOG_FILE_DIR,
getDataTime("yyyy-MM-dd-HH-mm-ss") + FILE_NAME);
PrintWriter pw = new PrintWriter(new BufferedWriter(
new FileWriter(file)));
// 导出发生异常的时间
pw.println(getDataTime("yyyy-MM-dd-HH-mm-ss"));
// 导出手机信息
savePhoneInfo(pw);
pw.println();
// 导出异常的调用栈信息
ex.printStackTrace(pw);
pw.close();
}
/**
* 保存手机硬件信息
*
* @description:
* @author ldm
* @date 2016-4-18 上午11:38:01
*/
private void savePhoneInfo(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);
pw.println();
// android版本号
pw.print("OS Version: ");
pw.print(Build.VERSION.RELEASE);
pw.print("_");
pw.println(Build.VERSION.SDK_INT);
pw.println();
// 手机制造商
pw.print("Manufacturer: ");
pw.println(Build.MANUFACTURER);
pw.println();
// 手机型号
pw.print("Model: ");
pw.println(Build.MODEL);
pw.println();
}
/**
* 根据时间格式返回时间
*
* @description:
* @author ldm
* @date 2016-4-18 上午11:39:30
*/
private String getDataTime(String format) {
SimpleDateFormat df = new SimpleDateFormat(format);
return df.format(new Date());
}
}
使用的时候,我们需要在Application中初始化:
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
MyExceptionHandler.create(this);
}
}
在AndroidManifest.xml文件中注册好Application:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ldm.exception"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name="com.ldm.exception.MyApplication"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.ldm.activity.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
注:更多关于Android Manifest权限控制文件的说明可点击此处查看Android权限操作说明
文件上传的方法有写好,但是没有具体实现,比如一但有日志文件就上传或是日志文件达到一定大小再上传,这就要根据实际情况来定啦。
当我们应用出现异常时,在手机文件夹中存在我们应用包名的文件夹,里面就有日志文件。
附:完整Demo点击此处本站下载。
更多关于Android相关内容感兴趣的读者可查看本站专题:《Android调试技巧与常见问题解决方法汇总》、《Android开发入门与进阶教程》、《Android基本组件用法总结》、《Android视图View技巧总结》、《Android布局layout技巧总结》及《Android控件用法总结》
希望本文所述对大家Android程序设计有所帮助。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。