As we all know, now installs the Android system the handset version and the equipment are very different, in the simulator the good running program installs to a certain handset to be possible to collapse the phenomenon, the developer individual cannot buy all equipment to debug one by the same time, therefore after the program releases, if has the collapse phenomenon, Developers should be able to get the information that caused the crash on the device in time, this is great for the next release of bug fixes, so let's take a look at how to gather relevant device parameter information and specific exception information in the event of a program crash, and send that information to the server for analysis and debugging by the developer.
We first set up a crash project, the project structure as shown:
In the Mainactivity.java code, the code reads:
Package Com.scott.crash;
Import android.app.Activity;
Import Android.os.Bundle;
public class Mainactivity extends activity {
private String s;
@Override public
void OnCreate (Bundle savedinstancestate) {
super.oncreate (savedinstancestate);
System.out.println (S.equals ("any string"));
}
We intentionally created a potential run-time exception, and the following interface appears when we run the program:
The
Encounters an exception that is not caught by the software and the system pops up this default forced Shutdown dialog box.
We certainly don't want users to see this, it's a mental blow to the user, and it's no help to fix our bugs. What we need is the software has a global exception trap, when there is an exception we do not find, catch this exception, and the exception information recorded, uploaded to the server public development This analysis of the specific reasons for the exception.
The next step is to implement this mechanism, but first let's look at the following two classes: Android.app.Application and Java.lang.Thread.UncaughtExceptionHandler.
Application: Used to manage the global state of an application. Application is created the first time the application starts, and then the corresponding activity and service are started according to the situation (Intent). In this example, an application exception handler is registered in the custom enhanced version of the.
Thread.uncaughtexceptionhandler: The thread did not capture an exception handler to handle an exception that was not caught. If an exception is not caught in the program, the Force Close dialog box is ejected from the system by default. We need to implement this interface and register for exception handling that is not caught by default in the program. This allows some personalized exception handling to occur when an exception is not caught.
The Crashhandler.java that you have just seen in the project's structure diagram implements the Thread.uncaughtexceptionhandler, which allows us to handle the primary members of the exception that were not caught, as follows:
Package Com.scott.crash;
Import Java.io.File;
Import Java.io.FileOutputStream;
Import Java.io.PrintWriter;
Import Java.io.StringWriter;
Import Java.io.Writer;
Import Java.lang.Thread.UncaughtExceptionHandler;
Import Java.lang.reflect.Field;
Import Java.text.DateFormat;
Import Java.text.SimpleDateFormat;
Import Java.util.Date;
Import Java.util.HashMap;
Import Java.util.Map;
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.widget.Toast;
/** * Uncaughtexception processing class, when the program occurs uncaught exception, there is a class to take over the program, and record the sending error report. * * @author User * */public class Crashhandler implements Uncaughtexceptionhandler {public static final St
Ring TAG = "Crashhandler"; system default Uncaughtexception processing class private Thread.uncaughteXceptionhandler Mdefaulthandler;
Crashhandler instance private static Crashhandler INSTANCE = new Crashhandler ();
The context object of the program is private context Mcontext;
Used to store device information and exception information private map<string, string> infos = new hashmap<string, string> ();
Used to format the date as part of the log file name private DateFormat formatter = new SimpleDateFormat ("Yyyy-mm-dd-hh-mm-ss"); /** guarantee Only one Crashhandler instance/private Crashhandler () {}/** get Crashhandler instance, single case mode/public static Crashhand
Ler getinstance () {return INSTANCE;
/** * Initialization * * @param context */public void init (context context) {Mcontext = context;
Gets the system default Uncaughtexception processor Mdefaulthandler = Thread.getdefaultuncaughtexceptionhandler ();
Set this Crashhandler as the default processor for the program Thread.setdefaultuncaughtexceptionhandler (this); /** * When uncaughtexception occurs, it is transferred to the function to process/@Override public void uncaughtexception (thread thread, Throwa Ble ex) {if (!handleException (ex) && mdefaulthandler!= null) {//If the user does not have a deal, let the system default exception handler handle mdefaulthandler.uncaughtexcept
Ion (thread, ex);
else {try {thread.sleep (3000);
catch (Interruptedexception e) {log.e (TAG, "error:", e);
}//Exit program Android.os.Process.killProcess (Android.os.Process.myPid ());
System.exit (1);
}/** * Custom error handling, collect error messages send error reports, and so on are done here.
* @param ex * @return true: If the exception information is processed, FALSE is returned.
* * Private Boolean handleexception (Throwable ex) {if (ex = null) {return false;
///Use Toast to display exception information new Thread () {@Override public void run () {looper.prepare ();
Toast.maketext (Mcontext, "Sorry, the program is abnormal, is about to exit.", Toast.length_long). Show ();
Looper.loop ();
}}.start ();
Collect equipment parameter information collectdeviceinfo (MCONTEXT);
Save log file Savecrashinfo2file (ex);
return true; /** * Collecting Equipment parametersInformation * @param CTX */public void Collectdeviceinfo (context ctx) {try {packagemanager pm = ctx.getpa
Ckagemanager ();
PackageInfo pi = pm.getpackageinfo (Ctx.getpackagename (), packagemanager.get_activities); if (pi!= null) {String versionname = Pi.versionname = null?
"NULL": Pi.versionname;
String Versioncode = Pi.versioncode + "";
Infos.put ("Versionname", versionname);
Infos.put ("Versioncode", Versioncode);
The catch (Namenotfoundexception e) {log.e (TAG, "An error occured when collect package info", e);
} field[] fields = Build.class.getDeclaredFields ();
for (Field field:fields) {try {field.setaccessible (true);
Infos.put (Field.getname (), Field.get (null). ToString ());
LOG.D (TAG, Field.getname () + ":" + field.get (null));
catch (Exception e) {log.e (TAG, "An error occured when collect crash info", e);
}
}
}
/** * Save error message to file * @param ex * @return returns the file name to facilitate the transfer of files to the server/private String Savecrashinfo2file (Throwable ex)
{StringBuffer sb = new StringBuffer ();
For (map.entry<string, string> entry:infos.entrySet ()) {String key = Entry.getkey ();
String value = Entry.getvalue ();
Sb.append (key + "=" + value + "\ n");
} Writer Writer = new StringWriter ();
PrintWriter printwriter = new PrintWriter (writer);
Ex.printstacktrace (PrintWriter);
Throwable cause = Ex.getcause ();
while (cause!= null) {cause.printstacktrace (printwriter);
Cause = Cause.getcause ();
} printwriter.close ();
String result = Writer.tostring ();
Sb.append (result);
try {long timestamp = System.currenttimemillis ();
String time = Formatter.format (new Date ());
String fileName = "crash-" + Time + "-" + timestamp + ". Log"; if (Environment.getexternalstoragestate (). eqUals (environment.media_mounted)) {String path = "/sdcard/crash/";
File dir = new file (path);
if (!dir.exists ()) {dir.mkdirs ();
FileOutputStream fos = new FileOutputStream (path + fileName);
Fos.write (Sb.tostring (). GetBytes ());
Fos.close ();
return fileName;
catch (Exception e) {log.e (TAG, "An error occured while writing file ...", e);
return null;
}
}
When collecting exception information, friends can also use properties, because properties have a convenient way to Properties.store (OutputStream out, String comments), Used to export the key values from the properties instance to the output stream, but found that the exception information in the generated file was printed on the same line in the same row, and it looked extremely laborious, so replace it with a map to store the information, and then take a little action when the file was generated.
After completing this crashhandler, we need to run it in a application environment, so we inherit android.app.Application, add our own code, Crashapplication.java code as follows:
Package Com.scott.crash;
Import android.app.Application;
public class Crashapplication extends application {
@Override public
void OnCreate () {
super.oncreate ();
Crashhandler Crashhandler = Crashhandler.getinstance ();
Crashhandler.init (Getapplicationcontext ());
}
Finally, in order for our crashapplication to take the place of android.app.Application, in our code, we need to modify the Androidmanifest.xml:
<application android:name= ". Crashapplication "...>
Because we have to save the device parameters and the specific exception information to SDcard in the above crashhandler, we need to add read and write SDcard permissions in Androidmanifest.xml:
<uses-permission android:name= "Android.permission.WRITE_EXTERNAL_STORAGE"/>
After we've done the above steps, let's Run this project:
See, there will be no forced closure of the dialog box appears, instead we have a better hint of the message.
Then look at the files generated by SDcard:
Open the log file with a text editor and read a section of log information:
Cpu_abi=armeabi
cpu_abi2=unknown
id=frf91
manufacturer=unknown
brand=generic
Type=eng ......
caused by:java.lang.NullPointerException at
com.scott.crash.MainActivity.onCreate (mainactivity.java:13) At
android.app.Instrumentation.callActivityOnCreate (instrumentation.java:1047)
at Android.app.ActivityThread.performLaunchActivity (activitythread.java:2627) ...
One more
This information is very helpful to developers, so we need to upload this log file to the server, for file upload technology, please refer to Android using the HTTP service related introduction.
However, before using the HTTP service, you need to determine that the network is unblocked, and we can use the following methods to determine whether the network is available:
*/Public
static Boolean isnetworkavailable (context context) {
Connectivitymanager mgr = (connectivitymanager) Context.getsystemservice (context.connectivity_service);
Networkinfo[] info = Mgr.getallnetworkinfo ();
if (info!= null) {for
(int i = 0; i < info.length i++) {
if (info[i].getstate () = = NetworkInfo.State.CONNECT ED) {return
true;
}}} return false;
I hope this article will help you learn about Android software programming.