简单介绍
一个好的Android应用开发框架,能够加快Android开发速度,今天笔记基于很多开源项目自写了一款Android应用框架。
内容
框架包含:界面管理(Activity管理)、数据库操作(orm框架、加密等)、http交互、缓存管理、下载管理、路径管理、日志输出、网络管理、系统命令、加解密、stl容器、任务管理、奔溃管理、存储管理、其他辅助管理…。
解决思路例如以下:
界面管理:使用Stack记录Activity的执行轨迹,并在每一个Activity加入一个广播处理自己定义事件。
private static Stack<Activity> mActivityStack;//进行Activity执行记录数据库管理:对数据库的操作要求orm框架、加解密等。採用的是greendao和sqlcrypt开源项目解决。
http交互:实现http交互方式有同步、异步操作。採用的是android-async-http开源项目解决。
缓存管理:实现缓存方式有内存缓存、磁盘缓存。当中内存缓存仅仅针对图片处理。磁盘缓存是针对某文件夹。实现的方式有:先进先出、最大量、使用频率等。
下载管理:下载管理方式有多线程下载、单线程下载。
路径管理:简单的说就是对程序的文件夹管理,分图片、视频、音频、缓存文件夹等。
日志输出:基于Log的管理(分调式、公布模式和文件输出、log输出)。
网络管理:2G、3G、4G等联网方式不同的管理和监听。
系统命令:直接命令执行。
加解密:aes、base64、des、md5等加密方式。
stl容器:重写stl部分容器。
任务管理:基于AsyncTask任务的管理。
奔溃管理:捕捉奔溃信息,并提供发送接口。採用的是acra方法解决。
存储管理:主要是SharedPreferences和Properties的管理。
其他辅助管理:版本号、内存、手机格式、字符串操作……等等。
项目如图:
效果如图:
+
相关測试代码:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.test_tree); TFilePathManager.getInstance().initConfig(null); // 默认文件夹(下载�?图片、视频�?缓存等目�?// 优先考虑内存条,其次手机内存�? } public void onClickTestPath(View view) { // 測试路径 TFilePathManager.getInstance().initConfig( Environment.getExternalStorageDirectory().getPath() + File.pathSeparator + "test"); // 程序文件夹里面分了图片、缓存区、下载图、音频区、视频区 TFilePathManager.getInstance().getAppPath(); TFilePathManager.getInstance().getAudioPath(); TFilePathManager.getInstance().getCachePath(); TFilePathManager.getInstance().getDownloadPath(); TFilePathManager.getInstance().getImagePath(); } public void onClickTestLog(View view) { // 測试日志 TLog.enablePrintToFileLogger(true); for (int i = 0; i < 100; i++) TLog.i(TAG, "123456" + i); // TLog.release(); //关闭程序可释�?
// 日志是放在程序文件夹下 // TLog.enableIgnoreAll(enable); // TLog.enableIgnoreWarn(enable); } public void onClickTestTActivity(View view) { // 測试TActivity Intent intent = new Intent(); intent.setClass(this, TestTActivity.class); startActivity(intent); } public void onClickTestHttp1(View view) { // 測试Http1 Intent intent = new Intent(); intent.setClass(this, TestHttp1.class); startActivity(intent); } public void onClickTestHttp2(View view) { // 測试Http2 Intent intent = new Intent(); intent.setClass(this, TestHttp2.class); startActivity(intent); } public void onClickTestThreadsdown(View view) { // 測试多线程下载 Intent intent = new Intent(); intent.setClass(this, TestDowns.class); startActivity(intent); } public void onClickTestCrash(View view) { // 崩溃 int result = 1 / 0; } public void onClickTestSqlEncrypt(View view) { // 測试sql加密 Intent intent = new Intent(); intent.setClass(this, TestSqlEncrypt.class); startActivity(intent); } public void onClickTestDAO(View view) { // 測试orm数据库 Intent intent = new Intent(); intent.setClass(this, TestDAO.class); startActivity(intent); } public void onClickTestDB(View view) { // 測试Think数据库 Intent intent = new Intent(); intent.setClass(this, TestDB.class); startActivity(intent); } public void onClickTestCache(View view) { // 測试缓存 Intent intent = new Intent(); intent.setClass(this, TestCache.class); startActivity(intent); } public void onClickTConfig(View view) { // 測试配置信息 TPreferenceConfig.getInstance().initConfig(this); TPropertiesConfig.getInstance().initConfig(this); TIConfig iConfig = TPreferenceConfig.getInstance(); iConfig.setBoolean("123", true); boolean result = iConfig.getBoolean("123", false); iConfig = TPropertiesConfig.getInstance(); iConfig.setBoolean("1234", true); result = iConfig.getBoolean("1234", false); } public void onClickEncryption(View view) { // 測试加密 String src = "banketree@qq.com"; String encrypted = ""; String key = "banketree"; try { encrypted = TAes.encrypt(key, src); String tempString = TAes.decrypt(key, encrypted); encrypted = TBase64.encode(src.getBytes()); tempString = TBase64.decode(encrypted).toString(); encrypted = TDes.encrypt(key, src); tempString = TDes.decrypt(key, encrypted); TLog.i(this, tempString); } catch (Exception e) { e.printStackTrace(); } } public void onClickZip(View view) { // 測试解压缩 try { TCompressUtils.compressJar(""); TCompressUtils.compressZip(""); TCompressUtils.uncompressJar(""); TCompressUtils.uncompressZip(""); } catch (Exception e) { e.printStackTrace(); } }
奔溃处理回调:
@Override public void onAppCrash(String crashFile) { TLog.d(TAG, "Creating Dialog for " + crashFile); Intent dialogIntent = new Intent(this, TestCrash.class); dialogIntent.putExtra(TCrash.EXTRA_REPORT_FILE_NAME, crashFile); dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(dialogIntent); }
mMemoryCacheSize = 2 * 1024 * 1024;// 2M mDiscCacheSize = 2 * 1024 * 1024;// 2M mDiscCacheFileCount = 100;// 一百个文件 mMemoryCache = TCacheManager.createLruMemoryCache(mMemoryCacheSize); try { mDiscCache1 = TCacheManager.createReserveDiscCache(TFilePathManager .getInstance().getCachePath(), "test"); } catch (Exception e) { e.printStackTrace(); } try { mDiscCache2 = TCacheManager.createFileCountLimitedDiscCache( mDiscCacheFileCount, TFilePathManager.getInstance() .getCachePath()); } catch (Exception e) { e.printStackTrace(); }
try { Drawable demo = getResources().getDrawable(R.drawable.ic_launcher); Bitmap bitmap = ((BitmapDrawable) demo).getBitmap(); if (arg0 == mTest1Button) { mMemoryCache.put("123", bitmap); mMemoryCache.put("1234", bitmap); mMemoryCache.get("123"); mMemoryCache.get("1234"); } else if (arg0 == mTest2Button) { mDiscCache1.put("123", mContext.getCacheDir()); mDiscCache1.get("123"); } else if (arg0 == mTest3Button) { mDiscCache2.put("123", mContext.getCacheDir()); mDiscCache2.get("123"); } } catch (Exception e) { makeText(e.getMessage()); }
Activity之间的通信:
@Override public void onClick(View arg0) { if (testComparatorButton == arg0) { Log.i("", ""); UIBroadcast.sentEvent(mContext, 1001, 1002, ""); } } @Override public void processEvent(Intent intent) { super.processEvent(intent); int mainEvent = intent.getIntExtra(UIBroadcast.MAINEVENT, -1); // 主事�?int subEvent = intent.getIntExtra(UIBroadcast.EVENT, -1);// 次事�? makeText("哈哈触发�?
" + mainEvent + subEvent);// 每一个Activity可接收广�? }
Http同步异步请求:
if (view == mCancelButton) { mTAsyncHttpClient.cancelRequests(this, true); mTAsyncHttpClient.cancelAllRequests(true); } else if (view == mGetButton) { url = "https://httpbin.org/get"; mTAsyncHttpClient.get(url, new AsyncHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { debugHeaders(headers); debugStatusCode(statusCode); debugResponse(new String(responseBody)); } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { debugHeaders(headers); debugStatusCode(statusCode); if (responseBody != null) { debugResponse(new String(responseBody)); } TLog.e(this, error.getMessage()); } @Override public void onProgress(int bytesWritten, int totalSize) { super.onProgress(bytesWritten, totalSize); } @Override public void onRetry(int retryNo) { makeText(String.format("Request is retried, retry no. %d", retryNo)); } }); } else if (view == mPostButton) { url = "http://httpbin.org/post"; mTAsyncHttpClient.post(mContext, url, getRequestHeaders(), getRequestEntity(), null, new AsyncHttpResponseHandler() { @Override public void onStart() { } @Override public void onSuccess(int statusCode, Header[] headers, byte[] response) { debugHeaders(headers); debugStatusCode(statusCode); debugResponse(new String(response)); } @Override public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) { debugHeaders(headers); debugStatusCode(statusCode); debugThrowable(e); if (errorResponse != null) { debugResponse(new String(errorResponse)); } } }); } else if (view == mPutButton) { url = "http://httpbin.org/put"; mTAsyncHttpClient.put(this, url, getRequestHeaders(), getRequestEntity(), null, new AsyncHttpResponseHandler() { @Override public void onStart() { } @Override public void onSuccess(int statusCode, Header[] headers, byte[] response) { debugHeaders(headers); debugStatusCode(statusCode); debugResponse(new String(response)); } @Override public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) { debugHeaders(headers); debugStatusCode(statusCode); debugThrowable(e); if (errorResponse != null) { debugResponse(new String(errorResponse)); } } }); } else if (view == mDeleteButton) { url = "http://httpbin.org/delete"; mTAsyncHttpClient.delete(this, url, getRequestHeaders(), null, new AsyncHttpResponseHandler() { @Override public void onStart() { } @Override public void onSuccess(int statusCode, Header[] headers, byte[] response) { debugHeaders(headers); debugStatusCode(statusCode); debugResponse(new String(response)); } @Override public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) { debugHeaders(headers); debugStatusCode(statusCode); debugThrowable(e); if (errorResponse != null) { debugResponse(new String(errorResponse)); } } }); } else if (view == mFileButton) { url = "https://httpbin.org/robots.txt"; mTAsyncHttpClient.get(this, url, getRequestHeaders(), null, new FileAsyncHttpResponseHandler(this) { @Override public void onStart() { } @Override public void onSuccess(int statusCode, Header[] headers, File response) { debugHeaders(headers); debugStatusCode(statusCode); debugFile(response); } @Override public void onFailure(int statusCode, Header[] headers, Throwable throwable, File file) { debugHeaders(headers); debugStatusCode(statusCode); debugThrowable(throwable); debugFile(file); } private void debugFile(File file) { if (file == null || !file.exists()) { debugResponse("Response is null"); return; } try { debugResponse(file.getAbsolutePath() + " " + TFileUtils.getStringFromFile(file)); } catch (Throwable t) { TLog.e(TAG, "Cannot debug file contents" + t.getMessage()); } if (!deleteTargetFile()) { TLog.d(TAG, "Could not delete response file " + file.getAbsolutePath()); } } }); } else if (view == mGZipButton) { url = "http://httpbin.org/gzip"; mTAsyncHttpClient.get(this, url, null, null, new BaseJsonHttpResponseHandler<SampleJSON>() { @Override public void onStart() { } @Override public void onSuccess(int statusCode, Header[] headers, String rawJsonResponse, SampleJSON response) { debugHeaders(headers); debugStatusCode(statusCode); if (response != null) { debugResponse(rawJsonResponse); } } @Override public void onFailure(int statusCode, Header[] headers, Throwable throwable, String rawJsonData, SampleJSON errorResponse) { debugHeaders(headers); debugStatusCode(statusCode); debugThrowable(throwable); if (errorResponse != null) { debugResponse(rawJsonData); } } @Override protected SampleJSON parseResponse(String rawJsonData, boolean isFailure) throws Throwable { return null; // return new ObjectMapper().readValues( // new JsonFactory().createParser(rawJsonData), // SampleJSON.class).next(); } }); } else if (view == mRedirect302Button) { url = "http://httpbin.org/redirect/6"; HttpClient client = mTAsyncHttpClient.getHttpClient(); if (client instanceof DefaultHttpClient) { // enableRedirects/enableRelativeRedirects/enableCircularRedirects mTAsyncHttpClient.setEnableRedirects(true, true, true); } mTAsyncHttpClient.get(url, new AsyncHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { debugHeaders(headers); debugStatusCode(statusCode); debugResponse(new String(responseBody)); } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { debugHeaders(headers); debugStatusCode(statusCode); if (responseBody != null) { debugResponse(new String(responseBody)); } TLog.e(this, error.getMessage()); } @Override public void onProgress(int bytesWritten, int totalSize) { super.onProgress(bytesWritten, totalSize); } @Override public void onRetry(int retryNo) { makeText(String.format("Request is retried, retry no. %d", retryNo)); } }); } else if (view == mJsonButton) { url = "http://httpbin.org/headers"; mTAsyncHttpClient.get(this, url, null, null, new BaseJsonHttpResponseHandler<SampleJSON>() { @Override public void onStart() { } @Override public void onSuccess(int statusCode, Header[] headers, String rawJsonResponse, SampleJSON response) { debugHeaders(headers); debugStatusCode(statusCode); if (response != null) { debugResponse(rawJsonResponse); } } @Override public void onFailure(int statusCode, Header[] headers, Throwable throwable, String rawJsonData, SampleJSON errorResponse) { debugHeaders(headers); debugStatusCode(statusCode); debugThrowable(throwable); if (errorResponse != null) { debugResponse(rawJsonData); } } @Override protected SampleJSON parseResponse(String rawJsonData, boolean isFailure) throws Throwable { return null; // return new ObjectMapper().readValues( // new JsonFactory().createParser(rawJsonData), // SampleJSON.class).next(); } }); } else if (view == mLoginButton) { url = "http://myendpoint.com"; RequestParams params = new RequestParams(); params.put("username", "banketree"); params.put("password", "111111"); params.put("email", "banketree@qq.com"); // params.put("profile_picture", new File("pic.jpg")); // Upload a // File // params.put("profile_picture2", someInputStream); // Upload // anInputStream // map = new HashMap<String, String>(); // map.put("first_name", "James"); // map.put("last_name", "Smith"); // params.put("user", map); // * Set<String> set = new HashSet<String>(); // // unordered collection // * set.add("music"); // * set.add("art"); // * params.put("like", set); // url params: // "like=music&like=art" // // * List<String> list = new ArrayList<String>(); // // Ordered collection // * list.add("Java");<> // * list.add("C"); // * params.put("languages", list); // url params: // "languages[]=Java&languages[]=C" // // * String[] colors = { "blue", "yellow" }; // Ordered collection // * params.put("colors", colors); // url params: // "colors[]=blue&colors[]=yellow" // * // * List<Map<String, String>> listOfMaps = new // ArrayList<Map<String, // * String>>(); // * Map<String, String> user1 = new HashMap<String, // String>(); // * user1.put("age", "30"); // * user1.put("gender", "male"); // * Map<String, String> user2 = new HashMap<String, // String>(); // * user2.put("age", "25"); // * user2.put("gender", "female"); // * listOfMaps.add(user1); // * listOfMaps.add(user2); // * params.put("users", listOfMaps); // url params: // "users[][age]=30&users[][gender]=male&users[][age]=25&users[][gender]=female" // * mTAsyncHttpClient.post(url, params, new AsyncHttpResponseHandler() { @Override public void onStart() { } @Override public void onSuccess(int statusCode, Header[] headers, byte[] response) { debugHeaders(headers); debugStatusCode(statusCode); debugResponse(new String(response)); } @Override public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) { debugHeaders(headers); debugStatusCode(statusCode); debugThrowable(e); if (errorResponse != null) { debugResponse(new String(errorResponse)); } } }); } else if (view == mBinaryButton) { url = "http://httpbin.org/gzip"; mTAsyncHttpClient.get(this, url, getRequestHeaders(), null, new BinaryHttpResponseHandler() { @Override public void onStart() { } @Override public String[] getAllowedContentTypes() { // Allowing all data for debug purposes return new String[] { ".*" }; } public void onSuccess(int statusCode, Header[] headers, byte[] binaryData) { debugStatusCode(statusCode); debugHeaders(headers); debugResponse("Received response is " + binaryData.length + " bytes"); } @Override public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) { debugHeaders(headers); debugStatusCode(statusCode); debugThrowable(e); if (errorResponse != null) { debugResponse("Received response is " + errorResponse.length + " bytes"); } } }); } else if (view == mSynGetButton) { url = "https://httpbin.org/delay/6"; mTSyncHttpClient.get(this, url, getRequestHeaders(), null, new AsyncHttpResponseHandler() { @Override public void onStart() { } @Override public void onSuccess(final int statusCode, final Header[] headers, final byte[] response) { debugHeaders(headers); debugStatusCode(statusCode); debugResponse(new String(response)); } @Override public void onFailure(final int statusCode, final Header[] headers, final byte[] errorResponse, final Throwable e) { debugHeaders(headers); debugStatusCode(statusCode); debugThrowable(e); if (errorResponse != null) { debugResponse(new String(errorResponse)); } } }); } else if (view == mTimeOutButton) { url = "http://httpbin.org/delay/6"; mTAsyncHttpClient.get(this, url, getRequestHeaders(), null, new AsyncHttpResponseHandler() { private int counter = 0; private int id = counter++; private SparseArray<String> states = new SparseArray<String>(); @Override public void onStart() { setStatus(id, "START"); } @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { setStatus(id, "SUCCESS"); } @Override public void onFinish() { setStatus(id, "FINISH"); } @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { setStatus(id, "FAILURE"); } @Override public void onCancel() { setStatus(id, "CANCEL"); } private synchronized void setStatus(int id, String status) { String current = states.get(id, null); states.put(id, current == null ? status : current + "," + status); for (int i = 0; i < states.size(); i++) { debugResponse(String.format("%d (from %d): %s", states.keyAt(i), counter, states.get(states.keyAt(i)))); } } }); }
结束
此框架參考了ThinkAndroid,在写此项目之前,笔者一直使用ThinkAndroid框架开发项目。所以非常多思想来源于此。Think框架介绍例如以下:
ThinkAndroid是一个免费的开源的、简易的、遵循Apache2开源协议公布的Android开发框架,其开发宗旨是简单、高速的进行Android应用程序的开发,包含Android mvc、简易sqlite orm、ioc模块、封装Android httpclitent的http模块,具有高速构建文件缓存功能,无需考虑缓存文件的格式,都能够非常轻松的实现缓存,它还基于文件缓存模块实现了图片缓存功能。在android中载入的图片的时候,对oom的问题。和对载入图片错位的问题都轻易解决。他还包含了一个手机开发中常常应用的有用工具类,如日志管理。配置文件管理,android下载器模块,网络切换检測等等工具。
下载地址:https://github.com/white-cat/ThinkAndroid