Android学习能力之统计日志上传设计

来源:互联网 发布:惊天大逆转知乎 编辑:程序博客网 时间:2024/05/03 18:09

一款软件就像一个孩子,不断的在学习,在探索,当孩子犯下错误的时候,我们可以去包容,当孩子犯不改的时候,获取他就不再让人喜欢,甚至是去抛弃他。人之常情的问题,也是做软件的我们需要去考虑的问题。同样孩子的成长速度和懂事程度也是我们非常关注的。

本章讲述Android日志上传功能,更快的更准确的将孩子的错误通知给我们,我们帮助孩子改正它的错误。

日志上传的过程

1.日志统计和日志存储

    public static void record(Context context, String ex) {        if (context == null) {            return;        }        PrintStream printStream = null;        ByteArrayOutputStream bos = null;        try {            bos = new ByteArrayOutputStream(256);            printStream = new PrintStream(bos);            printStream.print(ex);            JSONObject createJson = createJson(context, new String(bos.toByteArray()));//(1)做json            DBManager.getInstance(context).addCrashLog(createJson.toString());//(2)存储数据信息            Prefs.setPrefBoolean(PrefsContants.IS_NEEDED_UPLOAD, true));        } catch (Exception e) {            Log.e("CrashUploadUtils", "writeLog", e);        } finally {            closeQuietly(printStream);//(3)            closeQuietly(bos);        }    }

由上面代码可以看出我们将数据字符串传入统计记录后,首先做成json数据,如步骤(1);其次将数据存入数据库,如步骤(2);最后关闭我们的数据流,如步骤三。

(1)做成json数据

    private static JSONObject createJson(Context context, String log) {        JSONObject object = null;        try {            object = new JSONObject();            object.put("type", "crash");            JSONObject data = new JSONObject();            data.put("log", log);            data.put("uk", AccountManager.getUK(context));            data.put("version", IMManager.getVersion());            data.put("trigger_id", Utility.getTriggerId(context));            if (!TextUtils.isEmpty(android.os.Build.VERSION.RELEASE)) {                data.put("os", android.os.Build.VERSION.RELEASE);            }            if (!TextUtils.isEmpty(android.os.Build.MODEL)) {                data.put("device_model","mode" + android.os.Build.MODEL);            }            if (!TextUtils.isEmpty(android.os.Build.MANUFACTURER)) {                data.put("manufacture",android.os.Build.MANUFACTURER);            }            object.put("data", data);            object.put("ts", System.currentTimeMillis());        } catch (JSONException e) {            Log.e("CrashUploadUtils", "createJson", e);        }        return object;    }

内容这里可以忽略,自己放入就好。

(2)添加数据库

    public void addCrashLog(String log) {        synchronized (mSyncLock) {            ContentValues values = new ContentValues();            values.put(CrashLogColumns.COLUMN_COTENT, log);            insert(TableDefine.DB_TABLE_CRASH_LOG, values);        }    }

其中insert函数,读者要自己写了。
(3)关闭数据流

    private static void closeQuietly(OutputStream os) {        if (os != null) {            try {                os.close();            } catch (IOException e) {                Log.e("CrashUploadUtils", "closeQuietly", e);            }        }    }

上面我们完成了,日志的统计和信息的存储,其中日志的存储看上面添加数据库的过程。

2.日志上传

日志上传是该功能的关键步骤,涉及的问题有:怎么上传,什么时候上传,什么网络环境下上传?
日志上传功能

    private static void upLoad(Context context) {        Pair<Long, JSONArray> log = getCrashLog(context);//1获取数据库中异常信息        if (log == null || log.first < 0) {            return;        }        StringBuilder builder = new StringBuilder();        builder.append("device_id=" + Utility.getDeviceType(context));        builder.append("&appid=" + AccountManager.getAppid(context));        builder.append("&statistic=" + log.second.toString());        String jsonResult = null;        try {//2上传异常信息            jsonResult = HttpUtility.doUploadPost(url, builder.toString().getBytes("utf-8"));        } catch (UnsupportedEncodingException e) {            Log.e("CrashUploadUtils", "upLoadCrash UnsupportedEncodingException", e);        }        if (jsonResult == null) {            Log.e("CrashUploadUtils", "upload crash log failed!!");            return;        }        try {            JSONObject jsonObject = new JSONObject(jsonResult);            int errorCode = jsonObject.optInt("err_code");            String msg = jsonObject.optString("msg");//根据网络结果删除已经上传过的信息,并更新上传记录时间            if (errorCode == OK) {//3删除上传过的信息                int result = DBManager.getInstance(context).deleteLogBeforeId(log.first);                if (result > 0) {//4更新上传时间                    updateUploadTime(context, System.currentTimeMillis());                }            }        } catch (JSONException e) {            Log.e("CrashUploadUtils", "upLoadCrash JSONException", e);        }    }

(1)获取数据库中异常信息

    public static Pair<Long, JSONArray> getCrashLog(Context context) {        return DBManager.getInstance(context).getLog();    }    public Pair<Long, JSONArray> getLog() {        synchronized (mSyncLock) {            CrashLogParse parse = new CrashLogParse();            query(TableDefine.DB_TABLE_CRASH_LOG, null, null, null, null, null, CrashLogColumns._ID + " asc ", " 10 ",                    parse);            return parse.getResult();        }    }    class CrashLogParse implements CursorParse {        Pair<Long, JSONArray> result = null;        @Override        public void parseCursor(Cursor cursor) {            if (cursor != null) {                long maxid = -1;                long id = -1;                String log = null;                JSONArray array = null;                try {                    array = new JSONArray();                    while (cursor.moveToNext()) {                        id = cursor.getLong(cursor.getColumnIndex(CrashLogColumns._ID));                        log = cursor.getString(cursor.getColumnIndex(CrashLogColumns.COLUMN_COTENT));                        if (id > maxid) {                            maxid = id;                        }                        array.put(new JSONObject(log));                    }                } catch (JSONException e) {                    array = null;                    e.printStackTrace();                }                if (array != null) {                    result = new Pair<Long, JSONArray>(maxid, array);                }            }        }        @Override        public Pair<Long, JSONArray> getResult() {            return result;        }    }

获取到相应的数据库信息,获取的是其中的所有记录和最大id值。
(2)上传异常信息

    public static String doUploadPost(String httpUrl, byte[] byteToUpload) {        if (byteToUpload == null || byteToUpload.length < 0) {            return null;        }        URL url;        HttpURLConnection httpUrlConnection = null;        try {            url = new URL(httpUrl);            httpUrlConnection = (HttpURLConnection) url.openConnection();            httpUrlConnection.setRequestMethod("POST");            httpUrlConnection.setDoInput(true);            // Post mode            httpUrlConnection.setDoOutput(true);            httpUrlConnection.setConnectTimeout(30 * 1000);            httpUrlConnection.setReadTimeout(30 * 1000);            httpUrlConnection.setUseCaches(false);            OutputStream outputStream = httpUrlConnection.getOutputStream();            outputStream.write(byteToUpload);            outputStream.flush();            outputStream.close();            // while (offset < byteLength) {            // bufferOutStream.write(byteToUpload);            // offset += length;            // }            int response = httpUrlConnection.getResponseCode();            if (Constants.isDebugMode()) {                Log.e("HttpUtility", "upload response:" + response);            }            if (response != HttpURLConnection.HTTP_OK) {                return null;            }            return dealResponseResult(httpUrlConnection.getInputStream());        } catch (MalformedURLException e) {            Log.e("HttpUtility", "MalformedURLException doUploadPost", e);        } catch (IOException e) {            Log.e("HttpUtility", "IOException doUploadPost", e);        } catch (Exception e) {            Log.e("HttpUtility", "Exception doUploadPost", e);        } finally {            if (httpUrlConnection != null) {                httpUrlConnection.disconnect();            }        }        return null;    }    /**     * @param inputStream     * @return     */    public static String dealResponseResult(InputStream inputStream) {        String resultData = null; // 存储处理结果        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();        byte[] data = new byte[1024];        int len = 0;        int offset = 0;        try {            while ((len = inputStream.read(data)) != -1) {                byteArrayOutputStream.write(data, offset, len);                offset += len;            }            resultData = new String(byteArrayOutputStream.toByteArray());            if (Constants.isDebugMode()) {                Log.d("HttpUtility", "resultData:" + resultData);            }        } catch (IOException e) {            Log.e("HttpUtility", "IOException dealResponseResult", e);        }        return resultData;    }

(3)删除上传过的信息

    public int deleteLogBeforeId(long id) {        synchronized (mSyncLock) {            return delete(TableDefine.DB_TABLE_CRASH_LOG, CrashLogColumns._ID + " <=?",                    new String[] { String.valueOf(id) });        }    }

(4)更新上传时间
其中定义了上传时间间隔,不能上传过于频繁,造成服务压力,基本几个在10分钟左右,这里时间自己可以设定

    private static boolean updateUploadTime(Context context, long time) {        if (time > lastUpdateTime) {            lastUpdateTime = time;            return Utility.writeLongData(context, key, lastUpdateTime);        }        return false;    }    private static long getUpdateTime(Context context) {        if (lastUpdateTime == -1) {            lastUpdateTime = Utility.readLongData(context, key, -1);        }        return lastUpdateTime;    }    public static boolean isNeedToUpload(Context context, long time) {        return System.currentTimeMillis() - getUpdateTime(context) > time;    }

(5)开始上传

    public static void statUpload(final Context context) {        if(!Prefs.getPrefBoolean(PrefsContants.IS_NEEDED_UPLOAD, false))){            return;        }        if(!isNeedToUpload){            return;        }        new Thread(new Runnable() {            @Override            public void run() {                upLoadCrash(context);            }        }).start();    }

以后就可以通过在服务端查看日志去快速修改app所犯下的错误。

1 1
原创粉丝点击