package com.as.demo_ok44;import android.annotation.SuppressLint;import android.app.Activity;import android.app.Application;import android.content.Context;import android.content.Intent;import android.content.pm.PackageManager;import android.content.pm.ResolveInfo;import android.os.Build;import android.os.Bundle;import android.util.Log;import java.io.PrintWriter;import java.io.StringWriter;import java.lang.ref.WeakReference;import java.util.List;/* * Copyright 2015 Eduard Ereza Martínez * * 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. * * 崩溃页面 */@SuppressLint("NewApi")public final class CrashManager {    //Extras passed to the error activity    private static final String EXTRA_RESTART_ACTIVITY_CLASS = "EXTRA_RESTART_ACTIVITY_CLASS";    private static final String EXTRA_SHOW_ERROR_DETAILS = "EXTRA_SHOW_ERROR_DETAILS";    private static final String EXTRA_STACK_TRACE = "EXTRA_STACK_TRACE";    //General constants    private final static String TAG = "crashmanager";    private static final String INTENT_ACTION_ERROR_ACTIVITY = "ERROR";    private static final String INTENT_ACTION_RESTART_ACTIVITY = "RESTART";    private static final String CAOC_HANDLER_PACKAGE_NAME = "com.crashmanager";    private static final String DEFAULT_HANDLER_PACKAGE_NAME = "com.android.internal.os";    private static final int MAX_STACK_TRACE_SIZE = 131071; //128 KB - 1    //Internal variables    private static Application application;    private static WeakReference lastActivityCreated = new WeakReference<>(null);    private static boolean isInBackground = false;    //Settable properties and their defaults    private static boolean launchErrorActivityWhenInBackground = true;    private static boolean showErrorDetails = true;    private static boolean enableAppRestart = true;    private static Class<? extends Activity> errorActivityClass = null;    private static Class<? extends Activity> restartActivityClass = null;    /**     * Installs crashmanager on the application using the default error activity.     *     * @param context Context to use for obtaining the ApplicationContext. Must not be null.     */    public static void install(Context context) {        try {            if (context == null) {                Log.e(TAG, "Install failed: context is null!");            } else {                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {                    Log.w(TAG, "crashmanager will be installed, but may not be reliable in API lower than 14");                }                //INSTALL!                Thread.UncaughtExceptionHandler oldHandler = Thread.getDefaultUncaughtExceptionHandler();                if (oldHandler != null && oldHandler.getClass().getName().startsWith(CAOC_HANDLER_PACKAGE_NAME)) {                    Log.e(TAG, "You have already installed crashmanager, doing nothing!");                } else {                    if (oldHandler != null && !oldHandler.getClass().getName().startsWith(DEFAULT_HANDLER_PACKAGE_NAME)) {                        Log.e(TAG, "IMPORTANT WARNING! You already have an UncaughtExceptionHandler, are you sure this is correct? If you use ACRA, Crashlytics or similar libraries, you must initialize them AFTER crashmanager! Installing anyway, but your original handler will not be called.");                    }                    application = (Application) context.getApplicationContext();                    //We define a default exception handler that does what we want so it can be called from Crashlytics/ACRA                    Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {                        @Override                        public void uncaughtException(Thread thread, final Throwable throwable) {                            Log.e(TAG, "App has crashed, executing crashmanager's UncaughtExceptionHandler", throwable);                            if (errorActivityClass == null) {                                errorActivityClass = guessErrorActivityClass(application);                            }                            if (isStackTraceLikelyConflictive(throwable, errorActivityClass)) {                                Log.e(TAG, "Your application class or your error activity have crashed, the custom activity will not be launched!");                            } else {                                if (launchErrorActivityWhenInBackground || !isInBackground) {                                    final Intent intent = new Intent(application, errorActivityClass);                                    StringWriter sw = new StringWriter();                                    PrintWriter pw = new PrintWriter(sw);                                    throwable.printStackTrace(pw);                                    String stackTraceString = sw.toString();                                    //Reduce data to 128KB so we don't get a TransactionTooLargeException when sending the intent.                                    //The limit is 1MB on Android but some devices seem to have it lower.                                    //See: http://developer.android.com/reference/android/os/TransactionTooLargeException.html                                    //And: http://stackoverflow.com/questions/11451393/what-to-do-on-transactiontoolargeexception#comment46697371_12809171                                    if (stackTraceString.length() > MAX_STACK_TRACE_SIZE) {                                        String disclaimer = " [stack trace too large]";                                        stackTraceString = stackTraceString.substring(0, MAX_STACK_TRACE_SIZE - disclaimer.length()) + disclaimer;                                    }                                    if (enableAppRestart && restartActivityClass == null) {                                        //We can set the restartActivityClass because the app will terminate right now,                                        //and when relaunched, will be null again by default.                                        restartActivityClass = guessRestartActivityClass(application);                                    } else if (!enableAppRestart) {                                        //In case someone sets the activity and then decides to not restart                                        restartActivityClass = null;                                    }                                    intent.putExtra(EXTRA_STACK_TRACE, stackTraceString);                                    intent.putExtra(EXTRA_RESTART_ACTIVITY_CLASS, restartActivityClass);                                    intent.putExtra(EXTRA_SHOW_ERROR_DETAILS, showErrorDetails);                                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);                                    application.startActivity(intent);                                }                            }                            final Activity lastActivity = lastActivityCreated.get();                            if (lastActivity != null) {                                //We finish the activity, this solves a bug which causes infinite recursion.                                //This is unsolvable in API<14, so beware!                                //See: https://github.com/ACRA/acra/issues/42                                lastActivity.finish();                                lastActivityCreated.clear();                            }                            killCurrentProcess();                        }                    });                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {                        application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {                            int currentlyStartedActivities = 0;                            @Override                            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {                                if (activity.getClass() != errorActivityClass) {                                    // Copied from ACRA:                                    // Ignore activityClass because we want the last                                    // application Activity that was started so that we can                                    // explicitly kill it off.                                    lastActivityCreated = new WeakReference<>(activity);                                }                            }                            @Override                            public void onActivityStarted(Activity activity) {                                currentlyStartedActivities++;                                isInBackground = (currentlyStartedActivities == 0);                                //Do nothing                            }                            @Override                            public void onActivityResumed(Activity activity) {                                //Do nothing                            }                            @Override                            public void onActivityPaused(Activity activity) {                                //Do nothing                            }                            @Override                            public void onActivityStopped(Activity activity) {                                //Do nothing                                currentlyStartedActivities--;                                isInBackground = (currentlyStartedActivities == 0);                            }                            @Override                            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {                                //Do nothing                            }                            @Override                            public void onActivityDestroyed(Activity activity) {                                //Do nothing                            }                        });                    }                    Log.i(TAG, "crashmanager has been installed.");                }            }        } catch (Throwable t) {            Log.e(TAG, "An unknown error occurred while installing crashmanager, it may not have been properly initialized. Please report this as a bug if needed.", t);        }    }    /// INTERNAL METHODS NOT TO BE USED BY THIRD PARTIES    /**     * INTERNAL method that checks if the stack trace that just crashed is conflictive. This is true in the following scenarios:     * - The application has crashed while initializing (handleBindApplication is in the stack)     * - The error activity has crashed (activityClass is in the stack)     *     * @param throwable     The throwable from which the stack trace will be checked     * @param activityClass The activity class to launch when the app crashes     * @return true if this stack trace is conflictive and the activity must not be launched, false otherwise     */    private static boolean isStackTraceLikelyConflictive(Throwable throwable, Class<? extends Activity> activityClass) {        do {            StackTraceElement[] stackTrace = throwable.getStackTrace();            for (StackTraceElement element : stackTrace) {                if ((element.getClassName().equals("android.app.ActivityThread") && element.getMethodName().equals("handleBindApplication")) || element.getClassName().equals(activityClass.getName())) {                    return true;                }            }        } while ((throwable = throwable.getCause()) != null);        return false;    }    /**     * INTERNAL method used to guess which activity must be called from the error activity to restart the app.     * It will first get activities from the AndroidManifest with intent filter ,     * if it cannot find them, then it will get the default launcher.     * If there is no default launcher, this returns null.     *     * @param context A valid context. Must not be null.     * @return The guessed restart activity class, or null if no suitable one is found     */    private static Class<? extends Activity> guessRestartActivityClass(Context context) {        Class<? extends Activity> resolvedActivityClass;        //If action is defined, use that        resolvedActivityClass = CrashManager.getRestartActivityClassWithIntentFilter(context);        //Else, get the default launcher activity        if (resolvedActivityClass == null) {            resolvedActivityClass = getLauncherActivity(context);        }        return resolvedActivityClass;    }    /**     * INTERNAL method used to get the first activity with an intent-filter ,     * If there is no activity with that intent filter, this returns null.     *     * @param context A valid context. Must not be null.     * @return A valid activity class, or null if no suitable one is found     */    @SuppressWarnings("unchecked")    private static Class<? extends Activity> getRestartActivityClassWithIntentFilter(Context context) {        List resolveInfos = context.getPackageManager().queryIntentActivities(                new Intent().setAction(INTENT_ACTION_RESTART_ACTIVITY),                PackageManager.GET_RESOLVED_FILTER);        if (resolveInfos != null && resolveInfos.size() > 0) {            ResolveInfo resolveInfo = resolveInfos.get(0);            try {                return (Class<? extends Activity>) Class.forName(resolveInfo.activityInfo.name);            } catch (ClassNotFoundException e) {                //Should not happen, print it to the log!                Log.e(TAG, "Failed when resolving the restart activity class via intent filter, stack trace follows!", e);            }        }        return null;    }    /**     * INTERNAL method used to get the default launcher activity for the app.     * If there is no launchable activity, this returns null.     *     * @param context A valid context. Must not be null.     * @return A valid activity class, or null if no suitable one is found     */    @SuppressWarnings("unchecked")    private static Class<? extends Activity> getLauncherActivity(Context context) {        Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());        if (intent != null) {            try {                return (Class<? extends Activity>) Class.forName(intent.getComponent().getClassName());            } catch (ClassNotFoundException e) {                //Should not happen, print it to the log!                Log.e(TAG, "Failed when resolving the restart activity class via getLaunchIntentForPackage, stack trace follows!", e);            }        }        return null;    }    /**     * INTERNAL method used to guess which error activity must be called when the app crashes.     * It will first get activities from the AndroidManifest with intent filter ,     * if it cannot find them, then it will use the default error activity.     *     * @param context A valid context. Must not be null.     * @return The guessed error activity class, or the default error activity if not found     */    private static Class<? extends Activity> guessErrorActivityClass(Context context) {        Class<? extends Activity> resolvedActivityClass;        //If action is defined, use that        resolvedActivityClass = CrashManager.getErrorActivityClassWithIntentFilter(context);        //Else, get the default launcher activity    在这里   !!!        if (resolvedActivityClass == null) {            resolvedActivityClass = MainActivity.class;        }        return resolvedActivityClass;    }    /**     * INTERNAL method used to get the first activity with an intent-filter ,     * If there is no activity with that intent filter, this returns null.     *     * @param context A valid context. Must not be null.     * @return A valid activity class, or null if no suitable one is found     */    @SuppressWarnings("unchecked")    private static Class<? extends Activity> getErrorActivityClassWithIntentFilter(Context context) {        List resolveInfos = context.getPackageManager().queryIntentActivities(                new Intent().setAction(INTENT_ACTION_ERROR_ACTIVITY),                PackageManager.GET_RESOLVED_FILTER);        if (resolveInfos != null && resolveInfos.size() > 0) {            ResolveInfo resolveInfo = resolveInfos.get(0);            try {                return (Class<? extends Activity>) Class.forName(resolveInfo.activityInfo.name);            } catch (ClassNotFoundException e) {                //Should not happen, print it to the log!                Log.e(TAG, "Failed when resolving the error activity class via intent filter, stack trace follows!", e);            }        }        return null;    }    /**     * INTERNAL method that kills the current process.     * It is used after restarting or killing the app.     */    private static void killCurrentProcess() {        android.os.Process.killProcess(android.os.Process.myPid());        System.exit(10);    }}

 

public class App extends Application {    @Override    public void onCreate() {        super.onCreate();        CrashManager.install(this);    }}

清单注册

 

 

 

 

 

 

更多相关文章

  1. 安全新手入坑——HTML标签
  2. Nginx系列教程(四)| 一文带你读懂Nginx的动静分离
  3. WebView全屏播放h5视频
  4. android自动登陆SharedPreferences
  5. Android架构组件_LiveData
  6. 解决Android启动显示空白界面的问题,自定义进入软件前的背景图片
  7. Viewpager2—登录注册引导页面
  8. android 重新加载网络页面设置
  9. 【腾讯Bugly干货分享】Android内存泄漏的简单检查与分析方法

随机推荐

  1. android中布局的详解
  2. android 入门xml布局文件
  3. 传智播客android 视频课程列表
  4. 提取一个带计数框的EditText
  5. android改变字体的颜色的三种方法
  6. Android下修改SeekBar样式
  7. [Android(安卓)XML] --- android:scaleTy
  8. [置顶] Android(安卓)使用Android(安卓)S
  9. 分享:Android开发半月谈
  10. Android(安卓)- Binder机制 - client和普