捕获异常、存sd卡、封装请求头体、加密map值、网络工具类、生成Json、Https协议、传log日志到服务器、app崩溃友好重启

点击打开链接,免积分下载

在集成了统计SDK(友盟统计,百度统计等)之后,有一个非常有利于测试的功能:错误分析!此功能能够将程序在运行中碰到的崩溃(runtimeException)问题反馈到服务器,帮助开发者改善产品,多适配机器。然而在公司android开发中不集成这些SDK,那应该怎么实现这样的功能呢?下面让我们来看下如何使用UncaughtExceptionHandler来捕获异常。

在Android开发中,常常会出现uncheched Exception 导致程序的crash,为了提供良好的用户体验,并对出错的信息进行收集,以便对程序进行改进,提高程序的健壮性。因此,常使用Thread.UncaughtExceptionHandler来进行处理。

首先在CrashHandlerApplication中进行初始化

CrashHandler crashHandler = CrashHandler.getInstance();
		crashHandler.init(this);

然后我们看看在CrashHandler做了什么操作?

public void init(Context context) {
		mContext = context;
		// 获取handler
		mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
		// 实现接口
		Thread.setDefaultUncaughtExceptionHandler(this);
	}

Android系统的“程序异常退出”,给应用的用户体验造成不良影响。为了捕获应用运行时异常并给出友好提示,便可继承UncaughtExceptionHandler类来处理。通过Thread.setDefaultUncaughtExceptionHandler()方法将异常处理类设置到线程上即可。

在本例中第一个界面启动第二个界面之后,在第二个界面有一个bug如下,没有setContentView(R.layout.activity_XXXX);

	super.onCreate(savedInstanceState);

		findViewById(R.id.tv).setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				Toast.makeText(SecondAty.this, "onClick", Toast.LENGTH_SHORT)
						.show();
			}
		});

所以启动项目后,点击进入第二个界面,会有崩溃现象,此刻,在CrashHandler就可以捕获全局异常,捕获之后,会在接口方法uncaughtException中去做处理操作,那么我们是怎么处理的呢?

1、mDefaultHandler.uncaughtException(thread, ex);是说如果用户没有处理,则让系统默认的异常处理器来处理

2、我们会对异常做哪些处理操作?存到sd卡手机log信息,然后将log信息封装为json,然后传入到服务器,去做反馈收集

3、处理完之后呢?一般app退出会给用户良好体验,如果直接退出会感觉很low,我们可以友好的定位到某一个界面或者重启app

// android.os.Process.killProcess(android.os.Process.myPid());
			// System.exit(1);

			// 重新启动程序
			Intent intent = new Intent();
			intent.setClass(mContext, MainActivity.class);
			intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			mContext.startActivity(intent);
			android.os.Process.killProcess(android.os.Process.myPid());

4、然后我们回过头来,看看如何进行log日志处理的?

(4-1)我这个例子是封装为json字符串,传给服务器的,首先根据需求,我们需要构造请求头、请求体

private JsonParameters headParameters = null;
private JsonParameters bodyParameters = null;

(4-2)JsonParameters中就是构造键值对信息,我们这个例子就简单收集下手机信息即可

if (devicemodel != null)
			headParameters.add("devicemodel", CrashHandlerApplication
					.getInstance().getDevice());
		if (appversion != null)
			headParameters.add("appversion", CrashHandlerApplication
					.getInstance().getVersion());
		if (osversion != null)
			headParameters.add("osversion", CrashHandlerApplication
					.getInstance().getOsVersion());

(4-3)log产生后,可以将log日子,输出,在保存到sd卡的同时,进行封装请求体信息

以下代码是将log信息,输出字符串

	Writer writer = new StringWriter();
		PrintWriter printWriter = new PrintWriter(writer);
		// 输出 printStackTrace 堆栈信息
		ex.printStackTrace(printWriter);
		Throwable cause = ex.getCause();
		// 循环着把所有的异常信息写入writer中
		while (cause != null) {
			cause.printStackTrace(printWriter);
			cause = cause.getCause();
		}
		printWriter.close();
		// 将log信息输出字符串
		String result = writer.toString();

如下就是本例子的错误日志输出结果:

 result==>java.lang.RuntimeException: Unable to start activity
	 *         ComponentInfo
	 *         {com.example.crashhandler/com.example.crashhandler.SecondAty}:
	 *         java.lang.NullPointerException: Attempt to invoke virtual method
	 *         'void android.view.View.setOnClickListener(android.view.
	 *         View$OnClickListener)' on a null object reference

(4-4)然后存到sd卡saveCrashToFile方法就不介绍了

(4-5)然后就封装为json的项目需要格式,工具类就不介绍了,一下就是日志log的Json格式

String requestJson = ProtocolUtil.buildJSONPacketBody(headParameters,
				bodyParameters);
 * handljson===:{
		 *  "Request": {
		 * "head": { 07-15
		 *  "devicemodel":
		 * "AOSP on HammerHead", 07-15 14:51:19.698:
		 * "appversion": "1.0", 07-15
		 * "osversion": "5.1.1"
		 *  },
		 *   "body": {
		 *  "context":
		 * "java.lang.RuntimeException: Unable to start activity
		 * ComponentInfo{com
		 * .example.crashhandler\/com.example.crashhandler.SecondAty}:
		 * java.lang.NullPointerException: Attempt to invoke virtual method
		 * 'void android.view.View.setOnClickListener(android.view.
		 * View$OnClickListener)' on a null object reference\n\tat
		 * android.app.ActivityThread
		 * .performLaunchActivity(ActivityThread.java:2325)\n\tat
		 * android.app.ActivityThread
		 * .handleLaunchActivity(ActivityThread.java:2387)\n\tat
		 * android.app.ActivityThread.access$800(ActivityThread.java:151)\n\tat
		 * android
		 * .app.ActivityThread$H.handleMessage(ActivityThread.java:1303)\n\tat
		 * android.os.Handler.dispatchMessage(Handler.java:102)\n\tat
		 * android.os.Looper.loop(Looper.java:135)\n\tat
		 * android.app.ActivityThread.main(ActivityThread.java:5254)\n\tat
		 * java.lang.reflect.Method.invoke(Native Method)\n\tat
		 * java.lang.reflect.Method.invoke(Method.java:372)\n\tat
		 * com.android.internal
		 * .os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)\n\tat
		 * com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)\n\tat
		 * de.robv.android.xposed.XposedBridge.main(Unknown Source)\nCaused by:
		 * java.lang.NullPointerException: Attempt to invoke virtual method
		 * 'void android.view.View.setOnClickListener(android.view.
		 * View$OnClickListener)' on a null object reference\n\tat
		 * com.example.crashhandler.SecondAty.onCreate(SecondAty.java:14)\n\tat
		 * android.app.Activity.performCreate(Activity.java:5990)\n\tat
		 * android.app
		 * .Instrumentation.callActivityOnCreate(Instrumentation.java:
		 * 1106)\n\tat
		 * android.app.ActivityThread.performLaunchActivity(ActivityThread
		 * .java:2278)\n\t... 11 more\njava.lang.NullPointerException: Attempt
		 * to invoke virtual method 'void
		 * android.view.View.setOnClickListener(android
		 * .view.View$OnClickListener)' on a null object reference\n\tat
		 * com.example.crashhandler.SecondAty.onCreate(SecondAty.java:14)\n\tat
		 * android.app.Activity.performCreate(Activity.java:5990)\n\tat
		 * android.app
		 * .Instrumentation.callActivityOnCreate(Instrumentation.java:
		 * 1106)\n\tat
		 * android.app.ActivityThread.performLaunchActivity(ActivityThread
		 * .java:2278)\n\tat
		 * android.app.ActivityThread.handleLaunchActivity(ActivityThread
		 * .java:2387)\n\tat
		 * android.app.ActivityThread.access$800(ActivityThread.java:151)\n\tat
		 * android
		 * .app.ActivityThread$H.handleMessage(ActivityThread.java:1303)\n\tat
		 * android.os.Handler.dispatchMessage(Handler.java:102)\n\tat
		 * android.os.Looper.loop(Looper.java:135)\n\tat
		 * android.app.ActivityThread.main(ActivityThread.java:5254)\n\tat
		 * java.lang.reflect.Method.invoke(Native Method)\n\tat
		 * java.lang.reflect.Method.invoke(Method.java:372)\n\tat
		 * com.android.internal
		 * .os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)\n\tat
		 * com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)\n\tat
		 * de.robv.android.xposed.XposedBridge.main(Unknown Source)\n",
		 * "md5_value":
		 * "911fcae78ea4891892967ffd3d6034a8"
		 * }
		 *  }
		 *   }

(4-6)在JSONUtil才是封装为json对象,而ProtocolUtil只是我公司代码中的数据格式

(4-7)最后就传服务器,判断网络,接受服务器反馈成功即可

######################################以下代码########################################

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/> 

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.crashhandler.MainActivity" >

    <TextView
        android:id="@+id/tv"
        android:gravity="center"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:background="#ccc"
        android:text="first pager" />

</RelativeLayout>

activity_sec.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.crashhandler.MainActivity" >

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="second pager" />

</RelativeLayout>

SecondAty

package com.example.crashhandler;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class SecondAty extends Activity  {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);

		findViewById(R.id.tv).setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				Toast.makeText(SecondAty.this, "onClick", Toast.LENGTH_SHORT)
						.show();
			}
		});

	}

}

MainActivity

package com.example.crashhandler;

public class Crash {

	private String name;
	private int size;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getSize() {
		return size;
	}
	public void setSize(int size) {
		this.size = size;
	}
	public Crash(String name, int size) {
		super();
		this.name = name;
		this.size = size;
	}
	public Crash() {
		super();
		// TODO Auto-generated constructor stub
	}

}
package com.example.crashhandler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import android.R.integer;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		findViewById(R.id.tv).setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				Toast.makeText(MainActivity.this, "onClick", Toast.LENGTH_SHORT)
						.show();
				startActivity(new Intent(MainActivity.this, SecondAty.class));
			}
		});

		Crash crash = new Crash("1", 1);
		Crash crash2 = new Crash("2", 2);
		/**
		 * 对象转json object2json:{"name":"1","size":1}
		 */

		String object2json = JSONUtil.object2json(crash);
		LogUtils.i("Safly", "object2json:" + object2json);
		/**
		 * bean2json:{"name":"1","size":1}
		 *
		 */
		String bean2json = JSONUtil.bean2json(crash);
		LogUtils.i("Safly", "bean2json:" + bean2json);
		/**
		 * list集合转json list2json:[{"name":"1","size":1},{"name":"2","size":2}]
		 */

		ArrayList<Crash> crashs = new ArrayList<Crash>();
		crashs.add(crash);
		crashs.add(crash2);
		String list2json = JSONUtil.list2json(crashs);
		LogUtils.i("Safly", "list2json:" + list2json);
		/**
		 * 数组转json array2json:[{"name":"1","size":1},{"name":"2","size":2}]
		 */

		Crash[] crashsArr = new Crash[] { crash, crash2 };
		String array2json = JSONUtil.array2json(crashsArr);
		LogUtils.i("Safly", "array2json:" + array2json);

		/**
		 * map转json
		 * map2json:{"1":{"name":"1","size":1},"2":{"name":"2","size":2}}
		 */

		Map<Integer, Crash> crashMap = new HashMap<Integer, Crash>();
		crashMap.put(1, crash);
		crashMap.put(2, crash2);
		String map2json = JSONUtil.map2json(crashMap);
		LogUtils.i("Safly", "map2json:" + map2json);

		/**
		 * set转换为json set2json:[{"name":"1","size":1},{"name":"2","size":2}]
		 */

		HashSet<Crash> set = new HashSet<Crash>();
		set.add(crash);
		set.add(crash2);
		String set2json = JSONUtil.set2json(set);
		LogUtils.i("Safly", "set2json:" + set2json);
		/**
		 * objToMap
		 * key= size and value= 1
		 * key= name and value= 1
		 */
		Map<String, Object> objToMap = JSONUtil.objToMap(crash);

		for (String key : objToMap.keySet()) {
			LogUtils.i("Safly",
					"key= " + key + " and value= " + objToMap.get(key));
		}

	}

}

CrashHandlerApplication

package com.example.crashhandler;

import android.app.Application;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;

public class CrashHandlerApplication extends Application {
	private static CrashHandlerApplication instance;

	@Override
	public void onCreate() {
		super.onCreate();
		this.instance = this;
		CrashHandler crashHandler = CrashHandler.getInstance();
		crashHandler.init(this);

	}

	/**
	 * 手机的版本 比如5.1.1
	 */
	public String getOsVersion() {
		return Build.VERSION.RELEASE;
	}

	/**
	 * 手机名称 比如"devicemodel": "AOSP on HammerHead",
	 *
	 * @return
	 */
	public String getDevice() {
		return Build.MODEL;
	}

	public static CrashHandlerApplication getInstance() {

		return instance;
	}

	/**
	 * 项目version
	 *
	 * @return
	 */
	public String getVersion() {
		String version = "0.0.0";
		try {

			PackageInfo packageInfo = instance.getPackageManager()
					.getPackageInfo(instance.getPackageName(), 0);
			version = packageInfo.versionName;
		} catch (NameNotFoundException e) {
			e.printStackTrace();
		}

		return version;
	}

}

CrashHandler

package com.example.crashhandler;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;

import android.content.Context;
import android.content.Intent;
import android.os.Environment;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

public class CrashHandler implements UncaughtExceptionHandler {
	public static final String TAG = "CrashHandler";

	private Context mContext;

	private JsonParameters headParameters = null;
	private JsonParameters bodyParameters = null;
	private String devicemodel = null;
	private String appversion = null;
	private String osversion = null;
	private CrachToServer crachToServer = null;

	private UncaughtExceptionHandler mDefaultHandler;
	// 单例模式
	private static CrashHandler INSTANCE = new CrashHandler();

	private CrashHandler() {
	}

	public static CrashHandler getInstance() {
		return INSTANCE;
	}

	private SimpleDateFormat format = new SimpleDateFormat(
			"yyyy-MM-dd-HH-mm-ss");//

	public void init(Context context) {
		mContext = context;
		// 获取handler
		mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
		// 实现接口
		Thread.setDefaultUncaughtExceptionHandler(this);
	}

	/**
	 * 实现接口方法
	 */
	@Override
	public void uncaughtException(Thread thread, Throwable ex) {
		/**
		 * 07-14 22:44:49.198: E/Safly(20806): mainjava.lang.RuntimeException:
		 * Unable to start activity ComponentInfo{com
		 * .example.crashhandler/com.example.crashhandler.MainActivity}:
		 * java.lang.NullPointerException: Attempt to invoke virtual method
		 * 'void android.view.View.setOnClickListener(android.view.
		 * View$OnClickListener)' on a null object reference
		 */
		Log.e(TAG, thread.getName() + ex.toString());

		if (!handleException(ex) && mDefaultHandler != null) {
			// 如果用户没有处理则让系统默认的异常处理器来处理
			mDefaultHandler.uncaughtException(thread, ex);
		} else {
			try {
				Thread.sleep(3000);
			} catch (InterruptedException e) {
				LogUtils.e(TAG, "error : " + e);
			}
			// 退出程序
			// android.os.Process.killProcess(android.os.Process.myPid());
			// System.exit(1);

			// 重新启动程序
			Intent intent = new Intent();
			intent.setClass(mContext, MainActivity.class);
			intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
			mContext.startActivity(intent);
			android.os.Process.killProcess(android.os.Process.myPid());

		}
	}

	/**
	 * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成
	 *
	 * @param ex
	 * @return
	 */
	private boolean handleException(Throwable ex) {
		if (ex == null) {
			return false;
		}
		new Thread() {
			@Override
			public void run() {
				Looper.prepare();
				Toast.makeText(mContext, "很抱歉,程序出现异常,正在收集日志,即将退出。",
						Toast.LENGTH_LONG).show();
				Looper.loop();
			}
		}.start();
		// 請求头
		headParameters = new JsonParameters();
		collectDeviceInfo(mContext);
		// 请求体
		bodyParameters = new JsonParameters();
		saveCrashInfo2FileToServer(ex);
		return true;
	}

	/**
	 * 收集手机的信息
	 *
	 * @param ctx
	 */
	public void collectDeviceInfo(Context ctx) {
		devicemodel = CrashHandlerApplication.getInstance().getDevice();
		appversion = CrashHandlerApplication.getInstance().getVersion();
		osversion = CrashHandlerApplication.getInstance().getOsVersion();
		if (devicemodel != null)
			headParameters.add("devicemodel", CrashHandlerApplication
					.getInstance().getDevice());
		if (appversion != null)
			headParameters.add("appversion", CrashHandlerApplication
					.getInstance().getVersion());
		if (osversion != null)
			headParameters.add("osversion", CrashHandlerApplication
					.getInstance().getOsVersion());

	}

	/**
	 * 存储sd卡,封装json,并且传服务器
	 *
	 * @param ex
	 * @return
	 */
	private void saveCrashInfo2FileToServer(Throwable ex) {

		/**
		 * 将log信息日志输出
		 */
		Writer writer = new StringWriter();
		PrintWriter printWriter = new PrintWriter(writer);
		// 输出 printStackTrace 堆栈信息
		ex.printStackTrace(printWriter);
		Throwable cause = ex.getCause();
		// 循环着把所有的异常信息写入writer中
		while (cause != null) {
			cause.printStackTrace(printWriter);
			cause = cause.getCause();
		}
		printWriter.close();
		// 将log信息输出字符串
		String result = writer.toString();
		LogUtils.i(TAG, "result==>" + result.toString());

		/**
		 * 存储sd卡
		 */
		saveCrashToFile(result);

		bodyParameters.add("context", result);

		/**
		 * 返回实现指定摘要算法的 MessageDigest 对象。 用于MD5加密的
		 */
		MessageDigest md = null;
		try {
			md = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		// md.digest() 该函数返回值为存放哈希值结果的byte数组
		byte[] b = md.digest(result.getBytes());
		String res = "";
		for (int i = 0; i < b.length; i++) {
			// 为了显示一个byte型的单字节十六进制(两位十六进制表示)的编码
			String tmp = Integer.toHexString(b[i] & 0xFF);
			if (tmp.length() == 1) {
				res += "0" + tmp;
			} else {
				res += tmp;
			}
		}

		// res===:e3ab6e147ebbfc0dcc6bf072a92b63bc
		LogUtils.i(TAG, "md5_value===:" + res);
		bodyParameters.add("md5_value", res);

		/**
		 * 封装json对象
		 */
		String requestJson = ProtocolUtil.buildJSONPacketBody(headParameters,
				bodyParameters);
		LogUtils.i(TAG, "handljson===:" + requestJson);
		if (requestJson != null) {
			crachToServer = new CrachToServer(requestJson);
			new Thread() {
				@Override
				public void run() {
					if (IntenetUtil.getNetworkState(mContext) != 0) {

						LogUtils.i(TAG, "getNetworkState===conected:");
						crachToServer.uploadFile();
					}

				}
			}.start();
		}
	}

	/**
	 * 存储sd
	 *
	 * @param logResult
	 */
	public void saveCrashToFile(String logResult) {

		long timetamp = System.currentTimeMillis();
		String time = format.format(new java.util.Date());
		String fileName = "crash-" + time + "-" + timetamp + ".log";
		if (Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED)) {
			try {
				File dir = new File(Environment.getExternalStorageDirectory()
						.getAbsolutePath() + File.separator + "crash");
				Log.i(TAG, "dir:" + dir.toString());
				// dir:/storage/emulated/0/crash
				if (!dir.exists())
					dir.mkdir();
				FileOutputStream fos = new FileOutputStream(new File(dir,
						fileName));
				fos.write(logResult.toString().getBytes());
				fos.close();
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}

JsonParameters  键值对类

package com.example.crashhandler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class JsonParameters {

	private List<String> list = null;
	private Map<String, Object> map = null;

	public JsonParameters() {
		list = new ArrayList<String>();
		map = new HashMap<String, Object>();
	}

	public void add(String key, Object value) {
		if(list.contains(key)){
			list.remove(key);
		}
		list.add(key);
		map.put(key, value);
	}

	public String getKey(int id) {

		return list.get(id);

	}

	public Object getValue(String key) {

		return map.get(key);
	}

	public int size(){

		return list.size();
	}
	public boolean validate(){

		return list.size() == map.size();
	}
	public void clear(){
		list.clear();
		map.clear();
		list = null;
		map = null;
	}

}

构造特定格式的json类

ProtocolUtil

package com.example.crashhandler;

import android.annotation.SuppressLint;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;

/**
 * simple tools to handle protocol for apps.
 */
public class ProtocolUtil {

	public static final String COLON = ": ";
	public static final String LEFT_ANGLE_BRACKET = "{";
	public static final String RIGHT_ANGLE_BRACKET = "}";

	/**
	 * @param headValues
	 * @param bodyValues
	 */
	public static String buildJSONPacketBody(JsonParameters headValues,
			JsonParameters bodyValues) {
		if ((headValues != null && !headValues.validate())
				|| (bodyValues != null && !bodyValues.validate())) {
			throw new IllegalArgumentException();
		}
		StringBuffer sb = new StringBuffer(LEFT_ANGLE_BRACKET + "\r\n");
		sb.append("\t\"Request\"" + COLON + LEFT_ANGLE_BRACKET + "\r\n");

		sb.append("\t\t\"head\"" + COLON + LEFT_ANGLE_BRACKET + "\r\n");
		for (int i = 0; i < headValues.size(); i++) {

			sb.append(
					"\t\t\t\"" + headValues.getKey(i).toLowerCase() + "\""
							+ COLON).append(
					JSONUtil.object2json(headValues.getValue(headValues
							.getKey(i))));
			if (i != headValues.size() - 1) {
				sb.append(",");
			}
			sb.append("\r\n");
		}
		sb.append("\t\t" + RIGHT_ANGLE_BRACKET + ",\r\n");

		sb.append("\t\t\"body\"" + COLON + LEFT_ANGLE_BRACKET + "\r\n");
		for (int i = 0; i < bodyValues.size(); i++) {

			sb.append(
					"\t\t\t\"" + bodyValues.getKey(i).toLowerCase() + "\""
							+ COLON).append(
					JSONUtil.object2json(bodyValues.getValue(bodyValues
							.getKey(i))));
			if (i != bodyValues.size() - 1) {
				sb.append(",");
			}
			sb.append("\r\n");
		}
		sb.append("\t\t" + RIGHT_ANGLE_BRACKET + "\r\n");

		sb.append("\t" + RIGHT_ANGLE_BRACKET + "\r\n");
		sb.append(RIGHT_ANGLE_BRACKET);
		headValues.clear();
		bodyValues.clear();
		return sb.toString();
	}
}

json分装类

JSONUtil

package com.example.crashhandler;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.google.gson.Gson;
public class JSONUtil {

	/** 对象转换为json */
	public static String object2json(Object obj) {
		StringBuilder json = new StringBuilder();
		if (obj == null) {
			json.append("\"\"");
		} else if (obj instanceof String || obj instanceof Integer || obj instanceof Float || obj instanceof Boolean
				|| obj instanceof Short || obj instanceof Double || obj instanceof Long || obj instanceof BigDecimal
				|| obj instanceof BigInteger || obj instanceof Byte) {
			json.append("\"").append(string2json(obj.toString())).append("\"");
		} else if (obj instanceof Object[]) {
			json.append(array2json((Object[]) obj));
		} else if (obj instanceof List) {
			json.append(list2json((List<?>) obj));
		} else if (obj instanceof Map) {
			json.append(map2json((Map<?, ?>) obj));
		} else if (obj instanceof Set) {
			json.append(set2json((Set<?>) obj));
		} else {
			json.append(bean2json(obj));
		}
		return json.toString();
	}

	/** 对象转换为json */
	public static String bean2json(Object bean) {
		Gson gson = new Gson();
		return gson.toJson(bean);
	}

	/** List转换为json */
	public static String list2json(List<?> list) {
		StringBuilder json = new StringBuilder();
		json.append("[");
		if (list != null && list.size() > 0) {
			for (Object obj : list) {
				json.append(object2json(obj));
				json.append(",");
			}
			json.setCharAt(json.length() - 1, ']');
		} else {
			json.append("]");
		}
		return json.toString();
	}

	/** 数组转换为json */
	public static String array2json(Object[] array) {
		StringBuilder json = new StringBuilder();
		json.append("[");
		if (array != null && array.length > 0) {
			for (Object obj : array) {
				json.append(object2json(obj));
				json.append(",");
			}
			json.setCharAt(json.length() - 1, ']');
		} else {
			json.append("]");
		}
		return json.toString();
	}

	/** map转换为json */
	public static String map2json(Map<?, ?> map) {
		StringBuilder json = new StringBuilder();
		json.append("{");
		if (map != null && map.size() > 0) {
			for (Object key : map.keySet()) {
				json.append(object2json(key));
				json.append(":");
				json.append(object2json(map.get(key)));
				json.append(",");
			}
			json.setCharAt(json.length() - 1, '}');
		} else {
			json.append("}");
		}
		return json.toString();
	}

	/** set转换为json */
	public static String set2json(Set<?> set) {
		StringBuilder json = new StringBuilder();
		json.append("[");
		if (set != null && set.size() > 0) {
			for (Object obj : set) {
				json.append(object2json(obj));
				json.append(",");
			}
			json.setCharAt(json.length() - 1, ']');
		} else {
			json.append("]");
		}
		return json.toString();
	}

	public static String string2json(String s) {
		if (s == null)
			return "";
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < s.length(); i++) {
			char ch = s.charAt(i);
			switch (ch) {
			case '"':
				sb.append("\\\"");
				break;
			case '\\':
				sb.append("\\\\");
				break;
			case '\b':
				sb.append("\\b");
				break;
			case '\f':
				sb.append("\\f");
				break;
			case '\n':
				sb.append("\\n");
				break;
			case '\r':
				sb.append("\\r");
				break;
			case '\t':
				sb.append("\\t");
				break;
			case '/':
				sb.append("\\/");
				break;
			default:
				if (ch >= '\u0000' && ch <= '\u001F') {
					String ss = Integer.toHexString(ch);
					sb.append("\\u");
					for (int k = 0; k < 4 - ss.length(); k++) {
						sb.append('0');
					}
					sb.append(ss.toUpperCase());
				} else {
					sb.append(ch);
				}
			}
		}
		return sb.toString();
	}

	/**
	 * 对象转map
	 *
	 * @param obj
	 * @return
	 */
	public static Map<String, Object> objToMap(Object obj) {

		Map<String, Object> map = new HashMap<String, Object>();
		try {
			/*
			 * BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
			 * PropertyDescriptor[] propertyDescriptors = beanInfo
			 * .getPropertyDescriptors(); for (PropertyDescriptor property :
			 * propertyDescriptors) { String key = property.getName(); //
			 * 过滤class属性 if (!key.equals("class")) { // 得到property对应的getter方法
			 * Method getter = property.getReadMethod(); Object value =
			 * getter.invoke(obj); map.put(key, value); } }
			 */
			Field[] fields = obj.getClass().getDeclaredFields();
			for (Field field : fields) {
				String key = field.getName();
				boolean accessFlag = field.isAccessible();
				field.setAccessible(true);
				Object val = field.get(obj);
				if (val == null) {
					val = "";
				}
				map.put(key, val);
				field.setAccessible(accessFlag);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}

}

CrachToServer网络请求

package com.example.crashhandler;

import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.conn.ssl.SSLSocketFactory;

import android.util.Log;

/**
 * Created by Safly on 2016/7/5.
 *
 */
public class CrachToServer {
	public static final String TAG = "CrashHandler";
	private String urlString = "https://10.0.5.66:7771/ExceptionLog";
	private String content = null;

	public CrachToServer(String requestJson) {
		this.content = requestJson;
	}

	/* 上传文件至Server的方法 */
	public void uploadFile() {
		try {
			LogUtils.d(TAG, "uploadFile");

			byte[] requestStringBytes = content.getBytes("UTF-8");
			URL url = new URL(urlString);
			initHttps();
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();

			conn.setConnectTimeout(5 * 1000);
			conn.setRequestMethod("POST");
			conn.setRequestProperty("Content-length", ""
					+ requestStringBytes.length);
			conn.setRequestProperty(
					"Accept",
					"image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
			conn.setRequestProperty("Accept-Language", "zh-CN");
			conn.setRequestProperty("Referer", urlString);
			conn.setRequestProperty("Charset", "UTF-8");
			conn.setRequestProperty(
					"User-Agent",
					"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");
			conn.setRequestProperty("Connection", "Keep-Alive");
			Log.e(TAG, "HttpsURLConnection");
			conn.connect();

			OutputStream outputStream = conn.getOutputStream();
			outputStream.write(requestStringBytes);
			outputStream.close();
			/* 服务器返回的响应码 */
			int code = conn.getResponseCode();
			if (code == 200) {
				LogUtils.d(TAG, "response code:" + code);
			} else {
				LogUtils.d(TAG, "response code:" + code);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private void initHttps() {
		try {
			KeyStore trustStore = KeyStore.getInstance(KeyStore
					.getDefaultType());
			trustStore.load(null, null);

			SSLSocketFactoryEx sf = new SSLSocketFactoryEx(trustStore);
			HttpsURLConnection.setDefaultSSLSocketFactory(sf.getSSLContext()
					.getSocketFactory());

			HttpsURLConnection
					.setDefaultHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
		} catch (Exception e) {
		}
	}

	static class SSLSocketFactoryEx extends SSLSocketFactory {

		SSLContext sslContext = SSLContext.getInstance("TLS");

		public SSLSocketFactoryEx(KeyStore truststore)
				throws NoSuchAlgorithmException, KeyManagementException,
				KeyStoreException, UnrecoverableKeyException {
			super(truststore);

			TrustManager tm = new X509TrustManager() {

				public java.security.cert.X509Certificate[] getAcceptedIssuers() {
					return null;
				}

				@Override
				public void checkClientTrusted(
						java.security.cert.X509Certificate[] chain,
						String authType)
						throws java.security.cert.CertificateException {
				}

				@Override
				public void checkServerTrusted(
						java.security.cert.X509Certificate[] chain,
						String authType)
						throws java.security.cert.CertificateException {

				}
			};
			sslContext.init(null, new TrustManager[] { tm }, null);
		}

		@Override
		public Socket createSocket(Socket socket, String host, int port,
				boolean autoClose) throws IOException, UnknownHostException {
			return sslContext.getSocketFactory().createSocket(socket, host,
					port, autoClose);
		}

		@Override
		public Socket createSocket() throws IOException {
			return sslContext.getSocketFactory().createSocket();
		}

		public SSLContext getSSLContext() {
			return sslContext;
		}
	}

}

最后还有网络状态类,和log日志类

IntenetUtil

package com.example.crashhandler;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.telephony.TelephonyManager;

public class IntenetUtil {

	// 没有网络连接
	public static final int NETWORN_NONE = 0;
	// wifi连接
	public static final int NETWORN_WIFI = 1;
	// 手机网络数据连接类型
	public static final int NETWORN_2G = 2;
	public static final int NETWORN_3G = 3;
	public static final int NETWORN_4G = 4;
	public static final int NETWORN_MOBILE = 5;

	/**
	 * 获取当前网络连接类型
	 *
	 * @param context
	 * @return
	 */
	public static int getNetworkState(Context context) {
		// 获取系统的网络服务
		ConnectivityManager connManager = (ConnectivityManager) context
				.getSystemService(Context.CONNECTIVITY_SERVICE);

		// 如果当前没有网络
		if (null == connManager)
			return NETWORN_NONE;

		// 获取当前网络类型,如果为空,返回无网络
		NetworkInfo activeNetInfo = connManager.getActiveNetworkInfo();
		if (activeNetInfo == null || !activeNetInfo.isAvailable()) {
			return NETWORN_NONE;
		}

		// 判断是不是连接的是不是wifi
		NetworkInfo wifiInfo = connManager
				.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
		if (null != wifiInfo) {
			NetworkInfo.State state = wifiInfo.getState();
			if (null != state)
				if (state == NetworkInfo.State.CONNECTED
						|| state == NetworkInfo.State.CONNECTING) {
					return NETWORN_WIFI;
				}
		}

		// 如果不是wifi,则判断当前连接的是运营商的哪种网络2g、3g、4g等
		NetworkInfo networkInfo = connManager
				.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);

		if (null != networkInfo) {
			NetworkInfo.State state = networkInfo.getState();
			String strSubTypeName = networkInfo.getSubtypeName();
			if (null != state)
				if (state == NetworkInfo.State.CONNECTED
						|| state == NetworkInfo.State.CONNECTING) {
					switch (activeNetInfo.getSubtype()) {
					// 如果是2g类型
					case TelephonyManager.NETWORK_TYPE_GPRS: // 联通2g
					case TelephonyManager.NETWORK_TYPE_CDMA: // 电信2g
					case TelephonyManager.NETWORK_TYPE_EDGE: // 移动2g
					case TelephonyManager.NETWORK_TYPE_1xRTT:
					case TelephonyManager.NETWORK_TYPE_IDEN:
						return NETWORN_2G;
						// 如果是3g类型
					case TelephonyManager.NETWORK_TYPE_EVDO_A: // 电信3g
					case TelephonyManager.NETWORK_TYPE_UMTS:
					case TelephonyManager.NETWORK_TYPE_EVDO_0:
					case TelephonyManager.NETWORK_TYPE_HSDPA:
					case TelephonyManager.NETWORK_TYPE_HSUPA:
					case TelephonyManager.NETWORK_TYPE_HSPA:
					case TelephonyManager.NETWORK_TYPE_EVDO_B:
					case TelephonyManager.NETWORK_TYPE_EHRPD:
					case TelephonyManager.NETWORK_TYPE_HSPAP:
						return NETWORN_3G;
						// 如果是4g类型
					case TelephonyManager.NETWORK_TYPE_LTE:
						return NETWORN_4G;
					default:
						// 中国移动 联通 电信 三种3G制式
						if (strSubTypeName.equalsIgnoreCase("TD-SCDMA")
								|| strSubTypeName.equalsIgnoreCase("WCDMA")
								|| strSubTypeName.equalsIgnoreCase("CDMA2000")) {
							return NETWORN_3G;
						} else {
							return NETWORN_MOBILE;
						}
					}
				}
		}
		return NETWORN_NONE;
	}
}

LogUtils

package com.example.crashhandler;

import android.util.Log;

public class LogUtils {

	private static final String HEAD_TAG = "GLauncher_";

	public static void v(Class<?> clazz,String logInfo){
		i(clazz.getSimpleName(),logInfo);
	}

	public static void v(String tag,String logInfo){
		printLogInfo(tag,logInfo,Log.VERBOSE);
	}	

	public static void i(Class<?> clazz,String logInfo){
		i(clazz.getSimpleName(),logInfo);
	}

	public static void i(String tag,String logInfo){
		printLogInfo(tag,logInfo,Log.INFO);
	}	

	public static void d(Class<?> clazz,String logInfo){
		d(clazz.getSimpleName(),logInfo);
	}

	public static void d(String tag,String logInfo){
		printLogInfo(tag,logInfo,Log.DEBUG);
	}

	public static void w(Class<?> clazz,String logInfo){
		w(clazz.getSimpleName(),logInfo);
	}

	public static void w(String tag,String logInfo){
		printLogInfo(tag,logInfo,Log.WARN);
	}

	public static void e(Class<?> clazz,String logInfo){
		e(clazz.getSimpleName(),logInfo);
	}

	public static void e(String tag,String logInfo){
		printLogInfo(tag,logInfo,Log.ERROR);
	}

	public static void printLogInfo(String tag,String logInfo,int style){
		switch (style) {
		case Log.VERBOSE:
			Log.v(HEAD_TAG + tag,logInfo);
			break;
		case Log.INFO:
			Log.i(HEAD_TAG + tag,logInfo);
			break;
		case Log.DEBUG:
			Log.d(HEAD_TAG + tag,logInfo);
			break;
		case Log.ERROR:
			Log.e(HEAD_TAG + tag,logInfo);
			break;
		case Log.WARN:
			Log.w(HEAD_TAG + tag,logInfo);
			break;
		}
	}
}
时间: 2024-10-26 10:26:23

捕获异常、存sd卡、封装请求头体、加密map值、网络工具类、生成Json、Https协议、传log日志到服务器、app崩溃友好重启的相关文章

Android设备网络、屏幕尺寸、SD卡、本地IP、存储空间等信息获取工具类

Android设备网络.屏幕尺寸.SD卡.本地IP.存储空间.服务.进程.应用包名等信息获取的整合工具类. 1 package com.qiyu.ddb.util; 2 3 import android.annotation.SuppressLint; 4 import android.annotation.TargetApi; 5 import android.app.Activity; 6 import android.app.ActivityManager; 7 import androi

【Android平台中的安全编程】の #00-不要在外部存储(SD卡)中存放未加密的敏感信息

本文翻译自https://www.securecoding.cert.org/confluence/display/java/DRD00-J.+Do+not+store+sensitive+information+on+external+storage+%28SD+card%29+unless+encrypted+first,有增删改. Android提供了几种保存持久化应用数据的选择,其中之一就是外部存储(/sdcard, /mnt/sdcard).外部存储包括设备内部的微型或标准大小的SD卡

android读写SD卡封装的类

参考了网上的一些资源代码,FileUtils.java: package com.example.filereadwrite; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOut

WebAPi获取请求头中对应键值

/// <summary> /// 依据键获取请求头中值数据 /// </summary> /// <param name="request"></param> /// <param name="key"></param> /// <returns></returns> public static string GetHeader(this HttpRequestMess

封装网络工具类

// HFNetWorkTools.h #import <Foundation/Foundation.h> typedef void(^callBack)(); @class AFHTTPSessionManager; @interface HFNetWorkTools : NSObject @property(nonatomic,copy)AFHTTPSessionManager *manager; @property(nonatomic,copy)callBack block; + (in

封装一个List集合和datatable相互转换的工具类

/// <summary> /// List转换为DataTable对象 /// </summary> public class ListTranTableModel { /// <summary> /// 新增的列名称 /// </summary> public string addColumName { get; set; } /// <summary> /// 新增列的默认信息 /// </summary> public Tab

Android推断是否有sd卡

推断手机上是否有SD卡存在.作为经常用法,写到工具类里,用时直接调用.代码例如以下: public static boolean hasSdcard(){ String state = Environment.getExternalStorageState(); if(state.equals(Environment.MEDIA_MOUNTED)){ return true; }else{ return false; } }

第36章 SDIO—SD卡读写测试

第36章     SDIO-SD卡读写测试 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/firege 本章参考资料:<STM32F4xx参考手册>.<STM32F4xx规格书>.库帮助文档<stm32f4xx_dsp_stdperiph_lib_um.chm>以及SD简易规格文件<Physical Layer Simplified Specificatio

CE SD卡驱动开发(Zylonite)(转)

2008-06-05 09:45 1. WINCE 下的SD卡驱动架构 Wince 下SD卡驱动协议栈组成 : HOST硬件底层部分 (主控制端驱动)       SDHC_XXX.DLL BUS 中间逻辑命令层 (总线驱动)         SDBUS.DLL CLIENT上层(客户端驱动)                SDMEMORY.DLL 主控制端驱动    主控制端驱动控制包含主控制器硬件,遵循主控制端驱动接口,它被用于总线驱动通信和设置操作参数.主控制器驱动接口提供一个硬件提取层,