摘要 :在使用自己开发的android应用时,偶尔会出现 系统已停止运行 错误.这时候如果能记录错误日志,是非常有帮助的.

每个android应用都是由一个Application和多个activity或者server构成.应用启动时,会首先启动Application.在Application的onCreate方法中调用

Thread.setDefaultUncaughtExceptionHandler(handler);

就可以捕获导致应用崩溃的错误信息了.

 

首先应用要有读写sd卡权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

 

自定义一个Application,并在AndroidManifest.xml中使用这个Application

<application
        android:name=".MyApplication">
        ...
</application>
public class MyApplication extends Application {
    private static final String LOG_DIR = Environment
            .getExternalStorageDirectory().getAbsolutePath() + "/oldfeel/log/";
    private static final String LOG_NAME = getCurrentDateString() + ".txt";
    private ArrayList<Activity> list = new ArrayList<Activity>();
 
    @Override
    public void onCreate() {
        super.onCreate();
        Thread.setDefaultUncaughtExceptionHandler(handler);
    }
 
    UncaughtExceptionHandler handler = new UncaughtExceptionHandler() {
 
        @Override
        public void uncaughtException(Thread thread, Throwable ex) {
            writeErrorLog(ex);
            Intent intent = new Intent(getApplicationContext(),
                    CollapseActivity.class);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            exit();
        }
    };
 
    /**
     * 打印错误日志
     * 
     * @param ex
     */
    protected void writeErrorLog(Throwable ex) {
        String info = null;
        ByteArrayOutputStream baos = null;
        PrintStream printStream = null;
        try {
            baos = new ByteArrayOutputStream();
            printStream = new PrintStream(baos);
            ex.printStackTrace(printStream);
            byte[] data = baos.toByteArray();
            info = new String(data);
            data = null;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (printStream != null) {
                    printStream.close();
                }
                if (baos != null) {
                    baos.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        Log.d("example", "崩溃信息\n" + info);
        File dir = new File(LOG_DIR);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File file = new File(dir, LOG_NAME);
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(file, true);
            fileOutputStream.write(info.getBytes());
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
 
    }
 
    /**
     * 获取当前日期
     * 
     * @return
     */
    private static String getCurrentDateString() {
        String result = null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd",
                Locale.getDefault());
        Date nowDate = new Date();
        result = sdf.format(nowDate);
        return result;
    }
 
    /**
     * Activity关闭时,删除Activity列表中的Activity对象
     */
    public void removeActivity(Activity a) {
        list.remove(a);
    }
 
    /**
     * 向Activity列表中添加Activity对象
     */
    public void addActivity(Activity a) {
        list.add(a);
    }
 
    /**
     * 关闭Activity列表中的所有Activity
     */
    public void exit() {
        for (Activity activity : list) {
            if (null != activity) {
                activity.finish();
            }
        }
        // 杀死该应用进程
        android.os.Process.killProcess(android.os.Process.myPid());
    }
}

 

 系统错误后要还是要提示用户系统错误.这个是崩溃activity,

<activity
    android:name="com.example.test.CollapseActivity"
    android:theme="@android:style/Theme.Holo.Dialog.MinWidth" >
</activity>

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="horizontal" >
 
    <Button
        android:id="@+id/collapse_restart"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1.0"
        android:text="重启应用" />
 
    <Button
        android:id="@+id/collapse_exit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1.0"
        android:text="退出应用" />
 
</LinearLayout>

 

public class CollapseActivity extends Activity {
    private Button btnRestart, btnExit;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.collapse_activity);
        setTitle("应用崩溃了");
        btnRestart = (Button) findViewById(R.id.collapse_restart);
        btnExit = (Button) findViewById(R.id.collapse_exit);
        btnRestart.setOnClickListener(new OnClickListener() {
 
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(getApplicationContext(),
                        MainActivity.class);
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);
                finish();
            }
        });
        btnExit.setOnClickListener(new OnClickListener() {
 
            @Override
            public void onClick(View v) {
                finish();
            }
        });
    }
}

 

===========================================================Android日志收集上报功能设计与实现(总)================================================================


几乎所有的应用开发者都知道“用户体验”的重要性,要提升用户体验就离不开一个完备的监控和上报系统,这其中日志(包括Crash上报)是最基本的问题跟踪和解决手段。本文接下来将讨论一下如何设计和实现一个完备的日志上报系统。首先看一下类图:

Android 系统奔溃日志在哪里 android崩溃日志_xml

整个日志监控上报大体分为如下几个部分:

 

  1. 封装控制系统原生Log,然后根据不同的级别分别输出到Logcat和文件中,主要有类LogcatLog和FileLog实现。
  2. 收集手机其他信息,在将log上报到服务器时一同上报,这些信息包括Settings信息、DropBox打印的log、应用的SharedPreference、设备分辨率信息等。所有这些被时限为XXColector类,可以根据需要(后台配置控制)进行上传。
  3. 将FileLog信息、Crash信息、以及Collector收集的手机信息上报到服务器。上报的方式主要分为:通过Email发送和通过HTTP(以及后台CGI)发送,当然你也可以选择发送到Google Form等。
  4. Crash异常捕获处理(即:继承实现UncaughtExceptionHandler),有LogCenter中实现。
  5. 良好的可配置信息,即:系统中所有的日志收集、发送方式都是后台可配置的。

 

接下来会对这5部分分别进行介绍。