Android 之 LogDog

在写Android程序时,经常碰到在模拟器和调试器中无法捕捉的exception。有时自己运行好好的程序到了其他机器上就出现了问题。虽然Google Play有错误堆栈上传功能,但是没有办法把整个运行的过程记录下来。为此我写了一个LogDog类来试图解决这个问题。

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.HashSet;

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.util.Log;

public class LogDog implements UncaughtExceptionHandler {

	public static String 			TAG = "LogDog";

	private static HashSet	_tags = new HashSet();
	private static boolean			_debug = false;

	static {
		// add tags to be captured
		_tags.add(PDFMaster.TAG);
		_tags.add(RecentlyUsedActivity.TAG);
		_tags.add(DB.TAG);
	}

	public static LogDog instance() {
		return _instance;
	}

	public static void i(String tag, String message) {
		if(_debug) {
			Log.i(tag, message);
			return;
		}
		PrintWriter writer = _instance.getWriter();
		if(writer != null && _tags.contains(tag)) {
			_instance._writer.println("i:" + tag + ":" + message);
		}
	}

	public static void e(String tag, String message) {
		if(_debug) {
			Log.i(tag, message);
			return;
		}
		PrintWriter writer = _instance.getWriter();
		if(writer != null && _tags.contains(tag)) {
			_instance._writer.println("e" + tag + ":" + message);
		}
	}

	public static void w(String tag, String message) {
		if(_debug) {
			Log.i(tag, message);
			return;
		}
		PrintWriter writer = _instance.getWriter();
		if(writer != null && _tags.contains(tag)) {
			_instance._writer.println("w" + tag + ":" + message);
		}
	}

	public void init(Context context) {
		_context = context;
		_fileName = _context.getString(R.string.app_name) + ".log";
		_defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
		Thread.setDefaultUncaughtExceptionHandler(this);
	}

	public void close() {
		if(_writer != null) {
			_writer.close();
			_writer = null;
		}
	}

	// private

	private static LogDog					_instance = new LogDog();
	private static final String 			PATH =
		Environment.getExternalStorageDirectory().getPath() + "/log";
	private Context							_context;
	private String							_fileName;
	private Thread.UncaughtExceptionHandler	_defaultHandler;
	private PrintWriter						_writer = null;

	private LogDog() {
	}

	private PrintWriter getWriter() {
		if(_writer != null)
			return _writer;
		// check if we have SD card
		if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
			//Log.w(TAG, "sdcard unmounted,skip dump exception");
			return null;
		}
		File dir = new File(PATH);
		if (!dir.exists()) {
			dir.mkdirs();
		}
		File file = new File(PATH + "/" + _fileName);
		try {
			_writer = new PrintWriter(new BufferedWriter(new FileWriter(file)));
		} catch (IOException e) {
			//Log.e(TAG, "Failed to open " + PATH + "/" + FILE_NAME);
			_writer = null;
		}
		return _writer;
	}

	@Override
	public void uncaughtException(Thread thread, Throwable ex) {
		// first display a toast message
		new Thread() {
			@Override
			public void run() {
				Looper.prepare();
				PDFMarkerApp.instance().showToast("Sorry for the trouble, dumping uncaught exeption to SD card");
			}
		}.start();
		try {
			dump(ex);
		} catch (Exception e) {
			//Log.e(TAG, "Failed to dump because " + e.getMessage());
			e.printStackTrace();
		}
		if (_defaultHandler != null) {
			_defaultHandler.uncaughtException(thread, ex);
		} else {
			// sleep so the toast can have time to display
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
			}
			android.os.Process.killProcess(android.os.Process.myPid());
		}
	}

	private void dump(Throwable ex) throws IOException, NameNotFoundException {
		PrintWriter writer = _instance.getWriter();
		if(writer == null)
			return;
		long current = System.currentTimeMillis();
		String time = new SimpleDateFormat("yyyyMMdd.HHmmss").format(new Date(current));
		_writer.println(time);
		PackageManager pm = _context.getPackageManager();
		PackageInfo pi = pm.getPackageInfo(_context.getPackageName(), PackageManager.GET_ACTIVITIES);
		_writer.print("App Version: ");
		_writer.print(pi.versionName);
		_writer.print(‘_‘);
		_writer.println(pi.versionCode);
		_writer.print("OS Version: ");
		_writer.print(Build.VERSION.RELEASE);
		_writer.print("_");
		_writer.println(Build.VERSION.SDK_INT);
		_writer.print("Vendor: ");
		_writer.println(Build.MANUFACTURER);
		_writer.print("Model: ");
		_writer.println(Build.MODEL);
		_writer.print("CPU ABI: ");
		_writer.println(Build.CPU_ABI);
		_writer.println();
		ex.printStackTrace(_writer);
		close();
		File file = new File(PATH + "/" + _fileName);
		File file2 = new File(PATH + "/" + _fileName + "." + time + ".txt");
		file.renameTo(file2);
	}

}

在使用时所有的日志就全记录在一个文件中,直到最后的异常。每次异常都会单独被记录在一个文件中,连带所有需要知道的信息。要是正常运行,这个文件下次就被覆盖,不会造成空间问题。要是调试,只要把_debug改一下,所有日志就在LogCat中显示出来,非常方便。

时间: 2024-10-11 08:05:01

Android 之 LogDog的相关文章

android开发之onCreate( )方法详解

onCreate( )方法是android应用程序中最常见的方法之一,那么,我们在使用onCreate()方法的时候应该注意哪些问题呢? 先看看Google Android Developers官网上的解释: onCreate(Bundle) is where you initialize your activity. Most importantly, here you will usually call setContentView(int) with a layout resource d

如何用 Android Studio 导入开源项目以及常见错误的解决办法

声明:这篇文章完全来自这篇文章,感谢大神的相助.这篇文章纯粹是为了备份. 本篇以Github上最热门的MaterialDesign库,MaterialDesignLibrary来介绍怎样使用Android Sudio导入开源项目的,如果你和我一样刚刚从Eclipse转到AS,那本篇文章非常适合你. 如果不引入任何第三方库,不做自动化分渠道打包等操作,那可以在完全不了解Gradle的情况下进行Android项目的开发.但如果要想导入Github上的热门项目,必须首先熟悉Gradle. 1. Gra

Android——调用高德地图API前期准备

1.登陆高德开放平台注册账号http://lbs.amap.com/ 2.创建自己的应用并且添加新key 获取发布版安全码获取方法: 在AndroidStudio的Terminal中编译: 输入如下图: 开发版安全码获取: 开发版获取的另一种方法:(和获取发布版本一样在AndroidStudio的Terminal中编译 只是keystore的路径改成debug.keystore    密钥库口令默认是android) 创建key成功 得到key: 前期准备完成 下一篇文章是开发配置 备忘 ,也希

Android小例子:使用反射机制来读取图片制作一个图片浏览器

效果图: 工程文件夹: 该例子可供于新手参考练习,如果有哪里不对的地方,望指正>-< <黑幕下的人> java代码(MainActivity.java): package com.example.imageswitchtest; import java.lang.reflect.Field; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.v

Android Studio 安装及常见问题

今年放假比去年早了一些,就提前回来了.感觉挺爽,结果教研室电脑没有带回来,悲剧是导师让我维护一下以前的项目,只能屁颠屁颠的搞起呀.只能用自己的笔记本搭建android开发环境.由于前阶段听说Android Studio用着爽歪歪,于是尝试在超卡的笔记本上跑Android Studio.哇咔咔,费了九牛二虎之力终于将Android Studio玩转了.先上个图,快过年了,祝大家新年快乐! Android官网也开始推广Android Studio了,以前官网好像提供Eclipse和ADT打包下载,现

Android 导航条效果实现(六) TabLayout+ViewPager+Fragment

TabLayout 一.继承结构 public class TabLayout extends HorizontalScrollView java.lang.Object ? android.view.View ? android.view.ViewGroup ? android.widget.FrameLayout ? android.widget.HorizontalScrollView ? android.support.design.widget.TabLayout 二.TabLayou

Android Studio 连接真机不识别

本人也是初学..写错的请大神多多批评指正! 不胜荣幸!! 强烈推荐使用真机测试..除非是最后关头要测试各个Android系统版本.. 本人遇到的连不上的原因有以下几种: 1  --   手机设置问题.开USB调试   方法:  手机设置 - 开发人员选项 - USB调试  - 勾选 2  --   数据线问题.  有的数据线只能用来充电,有的可以连接存储.识别方法很简单..插上机器有USB存储设备的提示的就可以用.另外数据线如果都露线皮了..就赶紧扔了.十块八块的总比你为这个破问题纠结一下午的好

android Activity 的生命周期 以及横屏竖屏切换时 Activity 的状态变化

生命周期Android 系统在Activity 生命周期中加入一些钩子,我们可以在这些系统预留的钩子中做一些事情.例举了 7 个常用的钩子:protected void onCreate(Bundle savedInstanceState)protected void onStart()protected void onResume()protected void onPause()protected void onStop()protected void onRestart()protecte

谈谈-Android中的接口回调技术

Android中的接口回调技术有很多应用的场景,最常见的:Activity(人机交互的端口)的UI界面中定义了Button,点击该Button时,执行某个逻辑. 下面参见上述执行的模型,讲述James对Android接口回调技术的理解(结合前人的知识和自己的实践). 使用一个比喻很形象地说明:客户端有个疑问打电话请教服务端,但服务端无法现场给出解答,相互之间约定:服务端一旦有答案,使用电话的方式反馈给客户端. 以上有三个主体:客户端.服务端和接口(方式). 接口回调的原理框图说明: Demo界面