Package org.wp.activity; Import Java.io.File; Import Java.io.FileOutputStream; Import Java.io.FilenameFilter; Import Java.io.PrintWriter; Import Java.io.StringWriter; Import Java.io.Writer; Import Java.lang.Thread.UncaughtExceptionHandler; Import Java.lang.reflect.Field; Import Java.util.Arrays; Import java.util.Properties; Import Java.util.TreeSet; 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.Looper; Import Android.util.Log; Import Android.widget.Toast; /** * * * Uncaughtexceptionhandler: The thread did not catch the exception controller that was used to handle the exception that was not caught. * If the program appears to have an exception that is not caught, the forced Shutdown dialog box appears by default * Implement this interface and register as the default unhandled exception handling in the program * So when an exception is not caught, you can do some exception handling * For example: Collect exception information, send error reports, etc. * * Uncaughtexception processing class, when the program occurs uncaught exception, by the class to take over the program, and record the sending error report. */ public class Crashhandler implements Uncaughtexceptionhandler { /** Debug Log Tag * * public static final String TAG = "Crashhandler"; /** whether to turn on log output, open in debug state, turn off in release state to promote program performance. public static Final Boolean DEBUG = true; /** Crashhandler Example * * private static Crashhandler INSTANCE; /** program's Context Object * * Private context Mcontext; /** system default Uncaughtexception processing class * * Private Thread.uncaughtexceptionhandler Mdefaulthandler;
/** uses properties to store information about the device and error stack information. Private Properties Mdevicecrashinfo = new properties (); private static final String Version_name = "Versionname"; private static final String Version_code = "Versioncode"; private static final String Stack_trace = "Stack_trace"; /** Error Report File extension * * private static final String crash_reporter_extension = ". Cr";
/** guarantee Only one Crashhandler instance * * Private Crashhandler () { } /** get Crashhandler instance, single case mode * * public static Crashhandler getinstance () { if (INSTANCE = null) INSTANCE = new Crashhandler (); return INSTANCE; }
/** * Initialize, register the context object, get the system default Uncaughtexception processor, and set the Crashhandler as the default processor for the program * * @param CTX */ public void init (context ctx) { Mcontext = CTX; Mdefaulthandler = Thread.getdefaultuncaughtexceptionhandler (); Thread.setdefaultuncaughtexceptionhandler (this); }
/** * When uncaughtexception occurs, it is transferred to this function to handle */ @Override public void uncaughtexception (thread thread, Throwable ex) { if (!handleexception (ex) && mdefaulthandler!= null) { If the user does not have the processing, let the system default exception handler handle Mdefaulthandler.uncaughtexception (thread, ex); } else { Sleep after a while to end the program To let the thread stop for a while to display toast information to the user and then kill the program try { Thread.Sleep (3000); catch (Interruptedexception e) { LOG.E (TAG, "Error:", e); } Android.os.Process.killProcess (Android.os.Process.myPid ()); System.exit (10); } } /** * Custom error handling, collect error messages send error reports, and so on are done here. Developers can customize the exception handling logic according to their own situation * * @param ex * @return true: If the exception information is processed, FALSE is returned */ Private Boolean handleexception (Throwable ex) { if (ex = null) { return true; } Final String msg = Ex.getlocalizedmessage (); Use Toast to display exception information New Thread () { @Override public void Run () { Toast display needs to appear in the message queue of a thread Looper.prepare (); Toast.maketext (Mcontext, "program error:" + MSG, Toast.length_long). Show (); Looper.loop (); } }.start (); Collecting device information Collectcrashdeviceinfo (Mcontext); Save Error Report file String crashfilename = Savecrashinfotofile (ex); Send error report to server Sendcrashreportstoserver (Mcontext); return true; } /** * Collector Crash Device information * * @param CTX */ public void Collectcrashdeviceinfo (context ctx) { try { Class for retrieving various kinds of information related to the Application packages that are currently installed on the device. Can find this class through Getpackagemanager (). Packagemanager pm = Ctx.getpackagemanager (); Getpackageinfo (String packagename, int flags) Retrieve overall information about a application package on the system. public static final int get_activities Since:api Level 1 PackageInfo flag:return information about activities in the package in activities. PackageInfo pi = pm.getpackageinfo (Ctx.getpackagename (), packagemanager.get_activities); if (pi!= null) { Public String Versionname The version name of this package, As specified by the <manifest> tag ' s versionname attribute. Mdevicecrashinfo.put (version_name, pi.versionname = null?) "Not set": Pi.versionname); public int Versioncode The version number of this package, As specified by the <manifest> tag ' s Versioncode attribute. Mdevicecrashinfo.put (Version_code, Pi.versioncode); } catch (Namenotfoundexception e) { LOG.E (TAG, "Error while collect package info", e); } Use reflection to collect device information. Contains various device information in the build class, Example: System version number, device manufacturer, etc. useful information to help debug programs Returns an array of field objects that reflect all the fields declared by the class or interface represented by this class object field[] fields = Build.class.getDeclaredFields (); for (Field field:fields) { try { Setaccessible (Boolean flag) Sets the accessible flag of this object to the indicated Boolean value. You can access a private variable by setting the Accessible property to True, or you get a illegalaccessexception exception Field.setaccessible (TRUE); Mdevicecrashinfo.put (Field.getname (), field.get (null)); if (DEBUG) { LOG.D (TAG, Field.getname () + ":" + field.get (null)); } catch (Exception e) { LOG.E (TAG, "Error while collect crash info", e); } } }
/** * Save error message to file * * @param ex * @return */ Private String Savecrashinfotofile (Throwable ex) { Writer info = new StringWriter (); PrintWriter printwriter = new PrintWriter (info); Printstacktrace (PrintWriter s) Outputs this throwable and its trace to the specified printwriter Ex.printstacktrace (PrintWriter); Getcause () returns the cause of this throwable and returns null if cause is not present or unknown. Throwable cause = Ex.getcause (); while (cause!= null) { Cause.printstacktrace (PrintWriter); Cause = Cause.getcause (); } ToString () returns the current value of the buffer as a string. String result = Info.tostring (); Printwriter.close (); Mdevicecrashinfo.put (stack_trace, result); try { Long timestamp = System.currenttimemillis (); String fileName = "crash-" + timestamp + crash_reporter_extension; Save File FileOutputStream trace = Mcontext.openfileoutput (FileName, context.mode_private); Mdevicecrashinfo.store (Trace, ""); Trace.flush (); Trace.close (); return fileName; catch (Exception e) { LOG.E (TAG, "An error occured while writing file ...", e); } return null; }
/** * Send the error report to the server containing the newly generated and previously not sent. * * @param CTX */ private void Sendcrashreportstoserver (context ctx) { string[] Crfiles = Getcrashreportfiles (CTX); if (crfiles!= null && crfiles.length > 0) { treeset<string> sortedfiles = new treeset<string> (); Sortedfiles.addall (Arrays.aslist (crfiles)); for (String filename:sortedfiles) { file cr = new File ( Ctx.getfilesdir (), fileName); postreport (CR); cr.delete ();//delete sent reports } /** * Get error Report file name * * @param CTX * @return */ Private string[] Getcrashreportfiles (context ctx) { File Filesdir = Ctx.getfilesdir (); class instances that implement the FilenameFilter interface can be used for filter file names FilenameFilter filter = new FilenameFilter () { Accept (File dir, String name) Tests whether the specified file should be included in a list of files. Public Boolean Accept (File dir, String name) { Return Name.endswith (crash_reporter_extension); } }; List (FilenameFilter filter) Returns an array of strings that specify the files and directories in the directory represented by this abstract path name that meet the specified filter return filesdir.list (filter); } private void Postreport (file file) { TODO sends error reports to server using HTTP Post No longer detailed here, developers can follow other network operations on OPHONESDN Tutorial to submit error reports } /** * You can call this function at program startup to send a report that was not previously sent */ public void Sendpreviousreportstoserver ( ) { sendcrashreportstoserver (mcontext); } } |