Skip to content

Instantly share code, notes, and snippets.

@KennethYo
Last active June 5, 2017 06:09
Show Gist options
  • Save KennethYo/b2cc9ae2b8a6c26fbe249b1fb276fff6 to your computer and use it in GitHub Desktop.
Save KennethYo/b2cc9ae2b8a6c26fbe249b1fb276fff6 to your computer and use it in GitHub Desktop.
Android Crash Handler
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Application;
import android.os.Process;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.text.TextUtils;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
/**
* crash handler
* Created by kenneth on 2016/12/20.
*/
public class CrashHandler implements Thread.UncaughtExceptionHandler {
private final Application app;
private final boolean debug;
private final String buildTime;
private final Thread.UncaughtExceptionHandler defaultHandler;
private final SimpleActivityLifecycleCallbacks lifecycleCallbacks;
private OnCrashListener onCrashListener;
public static CrashHandler create(Application app, boolean debug) {
return new CrashHandler(app, debug, null);
}
public static CrashHandler create(Application app, boolean debug, String buildTime) {
return new CrashHandler(app, debug, buildTime);
}
private CrashHandler(Application app, boolean debug, String buildTime) {
this.app = app;
this.debug = debug;
this.buildTime = buildTime;
defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
lifecycleCallbacks = new SimpleActivityLifecycleCallbacks();
app.registerActivityLifecycleCallbacks(lifecycleCallbacks);
}
public void setOnCrashListener(OnCrashListener onCrashListener) {
this.onCrashListener = onCrashListener;
}
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
StringBuilder sb = new StringBuilder();
addAppDebug(sb);
addProcessAndThread(sb);
addActivitiesAndFragments(sb);
addLeakedActivities(sb);
addMemoryInfo(sb);
Throwable crashThrowable = new Throwable(sb.toString(), throwable);
if (onCrashListener != null) onCrashListener.onCrash(thread, crashThrowable);
if (defaultHandler != null) defaultHandler.uncaughtException(thread, crashThrowable);
}
/**
* add APP is debug or not
*/
private void addAppDebug(StringBuilder sb) {
sb.append("\n");
sb.append("debug: ").append(debug);
if (!TextUtils.isEmpty(buildTime)) {
sb.append(", ");
sb.append("build: ").append(buildTime);
}
}
/**
* add process name and current thread name
*/
private void addProcessAndThread(StringBuilder sb) {
sb.append("\n");
int myPid = Process.myPid();
ActivityManager am = (ActivityManager) app.getSystemService(Application.ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo appProcess : am.getRunningAppProcesses()) {
if (appProcess.pid == myPid) {
sb.append("process: ").append(appProcess.processName).append(", ");
break;
}
}
sb.append("thread: ").append(Thread.currentThread().getName());
}
/**
* add opened activities
*/
private void addActivitiesAndFragments(StringBuilder sb) {
sb.append("\n");
List<Activity> activityList = lifecycleCallbacks.activityList;
sb.append("activities: ");
boolean firstTime = true;
for (Activity activity : activityList) {
if (firstTime) {
firstTime = false;
} else {
sb.append(",");
}
sb.append(activity.getClass().getSimpleName());
addFragments(sb, activity);
}
}
private void addFragments(StringBuilder sb, Activity activity) {
if (activity instanceof FragmentActivity) {
FragmentActivity fragmentActivity = (FragmentActivity) activity;
FragmentManager fragmentManager = fragmentActivity.getSupportFragmentManager();
List<Fragment> fragments = fragmentManager.getFragments();
if (!Utils.isEmpty(fragments)) {
sb.append("(").append(Utils.getNamesString(fragments)).append(")");
}
}
}
/**
* add leaked activities
*/
private void addLeakedActivities(StringBuilder sb) {
sb.append("\n");
List<String> leakedActivityNames = new ArrayList<>();
List<WeakReference<Activity>> referenceActivities = lifecycleCallbacks.referenceActivities;
for (WeakReference<Activity> wf : referenceActivities) {
Activity activity = wf.get();
if (activity == null) continue;
if (!lifecycleCallbacks.activityList.contains(activity)) {
leakedActivityNames.add(activity.getClass().getSimpleName());
}
}
sb.append("leaked activities: ").append(TextUtils.join(",", leakedActivityNames));
}
/**
* add memory information
*/
private void addMemoryInfo(StringBuilder sb) {
sb.append("\n");
Runtime runtime = Runtime.getRuntime();
float maxMemory = runtime.maxMemory() / 1024 / 1024f;
float totalMemory = runtime.totalMemory() / 1024 / 1024f;
float freeMemory = runtime.freeMemory() / 1024 / 1024f;
sb.append("maxMemory: ").append(maxMemory).append("MB").append(",");
sb.append("totalMemory: ").append(totalMemory).append("MB").append(",");
sb.append("freeMemory: ").append(freeMemory).append("MB");
}
public interface OnCrashListener {
void onCrash(Thread thread, Throwable throwable);
}
}
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
/**
* Created by kenneth on 2016/12/20.
*/
class SimpleActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
List<Activity> activityList = new ArrayList<>();
List<WeakReference<Activity>> referenceActivities = new ArrayList<>();
SimpleActivityLifecycleCallbacks() {
}
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
activityList.add(activity);
referenceActivities.add(new WeakReference<>(activity));
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
activityList.remove(activity);
}
}
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Created by kenneth on 2016/12/20.
*/
public class Utils {
static <T> String getNamesString(List<T> list) {
if (isEmpty(list)) return null;
return TextUtils.join(",", getClassNames(list));
}
private static <T> List<String> getClassNames(List<T> list) {
if (isEmpty(list)) return null;
List<String> names = new ArrayList<>();
for (Object o : list) {
names.add(o.getClass().getSimpleName());
}
return names;
}
public static boolean isEmpty(Collection collection) {
return collection == null || collection.isEmpty();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment