Android program crash exception Collection framework

Source: Internet
Author: User

Recently, I am writing Android program crash Exception Handling. After completing this process, I will share it with you in a bit of encapsulation.

My idea is to save the exception information to a log file after the program crashes, and then process the file, such as sending it to the mailbox or to the server.

Therefore, the first step is to define an interface for callback after saving the log. The Code is as follows:

/** @ (#) CrashListener. java Project: crash * Date: ** Copyright (c) 2014 CFuture09, Institute of Software, * Guangdong Ocean University, Zhanjiang, GuangDong, China. * All rights reserved. ** Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file License t in compliance with the License. * You may obtain a copy of the License at ** http://www.apache.org /Licenses/LICENSE-2.0 ** Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "as is" BASIS, * without warranties or conditions of any kind, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com. githang. android. crash; import java. io. file ;/** * @ Author Geek_Soledad */public interface CrashListener {/*** saves abnormal logs. ** @ Param file */public void afterSaveCrash (File file );}

Next is the class used to handle crash exceptions. It implements the UncaughtExceptionHandler interface. After the program is implemented, it is set as the handler of the default thread exception, so that after the program crashes, it will be called. However, before calling it, you also need to obtain the default handler before saving it, which is used to process the program after we collect exceptions, for example, the "program stopped running" dialog box is displayed by default (you can also implement one by yourself), terminate the program, and print the LOG.

My implementation is as follows:

/* * @(#)CrashHandler.java       Project: crash * Date:2014-5-26 * * Copyright (c) 2014 CFuture09, Institute of Software,  * Guangdong Ocean University, Zhanjiang, GuangDong, China. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); *  you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.githang.android.crash;import java.io.File;import java.lang.Thread.UncaughtExceptionHandler;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Future;/** * @author Geek_Soledad  */public class CrashHandler implements UncaughtExceptionHandler {    private static final CrashHandler sHandler = new CrashHandler();    private static final UncaughtExceptionHandler sDefaultHandler = Thread            .getDefaultUncaughtExceptionHandler();    private static final ExecutorService THREAD_POOL = Executors.newSingleThreadExecutor();    private Future
  future;    private CrashListener mListener;    private File mLogFile;    public static CrashHandler getInstance() {        return sHandler;    }    @Override    public void uncaughtException(Thread thread, Throwable ex) {        CrashLogUtil.writeLog(mLogFile, "CrashHandler", ex.getMessage(), ex);        future = THREAD_POOL.submit(new Runnable() {            public void run() {                if (mListener != null) {                    mListener.afterSaveCrash(mLogFile);                }            };        });        if (!future.isDone()) {            try {                future.get();            } catch (Exception e) {                e.printStackTrace();            }        }        sDefaultHandler.uncaughtException(thread, ex);    }    public void init(File logFile, CrashListener listener) {        mLogFile = logFile;        mListener = listener;    }}

This class is very simple, that is, after an exception is not captured, save the LOG to the file, and then call the previously defined interface to process the LOG file. CrashLogUtil is the class that I implement to save logs to files. The Code is as follows:
/** @ (#) LogUtil. java Project: crash * Date: ** Copyright (c) 2014 CFuture09, Institute of Software, * Guangdong Ocean University, Zhanjiang, GuangDong, China. * All rights reserved. ** Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file License t in compliance with the License. * You may obtain a copy of the License at ** http://www.apache.org/licen Ses/LICENSE-2.0 ** Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "as is" BASIS, * without warranties or conditions of any kind, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com. githang. android. crash; import java. io. bufferedWriter; Import java. io. closeable; import java. io. file; import java. io. fileWriter; import java. io. IOException; import java. io. printWriter; import java. text. simpleDateFormat; import java. util. calendar; import java. util. locale;/*** @ author Geek_Soledad */public class CrashLogUtil {private static final SimpleDateFormat timeFormat = new SimpleDateFormat ("MM-dd HH: mm: ss. SSS ", Locale. getDefault ();/*** write logs to a file. ** @ Param tag * @ param message * @ param tr */public static synchronized void writeLog (File logFile, String tag, String message, Throwable tr) {logFile. getParentFile (). mkdirs (); if (! LogFile. exists () {try {logFile. createNewFile ();} catch (IOException e) {e. printStackTrace () ;}string time = timeFormat. format (Calendar. getInstance (). getTime (); synchronized (logFile) {FileWriter fileWriter = null; BufferedWriter bufdWriter = null; PrintWriter printWriter = null; try {fileWriter = new FileWriter (logFile, true ); bufdWriter = new BufferedWriter (fileWriter); printWriter = ne W PrintWriter (fileWriter); bufdWriter. append (time ). append (""). append ("E "). append ('/'). append (tag ). append (""). append (message ). append ('\ n'); bufdWriter. flush (); tr. printStackTrace (printWriter); printWriter. flush (); fileWriter. flush ();} catch (IOException e) {closeQuietly (fileWriter); closeQuietly (bufdWriter); closeQuietly (printWriter);} public static void closeQuietly (Closeable closeable) {If (closeable! = Null) {try {closeable. close () ;}catch (IOException ioe) {// ignore }}}}

After saving the log, we also need to generate a report and send it to the server. The report method can be sent to the mailbox or an http request to the server. Therefore, an abstract class is written to generate the title and content, and set the Log Path. The Code is as follows:

/* * @(#)AbstractReportHandler.java       Project: crash * Date:2014-5-27 * * Copyright (c) 2014 CFuture09, Institute of Software,  * Guangdong Ocean University, Zhanjiang, GuangDong, China. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); *  you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.githang.android.crash;import java.io.File;import android.content.Context;import android.content.pm.ApplicationInfo;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.os.Build;/** * @author Geek_Soledad  */public abstract class AbstractCrashReportHandler implements CrashListener {    private Context mContext;    public AbstractCrashReportHandler(Context context) {        mContext = context;        CrashHandler handler = CrashHandler.getInstance();        handler.init(getLogDir(context), this);        Thread.setDefaultUncaughtExceptionHandler(handler);    }    protected File getLogDir(Context context) {        return new File(context.getFilesDir(), "crash.log");    }    protected abstract void sendReport(String title, String body, File file);    @Override    public void afterSaveCrash(File file) {        sendReport(buildTitle(mContext), buildBody(mContext), file);    }    public String buildTitle(Context context) {        return "Crash Log: "                + context.getPackageManager().getApplicationLabel(context.getApplicationInfo());    }    public String buildBody(Context context) {        StringBuilder sb = new StringBuilder();        sb.append("APPLICATION INFORMATION").append('\n');        PackageManager pm = context.getPackageManager();        ApplicationInfo ai = context.getApplicationInfo();        sb.append("Application : ").append(pm.getApplicationLabel(ai)).append('\n');        try {            PackageInfo pi = pm.getPackageInfo(ai.packageName, 0);            sb.append("Version Code: ").append(pi.versionCode).append('\n');            sb.append("Version Name: ").append(pi.versionName).append('\n');        } catch (PackageManager.NameNotFoundException e) {            e.printStackTrace();        }        sb.append('\n').append("DEVICE INFORMATION").append('\n');        sb.append("Board: ").append(Build.BOARD).append('\n');        sb.append("BOOTLOADER: ").append(Build.BOOTLOADER).append('\n');        sb.append("BRAND: ").append(Build.BRAND).append('\n');        sb.append("CPU_ABI: ").append(Build.CPU_ABI).append('\n');        sb.append("CPU_ABI2: ").append(Build.CPU_ABI2).append('\n');        sb.append("DEVICE: ").append(Build.DEVICE).append('\n');        sb.append("DISPLAY: ").append(Build.DISPLAY).append('\n');        sb.append("FINGERPRINT: ").append(Build.FINGERPRINT).append('\n');        sb.append("HARDWARE: ").append(Build.HARDWARE).append('\n');        sb.append("HOST: ").append(Build.HOST).append('\n');        sb.append("ID: ").append(Build.ID).append('\n');        sb.append("MANUFACTURER: ").append(Build.MANUFACTURER).append('\n');        sb.append("PRODUCT: ").append(Build.PRODUCT).append('\n');        sb.append("TAGS: ").append(Build.TAGS).append('\n');        sb.append("TYPE: ").append(Build.TYPE).append('\n');        sb.append("USER: ").append(Build.USER).append('\n');        return sb.toString();    }}

Such a framework is basically complete.

Of course, I also provide an implementation of the Report to send emails.

There are a lot of materials on the Internet for sending emails.

Three jar packages are required: activation. jar, additionnal. jar, and mail. jar.

Then write a class that inherits from Authenticator. The Code is as follows:

/** @ (#) Snippet. java Project: CrashHandler * Date: ** Copyright (c) 2014 CFuture09, Institute of Software, * Guangdong Ocean University, Zhanjiang, GuangDong, China. * All rights reserved. ** Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file License t in compliance with the License. * You may obtain a copy of the License at ** http://www.apache.o Rg/licenses/LICENSE-2.0 ** Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "as is" BASIS, * without warranties or conditions of any kind, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com. githang. android. crash; import android. util. lo G; import java. util. date; import java. util. properties; import javax. activation. commandMap; import javax. activation. dataHandler; import javax. activation. dataSource; import javax. activation. fileDataSource; import javax. activation. mailcapCommandMap; import javax. mail. authenticator; import javax. mail. bodyPart; import javax. mail. messagingException; import javax. mail. multipart; import javax. mail. passwordAuthenticat Ion; import javax. mail. session; import javax. mail. transport; import javax. mail. internet. internetAddress; import javax. mail. internet. mimeBodyPart; import javax. mail. internet. mimeMessage; import javax. mail. internet. mimeMultipart;/*** Author: msdx (645079761@qq.com) Time: 14-5-27 am */public class LogMail extends Authenticator {private String host; private String port; private String user; private St Ring pass; private String from; private String to; private String subject; private String body; private Multipart multipart; private Properties props; public LogMail () {} public LogMail (String user, string pass, String from, String to, String host, String port, String subject, String body) {this. host = host; this. port = port; this. user = user; this. pass = pass; this. from = from; this. to = to; th Is. subject = subject; this. body = body;} public LogMail setHost (String host) {this. host = host; return this;} public LogMail setPort (String port) {this. port = port; return this;} public LogMail setUser (String user) {this. user = user; return this;} public LogMail setPass (String pass) {this. pass = pass; return this;} public LogMail setFrom (String from) {this. from = from; return this;} pub Lic LogMail setTo (String to) {this. to = to; return this;} public LogMail setSubject (String subject) {this. subject = subject; return this;} public LogMail setBody (String body) {this. body = body; return this;} public void init () {multipart = new MimeMultipart (); // There is something wrong with MailCap, javamail can not find a // handler for the multipart/mixed part, so this bit needs to be Dded. mailcapCommandMap mc = (MailcapCommandMap) CommandMap. getdefacommandcommandmap (); mc. addMailcap ("text/html; x-java-content-handler = com. sun. mail. handlers. text_html "); mc. addMailcap ("text/xml; x-java-content-handler = com. sun. mail. handlers. text_xml "); mc. addMailcap ("text/plain; x-java-content-handler = com. sun. mail. handlers. text_plain "); mc. addMailcap ("multipart/*; x-java-content-handler = com. sun. m Ail. handlers. multipart_mixed "); mc. addMailcap ("message/rfc822; x-java-content-handler = com. sun. mail. handlers. message_rfc822 "); CommandMap. setdefacommandcommandmap (mc); props = new Properties (); props. put ("mail. smtp. host ", host); props. put ("mail. smtp. auth "," true "); props. put ("mail. smtp. port ", port); props. put ("mail. smtp. socketFactory. port ", port); props. put ("mail. transport. protocol "," smtp "); props. pu T ("mail. smtp. socketFactory. class "," javax.net. ssl. SSLSocketFactory "); props. put ("mail. smtp. socketFactory. fallback "," false ");} public boolean send () throws MessagingException {if (! User. equals ("")&&! Pass. equals ("")&&! To. equals ("")&&! From. equals ("") {Session session Session = Session. getDefaultInstance (props, this); Log. d ("SendUtil", host + "... "+ port + ".. "+ user + "... "+ pass); MimeMessage msg = new MimeMessage (session); msg. setFrom (new InternetAddress (from); InternetAddress addressTo = new InternetAddress (to); msg. setRecipient (MimeMessage. recipientType. TO, addressTo); msg. setSubject (subject); msg. setSentDate (new Date (); // setup message body BodyPart messageBodyPart = new MimeBodyPart (); messageBodyPart. setText (body); multipart. addBodyPart (messageBodyPart); // Put parts in message msg. setContent (multipart); // send email Transport. send (msg); return true;} else {return false;} public void addAttachment (String filePath, String fileName) throws Exception {BodyPart messageBodyPart = new MimeBodyPart (); dataSource source = new FileDataSource (filePath); messageBodyPart. setDataHandler (new DataHandler (source); messageBodyPart. setFileName (fileName); multipart. addBodyPart (messageBodyPart);} @ Override public PasswordAuthentication getPasswordAuthentication () {return new PasswordAuthentication (user, pass );}}
Next, the class that sends the report email. It inherits from the aforementioned AbstractCrashReportHandler and implements the following:

/* * @(#)CrashEmailReport.java       Project: CrashHandler * Date: 2014-5-27 * * Copyright (c) 2014 CFuture09, Institute of Software,  * Guangdong Ocean University, Zhanjiang, GuangDong, China. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); *  you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package com.githang.android.crash;import java.io.File;import android.content.Context;/** * @author Geek_Soledad  */public class CrashEmailReport extends AbstractCrashReportHandler {    private String mReceiveEmail;    public CrashEmailReport(Context context) {        super(context);    }    public void setReceiver(String receiveEmail) {        mReceiveEmail = receiveEmail;    }        @Override    protected void sendReport(String title, String body, File file) {        LogMail sender = new LogMail().setUser("irain_log@163.com").setPass("xxxxxxxx")                .setFrom("irain_log@163.com").setTo(mReceiveEmail).setHost("smtp.163.com")                .setPort("465").setSubject(title).setBody(body);        sender.init();        try {            sender.addAttachment(file.getPath(), file.getName());            sender.send();            file.delete();        } catch (Exception e) {            e.printStackTrace();        }    }}

In this way, a complete program crash exception framework is complete. For log reports, you can inherit AbstractCrashReportHandler to expand the implementation.

When using this function, you need to write a class that inherits from the Application. In the onCreate method, add the following code to set the receiving mailbox.

  new CrashEmailReport(this).setReceiver("log@msdx.pw");
Configure this class in AndroidManifest. xml.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.