Android tree应用框架
简介
一个好的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() + "\r\n\r\n" + 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
相关推荐
离子框架(Ionic Framework)是一个开源的HTML5移动应用框架,主要用于构建原生感观的混合式移动应用。它基于Angular,并结合了Apache Cordova和 Capacitor,允许开发者使用Web技术(如HTML、CSS和JavaScript)来...
这需要实现`TreeView`或者利用`DocumentFile` API(API 19及以上)来处理Android的存储访问框架。 10. **权限控制** 在Android Q(API 29)及更高版本,文件访问进一步受限,需要使用`DocumentsContract` API和`...
【Android Plugin Framework Javadoc】是Android应用插件化框架的官方文档资源,源自Google Code项目。这个框架的主要目标是提供一种灵活的方式,让开发者能够构建可扩展的应用程序,通过插件系统来增强功能和更新...
在Android平台上,集成VLC(VideoLAN Client)流媒体视频播放器可以为用户提供高质量的视频播放体验...实际开发中,你可能需要结合"VLCTest01"中的源码进行深入学习和实践,以便更好地理解和掌握VLC在Android上的应用。
Java是一种面向对象的、跨平台的编程语言,广泛应用于服务器端开发、企业级应用、Android应用等。在本例中,Java可能用于实现HR系统的后端逻辑,包括数据存储、处理业务规则、与前端交互等。开发者可能使用了Spring...
自Android 6.0(API级别23)起,运行时权限被引入,应用需要在运行时请求`WRITE_EXTERNAL_STORAGE`和`READ_EXTERNAL_STORAGE`权限。源码中应该包含了请求这些权限的代码逻辑。 2. **文件系统操作**: 文件管理器的...
本项目"Android音乐播放器(Android Studio)"就是这样一个实例,旨在帮助开发者掌握如何在Android平台上创建一个功能完备的音乐应用。 首先,我们来看一下主要的功能实现: 1. **播放与暂停**:这是音乐播放器的...
1. HAL(Hardware Abstraction Layer):硬件抽象层,是Android框架层与硬件驱动之间的接口,提供了标准化的服务供上层应用调用。 2. Device Drivers:设备驱动,包括显示驱动、触摸屏驱动、电源管理驱动、音频驱动...
6. **设备树(Device Tree)**:为特定硬件设备定制Android系统时,设备树是关键部分,它定义了硬件的具体特性。 7. **Board Configurations**:在`device`目录下的配置文件,用于指定设备的硬件特性和组件。 编译...
Android系统的传感器框架分为两层:应用层和系统服务层。在应用层,开发者可以使用SensorManager API来注册SensorEventListener,当传感器数据发生变化时,监听器会接收到SensorEvent对象,包含了传感器的值和时间戳...
可以使用代码分割、tree shaking等技术减少JS体积,使用Fast Refresh提高开发效率,同时关注应用启动时的性能优化。 8. **处理错误**:在加载和执行JS过程中,可能出现各种错误,需要适当地捕获和处理这些错误,...
在AOSP框架下,`system.img`是关键的组成部分,它包含了Android系统的用户空间,如系统应用、库和其他系统服务。 一、Android镜像构建工具 Android镜像构建工具主要负责生成Android系统的各种映像文件,包括但不...
LCD用户指南会涵盖如何配置和驱动液晶显示屏,而Display用户指南则更全面地讨论了Android系统的显示框架,包括图形管道、缓冲区管理和多显示支持等。 "Android 10 clock接口使用说明书"讲解了如何管理芯片上的时钟...
7. **Android框架层适配**:Android系统分为多个层次,从底层的Linux内核到上层的应用框架。书中会讨论如何调整框架层以适应新的硬件特性,包括HAL(硬件抽象层)和系统服务的定制。 8. **系统优化**:除了基本的...
Android ORMLite框架是开发者在Android平台上进行数据库操作的一个便捷工具,它简化了与SQLite数据库交互的复杂性,使得数据库的增删改查等操作变得简单直观。本教程将通过一个入门实例Demo来介绍ORMLite的基本用法...
在Android平台上,调用微信扫一扫功能通常涉及到集成微信官方提供的SDK,这一过程主要依赖于微信的动态链接库(.so文件),使得应用能够调用到微信的扫码服务。下面将详细介绍如何实现这一功能。 首先,我们需要从...
2. 代码混淆:在Android开发中,ProGuard和R8等混淆工具使用ASM Tree来解析和混淆字节码。 3. 性能优化:通过分析字节码构建的树,可以自动进行性能优化,如去除无用代码,减少方法调用等。 4. 代码分析:对于逆向...
1. **Android系统架构**:首先,了解Android系统的五层架构(Linux内核、HAL、系统库、应用框架和应用程序)是基础。这包括Android运行时环境、Binder通信机制、权限管理系统等核心组件。 2. **系统移植**:系统...