├── .gitignore ├── LICENSE ├── README.md ├── WelikeAndroid ├── .classpath ├── .project ├── .settings │ └── org.eclipse.jdt.core.prefs ├── AndroidManifest.xml ├── proguard-project.txt ├── project.properties └── src │ └── com │ └── lody │ └── welike │ ├── Welike.java │ ├── WelikeBitmap.java │ ├── WelikeContext.java │ ├── WelikeDao.java │ ├── WelikeGuard.java │ ├── WelikeHttp.java │ ├── bitmap │ ├── AsyncBitmapLoader.java │ ├── BitmapConfig.java │ ├── BitmapPreprocessor.java │ ├── BitmapRequest.java │ ├── ImageMemoryLruCache.java │ └── callback │ │ └── BitmapCallback.java │ ├── database │ ├── DataType.java │ ├── DbUpdateListener.java │ ├── SQLMaker.java │ ├── SQLTypeParser.java │ ├── SqLiteConfig.java │ ├── TableBuilder.java │ ├── ValueConvertor.java │ ├── WhereBuilder.java │ ├── annotation │ │ ├── ID.java │ │ ├── Ignore.java │ │ ├── NotNull.java │ │ └── Table.java │ └── bean │ │ └── TableInfo.java │ ├── guard │ ├── Mode.java │ ├── UncaughtThrowable.java │ ├── WelikeGuardThreadGroup.java │ └── annotation │ │ ├── Catch.java │ │ └── UnCatch.java │ ├── http │ ├── DownloadController.java │ ├── DownloadTask.java │ ├── HttpConfig.java │ ├── HttpConfigFactory.java │ ├── HttpParams.java │ ├── HttpRequest.java │ ├── HttpRequestBuilder.java │ ├── HttpRequestExecutor.java │ ├── HttpRequestQueue.java │ ├── HttpResponse.java │ ├── HttpSession.java │ ├── HttpSessionManager.java │ ├── HttpThreadPool.java │ ├── RequestMethod.java │ └── callback │ │ ├── DownloadCallback.java │ │ ├── FileUploadCallback.java │ │ ├── HttpBitmapCallback.java │ │ ├── HttpCallback.java │ │ └── HttpResultCallback.java │ ├── reflect │ ├── NULL.java │ ├── Reflect.java │ └── ReflectException.java │ ├── ui │ ├── DynamicActivityBinder.java │ ├── WelikeActivity.java │ ├── WelikeToast.java │ ├── annotation │ │ ├── InitData.java │ │ └── JoinView.java │ └── screenadapter │ │ └── ViewPorter.java │ └── utils │ ├── AppUtils.java │ ├── ByteArrayPool.java │ ├── DiskLruCache.java │ ├── HashUtils.java │ ├── IOUtils.java │ ├── MemoryLruCache.java │ ├── MultiAsyncTask.java │ ├── NoLeakHandler.java │ ├── NoLeakHandlerInterface.java │ ├── PixelDipConverter.java │ ├── PoolingByteArrayOutputStream.java │ ├── ScreenUtils.java │ ├── UiHandler.java │ └── WeLog.java ├── WelikeSample ├── .classpath ├── .project ├── .settings │ └── org.eclipse.jdt.core.prefs ├── AndroidManifest.xml ├── ic_launcher-web.png ├── libs │ └── android-support-v4.jar ├── proguard-project.txt ├── project.properties ├── res │ ├── drawable-hdpi │ │ └── ic_launcher.png │ ├── drawable-mdpi │ │ └── ic_launcher.png │ ├── drawable-xhdpi │ │ ├── common_btn_green_normal.9.png │ │ ├── common_btn_green_pressed.9.png │ │ └── ic_launcher.png │ ├── drawable-xxhdpi │ │ └── ic_launcher.png │ ├── drawable │ │ ├── common_btn_green.xml │ │ └── welike_android.png │ ├── layout │ │ ├── bitmap_layout.xml │ │ ├── db_layout.xml │ │ ├── guard_layout.xml │ │ ├── http_layout.xml │ │ └── main_layout.xml │ ├── values-v11 │ │ └── styles.xml │ ├── values-v14 │ │ └── styles.xml │ └── values │ │ ├── strings.xml │ │ └── styles.xml └── src │ └── com │ └── lody │ └── sample │ ├── BitmapActivity.java │ ├── DbActivity.java │ ├── GuardActivity.java │ ├── HttpActivity.java │ ├── MainActivity.java │ ├── MyApp.java │ ├── bean │ └── MyBean.java │ └── custom │ └── CustomException.java ├── Welike_Android.png ├── doc ├── allclasses-frame.html ├── allclasses-noframe.html ├── com │ └── lody │ │ └── welike │ │ ├── BuildConfig.html │ │ ├── R.attr.html │ │ ├── R.html │ │ ├── R.string.html │ │ ├── WelikeBitmap.html │ │ ├── WelikeContext.html │ │ ├── WelikeDao.html │ │ ├── WelikeGuard.html │ │ ├── WelikeHttp.html │ │ ├── bitmap │ │ ├── AsyncBitmapLoader.BitmapPackage.html │ │ ├── AsyncBitmapLoader.html │ │ ├── BitmapConfig.html │ │ ├── BitmapPreprocessor.html │ │ ├── BitmapRequest.html │ │ ├── ImageMemoryLruCache.html │ │ ├── callback │ │ │ ├── BitmapCallback.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ └── package-tree.html │ │ ├── package-frame.html │ │ ├── package-summary.html │ │ └── package-tree.html │ │ ├── database │ │ ├── DataType.html │ │ ├── DbUpdateListener.html │ │ ├── SQLMaker.html │ │ ├── SQLTypeParser.html │ │ ├── SqLiteConfig.html │ │ ├── TableBuilder.html │ │ ├── ValueConvertor.html │ │ ├── annotation │ │ │ ├── ID.html │ │ │ ├── Ignore.html │ │ │ ├── NotNull.html │ │ │ ├── Table.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ └── package-tree.html │ │ ├── bean │ │ │ ├── TableInfo.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ └── package-tree.html │ │ ├── package-frame.html │ │ ├── package-summary.html │ │ └── package-tree.html │ │ ├── guard │ │ ├── Mode.html │ │ ├── UncaughtThrowable.html │ │ ├── WelikeGuardThreadGroup.html │ │ ├── annotation │ │ │ ├── Catch.html │ │ │ ├── UnCatch.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ └── package-tree.html │ │ ├── package-frame.html │ │ ├── package-summary.html │ │ └── package-tree.html │ │ ├── http │ │ ├── DownloadController.State.html │ │ ├── DownloadController.html │ │ ├── DownloadTask.html │ │ ├── HttpConfig.html │ │ ├── HttpParams.html │ │ ├── HttpRequest.html │ │ ├── HttpRequestBuilder.html │ │ ├── HttpRequestExecutor.html │ │ ├── HttpRequestQueue.html │ │ ├── HttpResponse.html │ │ ├── HttpSession.html │ │ ├── HttpSessionManager.html │ │ ├── HttpThreadPool.html │ │ ├── RequestMethod.html │ │ ├── callback │ │ │ ├── DownloadCallback.html │ │ │ ├── FileUploadCallback.html │ │ │ ├── HttpBitmapCallback.html │ │ │ ├── HttpCallback.html │ │ │ ├── HttpResultCallback.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ └── package-tree.html │ │ ├── package-frame.html │ │ ├── package-summary.html │ │ └── package-tree.html │ │ ├── package-frame.html │ │ ├── package-summary.html │ │ ├── package-tree.html │ │ ├── reflect │ │ ├── NULL.html │ │ ├── Reflect.html │ │ ├── ReflectException.html │ │ ├── package-frame.html │ │ ├── package-summary.html │ │ └── package-tree.html │ │ ├── ui │ │ ├── DynamicActivityBinder.html │ │ ├── WelikeActivity.html │ │ ├── WelikeToast.html │ │ ├── annotation │ │ │ ├── InitData.html │ │ │ ├── JoinView.html │ │ │ ├── package-frame.html │ │ │ ├── package-summary.html │ │ │ └── package-tree.html │ │ ├── package-frame.html │ │ ├── package-summary.html │ │ └── package-tree.html │ │ └── utils │ │ ├── AppUtils.html │ │ ├── ByteArrayPool.html │ │ ├── DiskLruCache.Editor.html │ │ ├── DiskLruCache.Snapshot.html │ │ ├── DiskLruCache.html │ │ ├── HashUtils.html │ │ ├── IOUtils.html │ │ ├── MemoryLruCache.html │ │ ├── MultiAsyncTask.html │ │ ├── PoolingByteArrayOutputStream.html │ │ ├── ScreenUtils.html │ │ ├── UiHandler.html │ │ ├── WeLog.html │ │ ├── package-frame.html │ │ ├── package-summary.html │ │ └── package-tree.html ├── constant-values.html ├── deprecated-list.html ├── help-doc.html ├── index-files │ ├── index-1.html │ ├── index-10.html │ ├── index-11.html │ ├── index-12.html │ ├── index-13.html │ ├── index-14.html │ ├── index-15.html │ ├── index-16.html │ ├── index-17.html │ ├── index-18.html │ ├── index-19.html │ ├── index-2.html │ ├── index-20.html │ ├── index-21.html │ ├── index-22.html │ ├── index-23.html │ ├── index-24.html │ ├── index-3.html │ ├── index-4.html │ ├── index-5.html │ ├── index-6.html │ ├── index-7.html │ ├── index-8.html │ └── index-9.html ├── index.html ├── overview-frame.html ├── overview-summary.html ├── overview-tree.html ├── package-list ├── script.js ├── serialized-form.html └── stylesheet.css ├── jar ├── WelikeAndroid_V1.1.jar ├── WelikeAndroid_V1.2.jar └── WelikeAndroid_V2.0.jar └── screenshot ├── log.png ├── log2.png └── record.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | /*/build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | -------------------------------------------------------------------------------- /WelikeAndroid/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /WelikeAndroid/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | WelikeAndroid 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /WelikeAndroid/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.7 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.source=1.7 12 | -------------------------------------------------------------------------------- /WelikeAndroid/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /WelikeAndroid/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /WelikeAndroid/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-22 15 | android.library=true 16 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/Welike.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike; 2 | 3 | /** 4 | * 有些人不太喜欢WelikeXXX.getDefault()这种方式, 5 | * 那么这个类适合你.
6 | * 7 | * @author Lody 8 | * @version 1.0 9 | */ 10 | public class Welike { 11 | public static WelikeHttp http; 12 | public static WelikeBitmap bitmap; 13 | public static WelikeDao dao; 14 | 15 | static { 16 | http = WelikeHttp.getDefault(); 17 | bitmap = WelikeBitmap.getDefault(); 18 | dao = WelikeDao.instance(); 19 | } 20 | 21 | /** 22 | * @see WelikeGuard#enableGuard() 23 | */ 24 | public static void enableGuard() { 25 | WelikeGuard.enableGuard(); 26 | } 27 | 28 | /** 29 | * @param name 30 | * @return 31 | * @see WelikeDao#instance(String) 32 | */ 33 | public static WelikeDao getDao(String name) { 34 | return WelikeDao.instance(name); 35 | } 36 | 37 | /** 38 | * @param name 39 | * @param version 40 | * @return 41 | * @see WelikeDao#instance(String, int) 42 | */ 43 | public static WelikeDao getDao(String name, int version) { 44 | return WelikeDao.instance(name); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/WelikeContext.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import android.os.Environment; 6 | 7 | import com.lody.welike.reflect.Reflect; 8 | 9 | import java.io.File; 10 | 11 | /** 12 | * @author Lody 13 | *
14 | * 让你在任何地方轻松拿到Context. 15 | */ 16 | public final class WelikeContext { 17 | 18 | /** 19 | * Application实例 20 | */ 21 | private static Application APP_INSTANCE; 22 | 23 | /** 24 | * 取得Application实例 25 | * (NOTE:必须在主线程调用!) 26 | * 27 | * @return 28 | */ 29 | public static Application getApplication() { 30 | 31 | if (APP_INSTANCE == null) { 32 | synchronized (WelikeContext.class) { 33 | if (APP_INSTANCE == null) { 34 | APP_INSTANCE = Reflect.on("android.app.ActivityThread").call("currentActivityThread").call("getApplication").get(); 35 | } 36 | } 37 | } 38 | return APP_INSTANCE; 39 | } 40 | 41 | 42 | /** 43 | * 根据SD卡的挂载情况来选择缓存文件夹. 44 | * (别忘了mkdir文件夹) 45 | * 46 | * @param uniqueName 47 | * @return 48 | */ 49 | public static File getDiskCacheDir(String uniqueName) { 50 | 51 | 52 | Context context = getApplication(); 53 | String cachePath; 54 | if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) 55 | || !Environment.isExternalStorageRemovable()) { 56 | cachePath = context.getExternalCacheDir().getPath(); 57 | } else { 58 | cachePath = context.getCacheDir().getPath(); 59 | } 60 | return new File(cachePath + File.separator + uniqueName); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/WelikeGuard.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike; 2 | 3 | import android.os.Looper; 4 | import android.widget.Toast; 5 | 6 | import com.lody.welike.guard.Mode; 7 | import com.lody.welike.guard.WelikeGuardThreadGroup; 8 | 9 | import java.lang.reflect.Field; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | /** 14 | * 应用异常安全隔离机制 15 | *
16 | * 经过对Android UI线程运行原理进行深度剖析后的思考结晶. 17 | *
18 | * 功能概述: 当在任何一个线程抛出任何未捕获的异常,都会被WelikeGuard拦截, 19 | * 在被拦截后,主线程不会卡死,仍然会继续运行下去.这也许会改变我们的编程理念. 20 | *
21 | * 注意: 目前我们的异常隔离机制是以方法追溯为单位的,也就是说, 22 | * 异常抛出所在的方法在异常抛出以后就不会继续执行下去. 23 | *
24 | * 警告: 本功能尚未成熟,使用本套应用异常隔离请确保您对本功能有所期待. 25 | * 26 | * @author Lody 27 | * @version 3.1 28 | */ 29 | public final class WelikeGuard { 30 | 31 | /** 32 | * 不需要捕获异常的类 33 | */ 34 | public static List> NOT_NEED_CATCH_CLASSES = new ArrayList<>(3); 35 | public static List UNCAUGHT_HANDLER_LIST = new ArrayList<>(2); 36 | 37 | 38 | /** 39 | * 抛出的异常数的阀值,超过此阀值框架就会强制把app杀掉 40 | */ 41 | public static int MAX_ERROR_COUNT = 10; 42 | 43 | /** 44 | * 异常隔离机制的模式 45 | */ 46 | public static Mode guardMode = Mode.THROW_IF_UN_CATCH; 47 | 48 | /** 49 | * 开启异常安全隔离机制,
50 | * 注意:目前开启后无法关闭. 51 | */ 52 | public static void enableGuard() { 53 | try { 54 | hookSystemThreadGroup(); 55 | } catch (Throwable e) { 56 | //适应不同API版本的异常隔离机制 57 | hookSystemThreadGroup2(); 58 | 59 | } 60 | } 61 | 62 | /** 63 | * 注册一个不需要捕获异常的类 64 | * 65 | * @param clazz 66 | */ 67 | public static void registerUncatchClass(Class clazz) { 68 | if (!NOT_NEED_CATCH_CLASSES.contains(clazz)) { 69 | NOT_NEED_CATCH_CLASSES.add(clazz); 70 | } 71 | } 72 | 73 | /** 74 | * 取消注册一个不需要捕获异常的类 75 | * 76 | * @param clazz 77 | */ 78 | public static void unregisterUncatchClass(Class clazz) { 79 | NOT_NEED_CATCH_CLASSES.remove(clazz); 80 | } 81 | 82 | /** 83 | * 注册一个未捕获监听器 84 | * 85 | * @param uncaughtExceptionHandler 86 | */ 87 | public static void registerUnCaughtHandler(Thread.UncaughtExceptionHandler uncaughtExceptionHandler) { 88 | if (!UNCAUGHT_HANDLER_LIST.contains(uncaughtExceptionHandler)) { 89 | UNCAUGHT_HANDLER_LIST.add(uncaughtExceptionHandler); 90 | } 91 | } 92 | 93 | /** 94 | * 取消注册一个未捕获监听器 95 | * 96 | * @param uncaughtExceptionHandler 97 | */ 98 | public static void unregisterCaughtUandler(Thread.UncaughtExceptionHandler uncaughtExceptionHandler) { 99 | UNCAUGHT_HANDLER_LIST.remove(uncaughtExceptionHandler); 100 | } 101 | 102 | 103 | /** 104 | * 创建一个子线程,在子线程弹出一个Toast 105 | * 106 | * @param msg 显示的字符串 107 | */ 108 | public static void newThreadToast(final String msg) { 109 | new Thread(new Runnable() { 110 | 111 | @Override 112 | public void run() { 113 | Looper.prepare(); 114 | Toast.makeText(WelikeContext.getApplication(), msg, Toast.LENGTH_SHORT).show(); 115 | Looper.loop(); 116 | 117 | } 118 | }).start(); 119 | } 120 | 121 | 122 | private static void hookSystemThreadGroup() throws Throwable { 123 | //在Android 5.X上测试正常 124 | Field f_mMain = ThreadGroup.class.getDeclaredField("mainThreadGroup"); 125 | Field f_mSystem = ThreadGroup.class.getDeclaredField("systemThreadGroup"); 126 | f_mMain.setAccessible(true); 127 | f_mSystem.setAccessible(true); 128 | ThreadGroup mMain = (ThreadGroup) f_mMain.get(null); 129 | ThreadGroup mSystem = (ThreadGroup) f_mSystem.get(null); 130 | Field f_parent = ThreadGroup.class.getDeclaredField("parent"); 131 | f_parent.setAccessible(true); 132 | f_parent.set(mMain, new WelikeGuardThreadGroup(mSystem)); 133 | 134 | 135 | } 136 | 137 | private static void hookSystemThreadGroup2() { 138 | //在Android 5.x以下测试正常 139 | try { 140 | Field f_mMain = ThreadGroup.class.getDeclaredField("mMain"); 141 | Field f_mSystem = ThreadGroup.class.getDeclaredField("mSystem"); 142 | f_mMain.setAccessible(true); 143 | f_mSystem.setAccessible(true); 144 | ThreadGroup mMain = (ThreadGroup) f_mMain.get(null); 145 | ThreadGroup mSystem = (ThreadGroup) f_mSystem.get(null); 146 | Field f_parent = ThreadGroup.class.getDeclaredField("parent"); 147 | f_parent.setAccessible(true); 148 | f_parent.set(mMain, new WelikeGuardThreadGroup(mSystem)); 149 | } catch (Throwable e) { 150 | } 151 | } 152 | 153 | 154 | } -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/bitmap/BitmapConfig.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.bitmap; 2 | 3 | import com.lody.welike.WelikeHttp; 4 | import com.lody.welike.http.HttpConfig; 5 | 6 | /** 7 | * 图片加载引擎的配置信息 8 | * 9 | * @author Lody 10 | * @version 1.0 11 | */ 12 | public class BitmapConfig { 13 | 14 | /** 15 | * 图片磁盘缓存的文件夹名 16 | */ 17 | public static String CACHE_DIR_NAME = "bitmap"; 18 | 19 | /** 20 | * 是否开启磁盘缓存 21 | */ 22 | public boolean enableDiskCache = true; 23 | 24 | /** 25 | * 内存缓存大小,默认为OOM上限的八分之一 26 | */ 27 | public int memoryCacheSize = (int) (Runtime.getRuntime().maxMemory() / 8); 28 | 29 | /** 30 | * 磁盘缓存大小 31 | */ 32 | public long diskCacheSize = HttpConfig.CACHE_MAX_SIZE; 33 | 34 | /** 35 | * 用于发起加载图片的Http请求 36 | */ 37 | private WelikeHttp welikeHttp; 38 | 39 | /** 40 | * 是否开启Debug模式 41 | */ 42 | public boolean debugMode = true; 43 | 44 | /** 45 | * 图片内存LruCache缓存池 46 | */ 47 | private ImageMemoryLruCache memoryLruCache; 48 | 49 | 50 | public BitmapConfig() { 51 | HttpConfig config = new HttpConfig(CACHE_DIR_NAME, diskCacheSize); 52 | welikeHttp = new WelikeHttp(config); 53 | memoryLruCache = new ImageMemoryLruCache(this); 54 | } 55 | 56 | /** 57 | * 应用另一个配置 58 | * 59 | * @param config 配置 60 | */ 61 | public void applyConfig(BitmapConfig config) { 62 | this.diskCacheSize = config.diskCacheSize; 63 | this.memoryCacheSize = config.memoryCacheSize; 64 | this.enableDiskCache = config.enableDiskCache; 65 | this.welikeHttp = config.welikeHttp; 66 | config.enableDiskCache = enableDiskCache; 67 | } 68 | 69 | /** 70 | * 取得用于发起加载图片的Http请求的WelikeHttp 71 | * 72 | * @return 用于发起加载图片的Http请求的WelikeHttp 73 | */ 74 | public WelikeHttp getWelikeHttp() { 75 | return this.welikeHttp; 76 | } 77 | 78 | /** 79 | * @return 图片内存LruCache缓存池 80 | */ 81 | public ImageMemoryLruCache getMemoryLruCache() { 82 | return memoryLruCache; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/bitmap/BitmapRequest.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.bitmap; 2 | 3 | import android.graphics.Bitmap; 4 | import android.graphics.drawable.Drawable; 5 | import android.view.View; 6 | 7 | import com.lody.welike.bitmap.callback.BitmapCallback; 8 | 9 | /** 10 | * 封装一个图片加载的请求 11 | * @author Lody 12 | * @version 1.0 13 | */ 14 | public class BitmapRequest { 15 | /** 16 | * 需要加载图片的View 17 | */ 18 | private View view; 19 | /** 20 | * 图片的Url 21 | */ 22 | private String url; 23 | /** 24 | * 加载中的显示的图片 25 | */ 26 | private Bitmap loadingBitmap; 27 | /** 28 | * 错误时显示的图片 29 | */ 30 | private Bitmap errorBitmap; 31 | /** 32 | * 加载中显示的图片 33 | */ 34 | private Drawable loadingDrawable; 35 | /** 36 | * 错误时显示的图片 37 | */ 38 | private Drawable errorDrawable; 39 | /** 40 | * 图片加载回调 41 | */ 42 | private BitmapCallback callback; 43 | 44 | /** 45 | * 图片要求的宽度 46 | */ 47 | private int requestWidth; 48 | /** 49 | * 图片要求的高度 50 | */ 51 | private int requestHeight; 52 | 53 | /** 54 | * 任务是否已经取消 55 | */ 56 | private boolean isCancel; 57 | 58 | /** 59 | * @param view 60 | * @param url 61 | * @param requestWidth 62 | * @param requestHeight 63 | * @param loadingBitmap 64 | * @param errorBitmap 65 | * @param callback 66 | */ 67 | public BitmapRequest(View view, String url, int requestWidth, int requestHeight, Bitmap loadingBitmap, Bitmap errorBitmap, BitmapCallback callback) { 68 | this.view = view; 69 | this.url = url; 70 | this.requestWidth = requestWidth; 71 | this.requestHeight = requestHeight; 72 | this.loadingBitmap = loadingBitmap; 73 | this.errorBitmap = errorBitmap; 74 | this.callback = callback; 75 | } 76 | 77 | /** 78 | * @param view 79 | * @param url 80 | * @param requestWidth 81 | * @param requestHeight 82 | * @param loadingDrawable 83 | * @param errorDrawable 84 | * @param callback 85 | */ 86 | public BitmapRequest(View view, String url, int requestWidth, int requestHeight, Drawable loadingDrawable, Drawable errorDrawable, BitmapCallback callback) { 87 | this.view = view; 88 | this.url = url; 89 | this.requestWidth = requestWidth; 90 | this.requestHeight = requestHeight; 91 | this.loadingDrawable = loadingDrawable; 92 | this.errorDrawable = errorDrawable; 93 | this.callback = callback; 94 | } 95 | 96 | public Bitmap getLoadingBitmap() { 97 | return loadingBitmap; 98 | } 99 | 100 | public void setLoadingBitmap(Bitmap loadingBitmap) { 101 | this.loadingBitmap = loadingBitmap; 102 | } 103 | 104 | public View getView() { 105 | return view; 106 | } 107 | 108 | public void setView(View view) { 109 | this.view = view; 110 | } 111 | 112 | public String getUrl() { 113 | return url; 114 | } 115 | 116 | public void setUrl(String url) { 117 | this.url = url; 118 | } 119 | 120 | public Bitmap getErrorBitmap() { 121 | return errorBitmap; 122 | } 123 | 124 | public void setErrorBitmap(Bitmap errorBitmap) { 125 | this.errorBitmap = errorBitmap; 126 | } 127 | 128 | public BitmapCallback getCallback() { 129 | return callback; 130 | } 131 | 132 | public void setCallback(BitmapCallback callback) { 133 | this.callback = callback; 134 | } 135 | 136 | public int getRequestWidth() { 137 | return requestWidth; 138 | } 139 | 140 | public void setRequestWidth(int requestWidth) { 141 | this.requestWidth = requestWidth; 142 | } 143 | 144 | public int getRequestHeight() { 145 | return requestHeight; 146 | } 147 | 148 | public void setRequestHeight(int requestHeight) { 149 | this.requestHeight = requestHeight; 150 | } 151 | 152 | 153 | public boolean isCancel() { 154 | return isCancel; 155 | } 156 | 157 | public void cancel() { 158 | this.isCancel = true; 159 | } 160 | 161 | public Drawable getLoadingDrawable() { 162 | return loadingDrawable; 163 | } 164 | 165 | public void setLoadingDrawable(Drawable loadingDrawable) { 166 | this.loadingDrawable = loadingDrawable; 167 | } 168 | 169 | public Drawable getErrorDrawable() { 170 | return errorDrawable; 171 | } 172 | 173 | public void setErrorDrawable(Drawable errorDrawable) { 174 | this.errorDrawable = errorDrawable; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/bitmap/ImageMemoryLruCache.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.bitmap; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | import com.lody.welike.utils.MemoryLruCache; 6 | 7 | /** 8 | * 用于图片加载的LruCache. 9 | * 10 | * @author Lody 11 | * @version 1.0 12 | */ 13 | public class ImageMemoryLruCache extends MemoryLruCache { 14 | 15 | /** 16 | * @param maxSize LruCache内存上限 17 | */ 18 | public ImageMemoryLruCache(int maxSize) { 19 | super(maxSize); 20 | } 21 | 22 | /** 23 | * @param config Bitmap加载引擎的配置 24 | */ 25 | public ImageMemoryLruCache(BitmapConfig config) { 26 | this(config.memoryCacheSize); 27 | } 28 | 29 | 30 | @Override 31 | protected int sizeOf(String key, Bitmap value) { 32 | //NOTE:有些人特意做了个判断, 33 | //在SDK_INT >= 12 时使用value.getByteCount(), 34 | //SDK_INT < 12 时使用value.getRowBytes() * value.getHeight(), 35 | //其实这不都一样么,value.getByteCount()内部还是调用了value.getRowBytes() * value.getHeight(). 36 | 37 | return value.getRowBytes() * value.getHeight(); 38 | } 39 | 40 | /** 41 | * 取得内存中的Bitmap 42 | * 43 | * @param url 44 | * @return 45 | */ 46 | public Bitmap getBitmap(String url) { 47 | return get(url); 48 | } 49 | 50 | /** 51 | * 将一张Bitmap放到LruCache 52 | * 53 | * @param url 54 | * @param bitmap 55 | */ 56 | public void putBitmap(String url, Bitmap bitmap) { 57 | put(url, bitmap); 58 | } 59 | 60 | /** 61 | * 清除全部缓存 62 | */ 63 | public void clearAllBitmap() { 64 | getMap().clear(); 65 | } 66 | 67 | /** 68 | * 移除一个张图片 69 | * 70 | * @param url 71 | * @return 72 | */ 73 | public Bitmap removeBitmap(String url) { 74 | return remove(url); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/bitmap/callback/BitmapCallback.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.bitmap.callback; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | import com.lody.welike.http.HttpRequest; 6 | import com.lody.welike.http.HttpResponse; 7 | 8 | /** 9 | * 图片加载的回调 10 | * 11 | * @author Lody 12 | * @version 1.0 13 | */ 14 | public abstract class BitmapCallback { 15 | 16 | /** 17 | * 图片开始加载前回调 18 | * 19 | * @param url 要加载的图片的Url 20 | */ 21 | public void onPreStart(String url) { 22 | } 23 | 24 | 25 | /** 26 | * 图片加载请求被取消时回调 27 | * 28 | * @param url 被取消的图片Url 29 | */ 30 | public void onCancel(String url) { 31 | } 32 | 33 | /** 34 | * 图片加载成功后回调 35 | * 36 | * @param bitmap 加载成功的Bitmap 37 | */ 38 | public void onLoadSuccess(String url, Bitmap bitmap) { 39 | } 40 | 41 | /** 42 | * 图片加载需要请求网络时回调 43 | * 44 | * @param request 请求 45 | */ 46 | public void onRequestHttp(HttpRequest request) { 47 | } 48 | 49 | /** 50 | * 图片加载失败后回调 51 | * 52 | * @param response 网络响应 53 | * @param url 加载失败的图片Url 54 | */ 55 | public void onLoadFailed(HttpResponse response, String url) { 56 | } 57 | 58 | /** 59 | * 需要将字节数组转换为Bitmap时回调 60 | * @param data 61 | * @return 可以为null, 也可以为自己处理后的Bitmap 62 | */ 63 | public Bitmap onProcessBitmap(byte[] data){ 64 | return null; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/database/DataType.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.database; 2 | 3 | /** 4 | * @author Lody 5 | *

6 | * 数据库支持的数据类型的枚举类 7 | */ 8 | public enum DataType { 9 | /** 10 | * int类型 11 | */ 12 | INTEGER, 13 | /** 14 | * String类型 15 | */ 16 | TEXT, 17 | /** 18 | * float类型 19 | */ 20 | FLOAT, 21 | /** 22 | * long类型 23 | */ 24 | BIGINT, 25 | /** 26 | * double类型 27 | */ 28 | DOUBLE; 29 | 30 | boolean nullable = true; 31 | 32 | /** 33 | * 数据类型是否允许为null 34 | */ 35 | public DataType nullable(boolean nullable) { 36 | this.nullable = nullable; 37 | return this; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/database/DbUpdateListener.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.database; 2 | 3 | import android.database.sqlite.SQLiteDatabase; 4 | 5 | /** 6 | * 数据库升级监听器 7 | * 8 | * @author Lody 9 | */ 10 | public interface DbUpdateListener { 11 | /** 12 | * @param db 数据库 13 | * @param oldVersion 旧版本 14 | * @param newVersion 新版本 15 | */ 16 | void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion); 17 | } -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/database/SQLTypeParser.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.database; 2 | 3 | import com.lody.welike.database.annotation.Ignore; 4 | import com.lody.welike.database.annotation.NotNull; 5 | 6 | import java.lang.reflect.Field; 7 | 8 | /** 9 | * @author Lody 10 | * 解析Java的数据类型,将其转换为对应的SQL类型. 11 | * 12 | * 2015/8/17 :支持 boolean 类型. 13 | * 14 | * @version 2.2 15 | */ 16 | public class SQLTypeParser { 17 | 18 | /** 19 | * 根据字段类型匹配它在数据库中的对应类型. 20 | * 21 | * @param field 22 | * @return 23 | */ 24 | public static DataType getDataType(Field field) { 25 | Class clazz = field.getType(); 26 | if (clazz == (String.class)) { 27 | return DataType.TEXT.nullable((field.getAnnotation(NotNull.class) == null)); 28 | } else if (clazz == (int.class) || clazz == (Integer.class)) { 29 | return DataType.INTEGER.nullable((field.getAnnotation(NotNull.class) == null)); 30 | } else if (clazz == (float.class) || clazz == (Float.class)) { 31 | return DataType.FLOAT.nullable((field.getAnnotation(NotNull.class) == null)); 32 | } else if (clazz == (long.class) || clazz == (Long.class)) { 33 | return DataType.BIGINT.nullable((field.getAnnotation(NotNull.class) == null)); 34 | } else if (clazz == (double.class) || clazz == (Double.class)) { 35 | return DataType.DOUBLE.nullable((field.getAnnotation(NotNull.class) == null)); 36 | } else if (clazz == (boolean.class) || clazz == (Boolean.class)) { 37 | return DataType.INTEGER.nullable((field.getAnnotation(NotNull.class) == null)); 38 | } 39 | return null; 40 | } 41 | 42 | /** 43 | * 根据字段类型匹配它在数据库中的对应类型. 44 | * 45 | * @param clazz 46 | * @return 47 | */ 48 | public static DataType getDataType(Class clazz) { 49 | if (clazz == (String.class)) { 50 | return DataType.TEXT; 51 | } else if (clazz == (int.class) || clazz == (Integer.class)) { 52 | return DataType.INTEGER; 53 | } else if (clazz == (float.class) || clazz == (Float.class)) { 54 | return DataType.FLOAT; 55 | } else if (clazz == (long.class) || clazz == (Long.class)) { 56 | return DataType.BIGINT; 57 | } else if (clazz == (double.class) || clazz == (Double.class)) { 58 | return DataType.DOUBLE; 59 | } else if (clazz == (boolean.class) || clazz == (Boolean.class)) { 60 | return DataType.INTEGER; 61 | } 62 | return null; 63 | } 64 | 65 | /** 66 | * 字段类型与数据类型是否匹配? 67 | * 68 | * @param field 69 | * @param dataType 70 | * @return 71 | */ 72 | public static boolean matchType(Field field, DataType dataType) { 73 | DataType fieldDataType = getDataType(field.getType()); 74 | 75 | return dataType != null && fieldDataType == (dataType); 76 | } 77 | 78 | /** 79 | * 字段是否可以被数据库忽略? 80 | * 81 | * @param field 82 | * @return 83 | */ 84 | public static boolean isIgnore(Field field) { 85 | return field.getAnnotation(Ignore.class) != null; 86 | } 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/database/SqLiteConfig.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.database; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * @author Lody 7 | *

8 | * 数据库配置信息 9 | */ 10 | public class SqLiteConfig implements Serializable { 11 | 12 | //============================================================== 13 | // 常量 14 | //============================================================== 15 | public static String DEFAULT_DB_NAME = "we_like.db"; 16 | public static SqLiteConfig DEFAULT_CONFIG = new SqLiteConfig(); 17 | private static final long serialVersionUID = -4069725570156436316L; 18 | 19 | //============================================================== 20 | // 字段 21 | //============================================================== 22 | /** 23 | * 数据库名 24 | */ 25 | private String dbName = DEFAULT_DB_NAME; 26 | 27 | /** 28 | * 是否为DEBUG模式 29 | */ 30 | public boolean debugMode = true; 31 | 32 | /** 33 | * 数据库升级监听器 34 | */ 35 | private DbUpdateListener dbUpdateListener; 36 | private String saveDir; 37 | private int dbVersion = 1; 38 | 39 | /** 40 | * 取得数据库的名称 41 | * 42 | * @return 43 | */ 44 | public String getDbName() { 45 | return dbName; 46 | } 47 | 48 | /** 49 | * 设置数据库的名称 50 | * 51 | * @param dbName 52 | */ 53 | public void setDbName(String dbName) { 54 | this.dbName = dbName; 55 | } 56 | 57 | /** 58 | * 设置数据库升级监听器 59 | * 60 | * @param dbUpdateListener 61 | */ 62 | public void setDbUpdateListener(DbUpdateListener dbUpdateListener) { 63 | this.dbUpdateListener = dbUpdateListener; 64 | } 65 | 66 | /** 67 | * 取得数据库升级监听器 68 | * 69 | * @return 70 | */ 71 | public DbUpdateListener getDbUpdateListener() { 72 | return dbUpdateListener; 73 | } 74 | 75 | /** 76 | * 取得数据库保存目录 77 | * 78 | * @return 79 | */ 80 | public String getSaveDir() { 81 | return saveDir; 82 | } 83 | 84 | /** 85 | * 设置数据库的保存目录 86 | * 87 | * @param saveDir 88 | */ 89 | public void setSaveDir(String saveDir) { 90 | this.saveDir = saveDir; 91 | } 92 | 93 | /** 94 | * 获取DB的版本号 95 | * 96 | * @return 97 | */ 98 | public int getDbVersion() { 99 | return dbVersion; 100 | } 101 | 102 | /** 103 | * 设置DB的版本号 104 | * 105 | * @param dbVersion 106 | */ 107 | public void setDbVersion(int dbVersion) { 108 | this.dbVersion = dbVersion; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/database/TableBuilder.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.database; 2 | 3 | import android.database.sqlite.SQLiteDatabase; 4 | 5 | import com.lody.welike.WelikeDao; 6 | import com.lody.welike.database.annotation.ID; 7 | import com.lody.welike.database.annotation.Table; 8 | import com.lody.welike.database.bean.TableInfo; 9 | 10 | import java.lang.reflect.Field; 11 | import java.lang.reflect.Method; 12 | import java.lang.reflect.Modifier; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | /** 17 | * @author Lody 18 | * 创建Table的辅助类 19 | */ 20 | public class TableBuilder { 21 | 22 | /*package*/ static final Map, TableInfo> classToTableInfoMap = new HashMap<>(); 23 | 24 | /** 25 | * 根据传入的Bean的Class将其映射为一个TableInfo. 26 | * 27 | * @param clazz 28 | * @return 29 | */ 30 | public static TableInfo from(Class clazz) { 31 | 32 | 33 | TableInfo tableInfo = classToTableInfoMap.get(clazz); 34 | if (tableInfo != null) { 35 | return tableInfo; 36 | } 37 | tableInfo = new TableInfo(); 38 | //Table注解解析 39 | Table table = clazz.getAnnotation(Table.class); 40 | String afterTableCreateMethod = table.afterTableCreate(); 41 | if (afterTableCreateMethod != null && afterTableCreateMethod.trim().length() > 0) { 42 | try { 43 | Method method = clazz.getDeclaredMethod(afterTableCreateMethod, WelikeDao.class); 44 | if (method != null && Modifier.isStatic(method.getModifiers())) { 45 | method.setAccessible(true); 46 | tableInfo.afterTableCreateMethod = method; 47 | } 48 | } catch (Throwable ignored) { 49 | } 50 | } 51 | if (table != null && table.name().trim().length() != 0) { 52 | tableInfo.tableName = table.name(); 53 | } else { 54 | tableInfo.tableName = clazz.getName().replace(".", "_"); 55 | } 56 | 57 | Map fieldEnumMap = new HashMap<>(); 58 | for (Field field : clazz.getDeclaredFields()) { 59 | field.setAccessible(true); 60 | //如果这个字段加了ignore注解,我们就跳过 61 | if (SQLTypeParser.isIgnore(field)) { 62 | continue; 63 | } 64 | DataType dataType = SQLTypeParser.getDataType(field); 65 | if (dataType != null) { 66 | fieldEnumMap.put(field, dataType); 67 | } else { 68 | throw new IllegalArgumentException("The type of " + field.getClass().getName() + "is not support in database."); 69 | } 70 | }//end 71 | tableInfo.fieldToDataTypeMap = fieldEnumMap; 72 | buildPrimaryIDForTableInfo(tableInfo); 73 | tableInfo.createTableStatement = SQLMaker.createTable(tableInfo); 74 | 75 | synchronized (classToTableInfoMap) { 76 | classToTableInfoMap.put(clazz, tableInfo); 77 | } 78 | return tableInfo; 79 | } 80 | 81 | /** 82 | * 为一个Bean匹配一个ID字段,如果ID字段不存在,使用默认的_id替代. 83 | * 84 | * @param info 85 | * @return 86 | */ 87 | private static TableInfo buildPrimaryIDForTableInfo(TableInfo info) { 88 | 89 | Field idField = null; 90 | ID id; 91 | for (Field field : info.fieldToDataTypeMap.keySet()) { 92 | id = field.getAnnotation(ID.class); 93 | if (id != null) { 94 | idField = field; 95 | break; 96 | } 97 | }//end 98 | if (idField != null) { 99 | //从字段表中移除ID 100 | info.fieldToDataTypeMap.remove(idField); 101 | info.containID = true; 102 | info.primaryField = idField; 103 | } else { 104 | info.containID = false; 105 | info.primaryField = null; 106 | } 107 | 108 | return info; 109 | } 110 | 111 | /** 112 | * 根据表名匹配TableInfo 113 | * 114 | * @param tableName 115 | * @return 116 | */ 117 | public static TableInfo findTableInfoByName(String tableName) { 118 | 119 | for (TableInfo tableInfo : classToTableInfoMap.values()) { 120 | if (tableInfo.tableName.equals(tableName)) { 121 | return tableInfo; 122 | } 123 | } 124 | 125 | return null; 126 | } 127 | 128 | /** 129 | * 清除留在内存中的TableInfo缓存 130 | */ 131 | public static void clearCache() { 132 | classToTableInfoMap.clear(); 133 | } 134 | 135 | } 136 | 137 | 138 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/database/ValueConvertor.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.database; 2 | 3 | import android.database.Cursor; 4 | 5 | import java.lang.reflect.Field; 6 | 7 | /** 8 | * @author Lody 9 | */ 10 | public class ValueConvertor { 11 | 12 | /** 13 | * 根据数据类型将数据库中的值写入到相应的字段. 14 | * 15 | * @param cursor 游标 16 | * @param object 赋值对象 17 | * @param field 赋值字段 18 | * @param dataType 数据类型 19 | */ 20 | public static void setKeyValue(Cursor cursor, Object object, Field field, DataType dataType, int index) { 21 | switch (dataType) { 22 | case INTEGER: 23 | try { 24 | field.set(object, cursor.getInt(index)); 25 | } catch (Throwable e) { 26 | try { 27 | //支持Boolean类型 28 | //因为Boolean默认当Integer处理 29 | field.set(object, cursor.getInt(index) != 0); 30 | } catch (IllegalAccessException ignored) { 31 | } 32 | } 33 | break; 34 | case TEXT: 35 | try { 36 | field.set(object, cursor.getString(index)); 37 | } catch (IllegalAccessException e) { 38 | } 39 | break; 40 | case FLOAT: 41 | try { 42 | field.set(object, cursor.getFloat(index)); 43 | } catch (IllegalAccessException e) { 44 | } 45 | break; 46 | case BIGINT: 47 | try { 48 | field.set(object, cursor.getLong(index)); 49 | } catch (IllegalAccessException e) { 50 | } 51 | break; 52 | case DOUBLE: 53 | try { 54 | field.set(object, cursor.getDouble(index)); 55 | } catch (IllegalAccessException e) { 56 | } 57 | break; 58 | 59 | } 60 | } 61 | 62 | /** 63 | * 根据数据类型从字段中提取值并转换为String 64 | * 65 | * @param dataType 66 | * @param field 67 | * @param o 68 | * @return 69 | * @throws IllegalAccessException 无法转换时抛出的异常 70 | */ 71 | public static String valueToString(DataType dataType, Field field, Object o) throws IllegalAccessException { 72 | switch (dataType) { 73 | case INTEGER: 74 | Object f = field.get(o); 75 | if (f instanceof Boolean) { 76 | return String.valueOf(((boolean) field.get(o)) ? 1 : 0); 77 | } else { 78 | return String.valueOf((int) field.get(o)); 79 | } 80 | case TEXT: 81 | return "\"" + field.get(o) + "" + "\""; 82 | case DOUBLE: 83 | return String.valueOf((double) field.get(o)); 84 | case FLOAT: 85 | return String.valueOf((float) field.get(o)); 86 | case BIGINT: 87 | return String.valueOf((long) field.get(o)); 88 | } 89 | return null; 90 | } 91 | 92 | /** 93 | * 根据数据类型将对象转换为String 94 | * 95 | * @param dataType 96 | * @param o 97 | * @return 98 | */ 99 | public static String valueToString(DataType dataType, Object o) { 100 | switch (dataType) { 101 | case INTEGER: 102 | if (o instanceof Boolean) { 103 | return ((boolean) o) ? "1" : "0"; 104 | } else { 105 | return String.valueOf((int) o); 106 | } 107 | case TEXT: 108 | return "\"" + o + "\""; 109 | case DOUBLE: 110 | return String.valueOf((double) o); 111 | case FLOAT: 112 | return String.valueOf((float) o); 113 | case BIGINT: 114 | return String.valueOf((long) o); 115 | } 116 | return null; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/database/WhereBuilder.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.database; 2 | 3 | import com.lody.welike.WelikeDao; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author Lody 9 | * @version 1.0 10 | */ 11 | public class WhereBuilder { 12 | 13 | private final WelikeDao dao; 14 | private StringBuilder statement; 15 | private Class beanClass; 16 | 17 | public WhereBuilder(WelikeDao welikeDao, Class beanClass){ 18 | this.dao = welikeDao; 19 | statement = new StringBuilder(); 20 | this.beanClass = beanClass; 21 | } 22 | 23 | public WhereBuilder where(String where){ 24 | statement.append(where); 25 | return this; 26 | } 27 | 28 | 29 | public WhereBuilder and(String appendStatement){ 30 | statement.append(" and ").append(appendStatement); 31 | return this; 32 | } 33 | 34 | public WhereBuilder or(String appendStatement){ 35 | statement.append(" or ").append(appendStatement); 36 | return this; 37 | } 38 | 39 | public WhereBuilder orderBy(String appendStatement){ 40 | statement.append(" order by ").append(appendStatement); 41 | return this; 42 | } 43 | 44 | public List find(){ 45 | return dao.findBeanByWhere(beanClass,statement.toString()); 46 | } 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/database/annotation/ID.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.database.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author Lody 10 | * 注解在字段上表示主键. 11 | */ 12 | @Target(ElementType.FIELD) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface ID { 15 | /** 16 | * 只对Integer类型的ID字段有效 17 | * 18 | * @return 是否为自增长 19 | */ 20 | boolean autoIncrement() default false; 21 | } 22 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/database/annotation/Ignore.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.database.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author Lody 10 | *

11 | * 此注解表示字段将被解析器忽略. 12 | */ 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target({ElementType.FIELD}) 15 | public @interface Ignore { 16 | } 17 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/database/annotation/NotNull.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.database.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author Lody 10 | * 加上此注解的字段不能NULL 11 | */ 12 | @Target(ElementType.FIELD) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface NotNull { 15 | } 16 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/database/annotation/Table.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.database.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author Lody 10 | * 对应一个表 11 | */ 12 | @Target(ElementType.TYPE) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface Table { 15 | /** 16 | * @return 表名 17 | */ 18 | String name() default ""; 19 | 20 | /** 21 | * @return 在表创建后需要回调的方法 22 | */ 23 | String afterTableCreate() default ""; 24 | } 25 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/database/bean/TableInfo.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.database.bean; 2 | 3 | import com.lody.welike.database.DataType; 4 | 5 | import java.lang.reflect.Field; 6 | import java.lang.reflect.Method; 7 | import java.util.Map; 8 | 9 | /** 10 | * @author Lody 11 | * 储存Table信息 12 | */ 13 | public class TableInfo { 14 | 15 | /** 16 | * 是否包含ID 17 | */ 18 | public boolean containID; 19 | /** 20 | * 主键字段 21 | */ 22 | public Field primaryField; 23 | 24 | /** 25 | * 表名 26 | */ 27 | public String tableName; 28 | 29 | /** 30 | * 字段表 31 | */ 32 | public Map fieldToDataTypeMap; 33 | 34 | /** 35 | * 创建table的语句 36 | */ 37 | public String createTableStatement; 38 | 39 | /** 40 | * 是否已经创建 41 | */ 42 | public boolean isCreate = false; 43 | 44 | public Method afterTableCreateMethod; 45 | 46 | } 47 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/guard/Mode.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.guard; 2 | 3 | /** 4 | * 异常安全隔离机制的模式枚举类. 5 | * 6 | * @author Lody 7 | * @version 1.1 8 | */ 9 | public enum Mode { 10 | /** 11 | * 除非异常上包含{@link com.lody.welike.guard.annotation.UnCatch} 12 | * 注解,否则一律捕获. 13 | */ 14 | THROW_IF_UN_CATCH, 15 | /** 16 | * 不捕获任何异常,遇到异常直接杀掉自己(只用于调试) 17 | */ 18 | DONT_CATCH, 19 | /** 20 | * 无论是否包含注解,一律捕获异常. 21 | */ 22 | CATCH_ALL 23 | } 24 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/guard/UncaughtThrowable.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.guard; 2 | 3 | import com.lody.welike.guard.annotation.UnCatch; 4 | 5 | /** 6 | * 继承本类的Throwable将不会被异常隔离机制拦截,直接抛出 7 | * 8 | * @author Lody 9 | * @version 1.0 10 | */ 11 | @UnCatch 12 | public class UncaughtThrowable extends NullPointerException { 13 | 14 | /** 15 | * 16 | */ 17 | private static final long serialVersionUID = 234876922020326875L; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/guard/WelikeGuardThreadGroup.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.guard; 2 | 3 | import android.os.Looper; 4 | import android.os.Process; 5 | 6 | import com.lody.welike.WelikeGuard; 7 | import com.lody.welike.guard.annotation.Catch; 8 | import com.lody.welike.guard.annotation.UnCatch; 9 | import com.lody.welike.reflect.NULL; 10 | 11 | import java.lang.reflect.Method; 12 | import java.lang.reflect.Modifier; 13 | import java.util.concurrent.atomic.AtomicInteger; 14 | 15 | 16 | /** 17 | * Welike安插的傀儡,异常隔离机制的底层守护类, 18 | * 我们将它植入到主线程.干扰原来的异常捕获机制:) 19 | * 20 | * @author Lody 21 | * @version 2.0 22 | */ 23 | public class WelikeGuardThreadGroup extends ThreadGroup { 24 | 25 | 26 | 27 | /** 28 | * 拦截的异常数量(允许高并发) 29 | */ 30 | private static AtomicInteger errorHitCount = new AtomicInteger(0); 31 | 32 | public WelikeGuardThreadGroup(ThreadGroup mSystem) { 33 | super(mSystem, "system"); 34 | } 35 | 36 | 37 | @Override 38 | public void uncaughtException(Thread t, Throwable e) { 39 | 40 | errorHitCount.incrementAndGet(); 41 | //回调所有未捕获异常监听器 42 | for (Thread.UncaughtExceptionHandler uncaughtExceptionHandler : WelikeGuard.UNCAUGHT_HANDLER_LIST) { 43 | uncaughtExceptionHandler.uncaughtException(t, e); 44 | } 45 | if (WelikeGuard.NOT_NEED_CATCH_CLASSES.contains(e.getClass())) { 46 | super.uncaughtException(t, e); 47 | return; 48 | } 49 | if (e instanceof RuntimeException){ 50 | killSelf(); 51 | }else if (e instanceof UncaughtThrowable) { 52 | super.uncaughtException(t, e); 53 | return; 54 | } 55 | 56 | Catch catchAnnotation = e.getClass().getAnnotation(Catch.class); 57 | UnCatch unCatchAnnotation = e.getClass().getAnnotation(UnCatch.class); 58 | if (catchAnnotation != null && catchAnnotation.process().length() > 0) { 59 | String processMethodName = catchAnnotation.process(); 60 | Class processMethodClass = catchAnnotation.processClass(); 61 | processThrowable(processMethodName, processMethodClass, e, t); 62 | if (WelikeGuard.guardMode == Mode.DONT_CATCH) { 63 | killSelf(); 64 | } 65 | 66 | } else if (unCatchAnnotation != null && unCatchAnnotation.process().length() > 0) { 67 | String processMethodName = catchAnnotation.process(); 68 | Class processMethodClass = catchAnnotation.processClass(); 69 | processThrowable(processMethodName, processMethodClass, e, t); 70 | if (WelikeGuard.guardMode != Mode.CATCH_ALL) { 71 | killSelf(); 72 | } 73 | } 74 | killSelfIfNeed(); 75 | 76 | //下面的代码很多人会难以理解,如果你无法理解, 77 | // 你可以尝试去掉while(true),然后看看异常隔离发生了什么变化. 78 | while (!killSelfIfNeed()) { 79 | 80 | try { 81 | if (Looper.myLooper() == null) { 82 | Looper.prepare(); 83 | } 84 | Looper.loop(); 85 | } catch (Throwable th) { 86 | errorHitCount.incrementAndGet(); 87 | for (Thread.UncaughtExceptionHandler uncaughtExceptionHandler : WelikeGuard.UNCAUGHT_HANDLER_LIST) { 88 | uncaughtExceptionHandler.uncaughtException(t, th); 89 | } 90 | if (e instanceof RuntimeException){ 91 | //如果是RuntimeException,我们不应该继续下去,应该退出, 92 | killSelf(); 93 | } 94 | } 95 | } 96 | 97 | } 98 | 99 | /** 100 | * 处理一个异常 101 | * 102 | * @param processMethodName 处理方法的名称(如:public static void process(Thread t,Throwable e)); 103 | * @param processMethodClass 处理方法所在的类(可以为null) 104 | * @param e 异常 105 | * @param t 抛出异常的线程 106 | */ 107 | private void processThrowable(String processMethodName, Class processMethodClass, Throwable e, Thread t) { 108 | if (processMethodClass == NULL.class) { 109 | try { 110 | invokeProcessMethod(e.getClass(), processMethodName, t); 111 | } catch (Throwable throwable) { 112 | } 113 | } else { 114 | try { 115 | invokeProcessMethod(processMethodClass, processMethodName, t); 116 | 117 | } catch (Throwable throwable) { 118 | } 119 | } 120 | } 121 | 122 | private void invokeProcessMethod(Class clazz, String processMethodName, Thread thread) throws Throwable { 123 | Method method = clazz.getDeclaredMethod(processMethodName, Thread.class); 124 | 125 | if (method != null && Modifier.isStatic(method.getModifiers())) { 126 | method.setAccessible(true); 127 | method.invoke(null, thread); 128 | } 129 | } 130 | 131 | /** 132 | * 看看是不是需要杀掉自己 133 | */ 134 | public boolean killSelfIfNeed() { 135 | if (errorHitCount.get() >= WelikeGuard.MAX_ERROR_COUNT) { 136 | //杀掉自己,以防止死循环直至ANR出现 137 | killSelf(); 138 | 139 | return true; 140 | } 141 | return false; 142 | } 143 | 144 | /** 145 | * 百分百杀掉自己 146 | */ 147 | private void killSelf() { 148 | android.os.Process.killProcess(Process.myPid()); 149 | System.exit(-1); 150 | } 151 | 152 | /** 153 | * 取得当前的异常数量 154 | * 155 | * @return 目前的异常数量 156 | */ 157 | public static int getErrorCount() { 158 | return errorHitCount.get(); 159 | } 160 | } -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/guard/annotation/Catch.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.guard.annotation; 2 | 3 | import com.lody.welike.reflect.NULL; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * @author Lody 12 | * @version 1.0 13 | */ 14 | @Target(ElementType.TYPE) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface Catch { 17 | /** 18 | * process函数所在的类 19 | */ 20 | Class processClass() default NULL.class; 21 | 22 | /** 23 | * 处理函数的名称 24 | */ 25 | String process() default ""; 26 | } 27 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/guard/annotation/UnCatch.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.guard.annotation; 2 | 3 | import com.lody.welike.reflect.NULL; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * @author Lody 12 | * @version 1.0 13 | */ 14 | @Target(ElementType.TYPE) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface UnCatch { 17 | Class processClass() default NULL.class; 18 | 19 | /** 20 | * 处理函数的名称 21 | */ 22 | String process() default ""; 23 | } 24 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/http/DownloadController.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.http; 2 | 3 | import com.lody.welike.http.callback.DownloadCallback; 4 | import com.lody.welike.utils.WeLog; 5 | 6 | import java.io.File; 7 | import java.util.ArrayList; 8 | import java.util.Collections; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | 13 | /** 14 | * 下载控制器, 15 | * 要取得下载进度,请使用{@link DownloadTask#getProgress()}取得下载进度. 16 | * 17 | * @author Lody 18 | * @version 1.4 19 | */ 20 | public class DownloadController { 21 | 22 | /** 23 | * 目前的下载任务 24 | */ 25 | private List downloadTasks = Collections.synchronizedList(new ArrayList()); 26 | /** 27 | * 当下载的任务完成后,就会从downloadTasks中移除,并将状态加入到本表中. 28 | */ 29 | private Map finishUrlToState = new ConcurrentHashMap<>(); 30 | 31 | /** 32 | * 取得指定Url的下载状态 33 | * 34 | * @param url 35 | * @return 36 | */ 37 | public State getDownloadState(String url) { 38 | for (DownloadTask downloadTask : downloadTasks) { 39 | if (downloadTask.getDownloadUrl().equals(url)) { 40 | return downloadTask.getCurrentState(); 41 | } 42 | } 43 | for (String finishUrl : finishUrlToState.keySet()) { 44 | if (finishUrl.equals(url)) { 45 | return finishUrlToState.get(finishUrl); 46 | } 47 | } 48 | return State.NONE; 49 | } 50 | 51 | /** 52 | * 取得下载任务 53 | * 54 | * @param url 55 | * @return 56 | */ 57 | public DownloadTask getDownloadTask(String url) { 58 | 59 | for (DownloadTask downloadTask : downloadTasks) { 60 | if (downloadTask.getDownloadUrl().equals(url)) { 61 | return downloadTask; 62 | } 63 | } 64 | return null; 65 | } 66 | 67 | /** 68 | * 开始一个下载任务,如果任务已经存在,直接返回任务 69 | * 70 | * @param url 下载Url 71 | * @param target 下载到的地方 72 | * @param callback 回调 73 | * @return 74 | */ 75 | public DownloadTask startDownloadTask(String url, File target, DownloadCallback callback) { 76 | 77 | for (DownloadTask downloadTask : downloadTasks) { 78 | if (downloadTask.getTargetFile().equals(target)) { 79 | //如果下载任务存在,就返回下载任务 80 | downloadTask.addCallback(callback); 81 | return downloadTask; 82 | } 83 | } 84 | //创建下载任务 85 | DownloadTask downloadTask = new DownloadTask(this, url, target, callback); 86 | //将下载任务放到任务列表 87 | downloadTasks.add(downloadTask); 88 | downloadTask.execute(); 89 | return downloadTask; 90 | } 91 | 92 | 93 | /** 94 | * 取消指定Url的下载任务 95 | * 96 | * @param url 指定的Url 97 | */ 98 | public void cancelDownloadTask(String url) { 99 | DownloadTask task = getDownloadTask(url); 100 | if (task != null){ 101 | task.cancel(); 102 | } 103 | } 104 | 105 | /** 106 | * 结束一个下载任务 107 | * 108 | * @param task 109 | */ 110 | public void finish(DownloadTask task) { 111 | downloadTasks.remove(task); 112 | finishUrlToState.put(task.getDownloadUrl(), task.getCurrentState()); 113 | } 114 | 115 | /** 116 | * 下载状态 117 | * 118 | * @author Lody 119 | */ 120 | public static enum State { 121 | /** 122 | * 下载中的状态 123 | */ 124 | DOWNLOADING, 125 | /** 126 | * 下载成功状态 127 | */ 128 | SUCCESS, 129 | /** 130 | * 下载失败的状态 131 | */ 132 | FAILED, 133 | /** 134 | * 还没开始下载 135 | */ 136 | NOT_START, 137 | /** 138 | * 任务不存在 139 | */ 140 | NONE, 141 | /** 142 | * 下载任务已经取消 143 | */ 144 | CANCEL, 145 | /** 146 | * 下载任务暂停 147 | */ 148 | PAUSE 149 | 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/http/HttpConfigFactory.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.http; 2 | 3 | /** 4 | * @author Lody 5 | * @version 1.0 6 | */ 7 | public abstract class HttpConfigFactory { 8 | 9 | /** 10 | * @return 默认Http配置 11 | */ 12 | public abstract HttpConfig newDefaultConfig(); 13 | 14 | 15 | public static final class DefaultHttpConfigFactory extends HttpConfigFactory { 16 | 17 | @Override 18 | public HttpConfig newDefaultConfig() { 19 | return new HttpConfig(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/http/HttpRequestBuilder.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.http; 2 | 3 | import com.lody.welike.WelikeHttp; 4 | import com.lody.welike.http.callback.HttpCallback; 5 | 6 | import java.io.File; 7 | import java.util.Map; 8 | 9 | /** 10 | * @author Lody 11 | *
12 | * Http请求构造器,通过本类能够轻松构造一个Http请求, 13 | * 通过{@link WelikeHttp}发送请求. 14 | */ 15 | 16 | public class HttpRequestBuilder { 17 | private String url; 18 | private RequestMethod method = RequestMethod.GET; 19 | private HttpConfig httpConfig; 20 | private HttpParams params; 21 | private HttpCallback callback; 22 | 23 | public HttpRequestBuilder(String url) { 24 | this.url = url; 25 | } 26 | 27 | /** 28 | * 创建一个RequestBuilder 29 | * 30 | * @param url 请求的目标Url 31 | * @return 32 | */ 33 | public static HttpRequestBuilder newBuilder(String url) { 34 | return new HttpRequestBuilder(url); 35 | } 36 | 37 | /** 38 | * 配置请求类型 39 | * 40 | * @param requestMethod 41 | * @return 42 | */ 43 | public HttpRequestBuilder requestMethod(RequestMethod requestMethod) { 44 | this.method = requestMethod; 45 | return this; 46 | } 47 | 48 | /** 49 | * 配置Http配置 50 | * 51 | * @param config 52 | * @return 53 | */ 54 | public HttpRequestBuilder config(HttpConfig config) { 55 | this.httpConfig = config; 56 | return this; 57 | } 58 | 59 | /** 60 | * 配置HttpParam 61 | * 62 | * @param params 63 | * @return 64 | */ 65 | public HttpRequestBuilder withParams(HttpParams params) { 66 | this.params = params; 67 | return this; 68 | } 69 | 70 | /** 71 | * 配置参数 72 | * 73 | * @param params 74 | * @return 75 | */ 76 | public HttpRequestBuilder withParams(Map params) { 77 | if (this.params == null) { 78 | this.params = new HttpParams(); 79 | } 80 | this.params.putAllParams(params); 81 | return this; 82 | } 83 | 84 | /** 85 | * 添加需要上传的文件 86 | * 87 | * @param name 88 | * @param file 89 | * @return 90 | */ 91 | public HttpRequestBuilder withFile(String name, File file) { 92 | if (this.params == null) { 93 | this.params = new HttpParams(); 94 | } 95 | this.params.putFile(name, file); 96 | this.method = RequestMethod.POST; 97 | return this; 98 | } 99 | 100 | /** 101 | * 配置参数 102 | * 103 | * @param params 104 | * @return 105 | */ 106 | public HttpRequestBuilder withParams(@SuppressWarnings("unchecked") T... params) { 107 | if (this.params == null) { 108 | this.params = new HttpParams(); 109 | } 110 | this.params.putParams(params); 111 | return this; 112 | } 113 | 114 | /** 115 | * 配置请求头 116 | * 117 | * @param headers 118 | * @return 119 | */ 120 | public HttpRequestBuilder withHeaders(String... headers) { 121 | if (this.params == null) { 122 | this.params = new HttpParams(); 123 | } 124 | this.params.putHeaders(headers); 125 | return this; 126 | } 127 | 128 | 129 | /** 130 | * 配置请求头 131 | * 132 | * @param headers 133 | * @return 134 | */ 135 | public HttpRequestBuilder withHeaders(Map headers) { 136 | if (this.params == null) { 137 | this.params = new HttpParams(); 138 | } 139 | this.params.putAllHeader(headers); 140 | return this; 141 | } 142 | 143 | 144 | /** 145 | * 配置Http请求的回调 146 | * 147 | * @param callback 148 | * @return 149 | */ 150 | public HttpRequestBuilder callback(HttpCallback callback) { 151 | this.callback = callback; 152 | return this; 153 | } 154 | 155 | /** 156 | * 构造一个{@link HttpRequest}实例. 157 | * 158 | * @return 159 | */ 160 | public HttpRequest build() { 161 | if (this.url == null) { 162 | throw new IllegalArgumentException("URL没传入到HttpRequestBuilder."); 163 | } 164 | if (this.httpConfig == null) { 165 | httpConfig = HttpConfig.newDefaultConfig(); 166 | } 167 | HttpSession session = HttpSessionManager.getManager().getSession(url, method); 168 | return new HttpRequest(session, params, httpConfig, callback); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/http/HttpRequestQueue.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.http; 2 | 3 | import com.lody.welike.WelikeHttp; 4 | import com.lody.welike.http.callback.HttpCallback; 5 | import com.lody.welike.utils.UiHandler; 6 | 7 | import java.util.concurrent.BlockingQueue; 8 | import java.util.concurrent.LinkedBlockingDeque; 9 | 10 | /** 11 | * Http请求的队列循环,负责Http请求的拉取.
12 | * 一个{@link WelikeHttp}实例只有一个{@link HttpRequestQueue}. 13 | * 14 | * @author Lody 15 | */ 16 | public class HttpRequestQueue implements Runnable { 17 | 18 | /** 19 | * Http请求的队列,拉去不到会阻塞. 20 | */ 21 | private BlockingQueue requestQueue = new LinkedBlockingDeque<>(/*MAX*/); 22 | 23 | /** 24 | * 是否已经退出 25 | */ 26 | private boolean mQuit = false; 27 | 28 | /** 29 | * 向队列中添加一个Http请求 30 | * 31 | * @param request 32 | */ 33 | public synchronized void enqueue(HttpRequest request) { 34 | try { 35 | requestQueue.put(request); 36 | } catch (InterruptedException ignored) { 37 | } 38 | } 39 | 40 | @Override 41 | public void run() { 42 | 43 | for (; ; ) {//while(true)的效率不如for(;;),话说,优化效率要从娃娃抓起... 44 | try { 45 | //如果队列中没有请求,就会阻塞,直到填充 46 | final HttpRequest request = requestQueue.take(); 47 | //请求已经取消 48 | if (request.isCancel()) { 49 | synchronized (request) { 50 | final HttpCallback callback = request.getHttpCallback(); 51 | if (callback != null) { 52 | //调用onCancel 53 | runCancelOnUiThread(callback, request); 54 | } 55 | //结束会话 56 | request.getSession().finish(); 57 | } 58 | continue; 59 | } 60 | dispatchRequest(request); 61 | //会话到了这里就算接手完成了 62 | request.getSession().finish(); 63 | 64 | } catch (InterruptedException e) { 65 | if (mQuit) { 66 | break; 67 | } 68 | } 69 | } 70 | 71 | } 72 | 73 | /** 74 | * 在主线程执行onCancel回调 75 | * 76 | * @param callback Http回调 77 | * @param request 取消的Http请求 78 | */ 79 | private void runCancelOnUiThread(final HttpCallback callback, final HttpRequest request) { 80 | UiHandler.runOnUiThread(new Runnable() { 81 | @Override 82 | public void run() { 83 | callback.onCancel(request); 84 | } 85 | }); 86 | } 87 | 88 | /** 89 | * 派发Http请求 90 | * 91 | * @param httpRequest 92 | */ 93 | private void dispatchRequest(final HttpRequest httpRequest) { 94 | UiHandler.runOnUiThread(new Runnable() { 95 | @Override 96 | public void run() { 97 | HttpRequestExecutor.newExecutor(httpRequest).execute(); 98 | } 99 | }); 100 | 101 | } 102 | 103 | /** 104 | * 拉去队列最前端的一个Http请求. 105 | * 106 | * @return 107 | */ 108 | public HttpRequest peekRequest() { 109 | return requestQueue.peek(); 110 | } 111 | 112 | 113 | /** 114 | * 退出,队列不再继续循环. 115 | */ 116 | public void quit() { 117 | synchronized (this) { 118 | cancelAll(); 119 | mQuit = true; 120 | requestQueue.clear(); 121 | } 122 | requestQueue = null; 123 | } 124 | 125 | /** 126 | * 取消队列中的所有任务 127 | */ 128 | public void cancelAll() { 129 | synchronized (this) { 130 | for (HttpRequest request : requestQueue) { 131 | request.cancel(); 132 | } 133 | requestQueue.clear(); 134 | } 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/http/HttpResponse.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.http; 2 | 3 | import java.io.Serializable; 4 | import java.util.HashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | /** 9 | * Http响应的封装 10 | * 11 | * @author lody 12 | * @version 2.0 13 | */ 14 | public class HttpResponse implements Serializable { 15 | 16 | private static final long serialVersionUID = -2291797411702677590L; 17 | /** 18 | * 内容长度 19 | */ 20 | public int contentLength; 21 | /** 22 | * 请求返回的数据 23 | */ 24 | public byte[] data; 25 | /** 26 | * 响应代码 27 | */ 28 | public int responseCode; 29 | /** 30 | * 响应信息 31 | */ 32 | public String responseMessage; 33 | /** 34 | * 错误信息 35 | */ 36 | public String errorMessage; 37 | /** 38 | * 内容的MIME类型 39 | */ 40 | public String contentType; 41 | /** 42 | * 请求内容最后变化的时间 43 | */ 44 | public long lastModifiedTime; 45 | /** 46 | * 请求的编码 47 | */ 48 | public String contentEncoding; 49 | /** 50 | * 返回的响应头 51 | */ 52 | public Map> header; 53 | /** 54 | * Http响应对应的Http请求 55 | */ 56 | public transient HttpRequest httpRequest; 57 | 58 | public void copyFrom(HttpResponse response) { 59 | this.contentLength = response.contentLength; 60 | this.contentEncoding = response.contentEncoding; 61 | this.contentType = response.contentType; 62 | this.data = response.data; 63 | this.errorMessage = response.errorMessage; 64 | copyHeader(response.header); 65 | this.responseCode = response.responseCode; 66 | this.lastModifiedTime = response.lastModifiedTime; 67 | this.responseMessage = response.responseMessage; 68 | } 69 | 70 | /** 71 | * 复制Header,转换为HashMap 72 | * 73 | * @param oldHeader 74 | */ 75 | public void copyHeader(Map> oldHeader) { 76 | //oldHeader的类型为RawHeader$1,是一个内部类,并且没有实现序列化接口, 77 | //因此将它转换为HashMap. 78 | this.header = new HashMap<>(oldHeader.size()); 79 | for (String key : oldHeader.keySet()) { 80 | List value = oldHeader.get(key); 81 | header.put(key, value); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/http/HttpSession.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.http; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.net.HttpURLConnection; 6 | import java.net.URL; 7 | import java.util.Map; 8 | 9 | /** 10 | * 代表一个Http的会话 11 | * 12 | * @author lody 13 | * @version 1.2 14 | */ 15 | public class HttpSession { 16 | 17 | //============================================= 18 | // 字段 19 | //============================================= 20 | /** 21 | * 请求的URL 22 | */ 23 | private String url; 24 | /** 25 | * 请求的方式 26 | */ 27 | private RequestMethod requestMethod = RequestMethod.GET; 28 | 29 | 30 | /** 31 | * @param url 32 | * @param requestMethod 33 | */ 34 | public HttpSession(String url, RequestMethod requestMethod) { 35 | this.url = url; 36 | this.requestMethod = requestMethod; 37 | } 38 | 39 | /** 40 | * 取得请求的URL 41 | * 42 | * @return 43 | */ 44 | public String getUrl() { 45 | return url; 46 | } 47 | 48 | public String getFixUrl() { 49 | return url.startsWith("http://") ? url : "http://" + url; 50 | } 51 | 52 | /** 53 | * 设置请求的URL 54 | * 55 | * @param url 56 | */ 57 | public void setUrl(String url) { 58 | this.url = url; 59 | } 60 | 61 | 62 | /** 63 | * 取得请求的方式 64 | * 65 | * @return 请求方式 66 | */ 67 | public RequestMethod getRequestMethod() { 68 | return requestMethod; 69 | } 70 | 71 | /** 72 | * 设置请求的方式 73 | * 74 | * @param requestMethod 请求方式 75 | */ 76 | public void setRequestMethod(RequestMethod requestMethod) { 77 | this.requestMethod = requestMethod; 78 | } 79 | 80 | /** 81 | * 打开会话的网络连接 82 | * 83 | * @param request Http请求 84 | * @return 请求对应的Http连接 85 | * @throws IOException 86 | */ 87 | public HttpURLConnection open(HttpRequest request) throws IOException { 88 | HttpURLConnection urlConnection; 89 | if (RequestMethod.GET == requestMethod) { 90 | String param = request.getParams().makeParams(request.getHttpConfig().getEncoding()); 91 | String fullUrl = getFixUrl(); 92 | if (param.length() > 1) { 93 | fullUrl += "?" + param; 94 | } 95 | 96 | urlConnection = (HttpURLConnection) new URL(fullUrl).openConnection(); 97 | } else { 98 | urlConnection = (HttpURLConnection) new URL(getFixUrl()).openConnection(); 99 | urlConnection.setUseCaches(false); 100 | urlConnection.setRequestMethod("POST"); 101 | } 102 | request.getParams().setEncoding(request.getHttpConfig().getEncoding()); 103 | 104 | Map uploadFiles = request.getParams().getUploadFiles(); 105 | if (uploadFiles.size() > 0) { 106 | if (requestMethod != RequestMethod.POST) { 107 | throw new IllegalArgumentException("请求需要上传文件,RequestMethod必须为Post方式!"); 108 | } 109 | request.getParams().keepAlive().putHeader("Content-Type", HttpParams.MULTI_PART_FORM_DATA + " boundary=" + request.getParams().boundary); 110 | } 111 | 112 | if (request.getParams().headersSize() > 0) { 113 | for (String key : request.getParams().headerKeySet()) { 114 | urlConnection.addRequestProperty(key, request.getParams().getHeader(key)); 115 | } 116 | } 117 | //我们有自己的缓存机制,所以那套就不需要了 118 | urlConnection.setUseCaches(false); 119 | //设置连接超时 120 | if (request.getConnectTimeout() != 0) { 121 | urlConnection.setConnectTimeout(request.getConnectTimeout()); 122 | } 123 | //设置读取超时 124 | if (request.getReadTimeOut() != 0) { 125 | urlConnection.setReadTimeout(request.getReadTimeOut()); 126 | } 127 | //设置是否允许重定向 128 | urlConnection.setAllowUserInteraction(request.getHttpConfig().isAllowUserInteraction()); 129 | 130 | return urlConnection; 131 | } 132 | 133 | 134 | /** 135 | * 关闭会话 136 | */ 137 | protected void close() { 138 | 139 | } 140 | 141 | /** 142 | * 结束会话 143 | */ 144 | public void finish() { 145 | HttpSessionManager.getManager().finish(this); 146 | this.close(); 147 | } 148 | 149 | 150 | } 151 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/http/HttpSessionManager.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.http; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | /** 7 | * Http会话的管理器 8 | * 9 | * @author lody 10 | * @version 1.2 11 | */ 12 | public class HttpSessionManager { 13 | 14 | /** 15 | * 内部维护一个Http会话管理器的单例 16 | */ 17 | private static class HttpSessionManagerHolder { 18 | static HttpSessionManager INSTANCE = new HttpSessionManager(); 19 | } 20 | 21 | /** 22 | * 取得会话管理器 23 | * 24 | * @return 会话管理器 25 | */ 26 | public static HttpSessionManager getManager() { 27 | return HttpSessionManagerHolder.INSTANCE; 28 | } 29 | 30 | /*package*/ Map urlToSessionMap = new ConcurrentHashMap<>(5); 31 | 32 | /** 33 | * 取出一个会话,会话不存在,则创建会话. 34 | * 35 | * @param url 36 | * @param requestMethod 37 | * @return 38 | */ 39 | public HttpSession getSession(String url, RequestMethod requestMethod) { 40 | HttpSession session = urlToSessionMap.get(url); 41 | if (session == null) { 42 | synchronized (urlToSessionMap) { 43 | session = new HttpSession(url, requestMethod); 44 | urlToSessionMap.put(url, session); 45 | } 46 | } 47 | return session; 48 | } 49 | 50 | /** 51 | * 取得当前会话的数量 52 | * 53 | * @return 54 | */ 55 | public int getSessionSize() { 56 | return urlToSessionMap.size(); 57 | } 58 | 59 | /** 60 | * 结束一个会话 61 | * 62 | * @param session 63 | */ 64 | public void finish(HttpSession session) { 65 | urlToSessionMap.remove(session.getUrl()); 66 | } 67 | 68 | /** 69 | * 结束指定Url的会话 70 | * 71 | * @param url 72 | */ 73 | public void finish(String url) { 74 | if (url != null) { 75 | urlToSessionMap.remove(url); 76 | } 77 | } 78 | 79 | 80 | } 81 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/http/HttpThreadPool.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.http; 2 | 3 | import java.util.concurrent.ArrayBlockingQueue; 4 | import java.util.concurrent.BlockingQueue; 5 | import java.util.concurrent.ThreadFactory; 6 | import java.util.concurrent.ThreadPoolExecutor; 7 | import java.util.concurrent.TimeUnit; 8 | import java.util.concurrent.atomic.AtomicInteger; 9 | 10 | /** 11 | * 优化的线程池,线程池的参数来自{@link android.os.AsyncTask}. 12 | * 13 | * @author Lody 14 | */ 15 | public class HttpThreadPool { 16 | 17 | private HttpThreadPool() { 18 | 19 | } 20 | 21 | // 线程池核心线程数 22 | private static int CORE_POOL_SIZE = 5; 23 | 24 | // 线程池最大线程数 25 | private static int MAX_POOL_SIZE = 100; 26 | 27 | // 额外线程空状态生存时间 28 | private static int KEEP_ALIVE_TIME = 10 * 1000; 29 | 30 | // 阻塞队列。当核心线程都被占用,且阻塞队列已满的情况下,才会开启额外线程。 31 | private static BlockingQueue workQueue = new ArrayBlockingQueue<>( 32 | 10); 33 | 34 | // 线程工厂 35 | private static ThreadFactory threadFactory = new ThreadFactory() { 36 | private final AtomicInteger integer = new AtomicInteger(); 37 | 38 | @Override 39 | public Thread newThread(Runnable r) { 40 | return new Thread(r, "WL-Thread #" 41 | + integer.getAndIncrement()); 42 | } 43 | }; 44 | 45 | // 创建线程池 46 | private static ThreadPoolExecutor threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, 47 | KEEP_ALIVE_TIME, TimeUnit.SECONDS, workQueue, threadFactory); 48 | ; 49 | 50 | /** 51 | * 从线程池中抽取线程,执行指定的Runnable对象 52 | * 53 | * @param runnable 54 | */ 55 | public static void execute(Runnable runnable) { 56 | threadPool.execute(runnable); 57 | } 58 | 59 | /** 60 | * 取得执行器 61 | * 62 | * @return 63 | */ 64 | public static ThreadPoolExecutor getThreadPoolExecutor() { 65 | return threadPool; 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/http/RequestMethod.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.http; 2 | 3 | /** 4 | * Http请求的方式 5 | * 6 | * @author Lody 7 | */ 8 | public enum RequestMethod { 9 | /** 10 | * Post方式的请求 11 | */ 12 | POST, 13 | /** 14 | * Get方式的请求 15 | */ 16 | GET, 17 | } 18 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/http/callback/DownloadCallback.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.http.callback; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * @author Lody 7 | * @version 1.0 8 | */ 9 | public abstract class DownloadCallback { 10 | 11 | /** 12 | * 当下载开始前回调 13 | * 14 | * @param url 15 | */ 16 | public void onDownloadStart(String url) { 17 | } 18 | 19 | /** 20 | * 当下载进度更新时回调 21 | * 22 | * @param completed 完成的进度,总进度为100 23 | */ 24 | public void onProgressUpdate(String url, int completed) { 25 | } 26 | 27 | /** 28 | * 当下载成功后回调 29 | * 30 | * @param url 下载的url 31 | * @param downloadedFile 下载成功生成的文件 32 | */ 33 | public void onDownloadSuccess(String url, File downloadedFile) { 34 | } 35 | 36 | /** 37 | * 当下载失败后回调 38 | */ 39 | public void onDownloadFailed(String url) { 40 | } 41 | 42 | /** 43 | * 下载任务取消时回调 44 | * 45 | * @param url 下载的url 46 | */ 47 | public void onCancel(String url) { 48 | 49 | } 50 | 51 | /** 52 | * 下载任务暂停 53 | * @param url 54 | */ 55 | public void onPause(String url) { 56 | 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/http/callback/FileUploadCallback.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.http.callback; 2 | 3 | import com.lody.welike.http.HttpRequest; 4 | 5 | import java.io.File; 6 | 7 | /** 8 | * @author Lody 9 | * @version 1.0 10 | */ 11 | public class FileUploadCallback extends HttpCallback { 12 | 13 | /** 14 | * 当一个文件开始上传时回调 15 | * 16 | * @param request 17 | * @param file 18 | */ 19 | public void onFileStartUpload(HttpRequest request, File file) { 20 | } 21 | 22 | /** 23 | * 当一个文件上传成功时回调. 24 | * 25 | * @param request 26 | * @param file 27 | */ 28 | public void onFileUploadSuccess(HttpRequest request, File file) { 29 | } 30 | 31 | /** 32 | * 当一个文件上传失败时回调. 33 | * 34 | * @param errorMessage 错误消息 35 | * @param file 上传失败的文件 36 | */ 37 | public void onFileUploadFailed(String errorMessage, File file) { 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/http/callback/HttpBitmapCallback.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.http.callback; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | /** 6 | * 当你需要使用Http请求加载图片时使用本回调. 7 | * 8 | * @author Lody 9 | * @version 1.0 10 | */ 11 | public abstract class HttpBitmapCallback extends HttpCallback { 12 | 13 | /** 14 | * 当一张图片下载成功时回调 15 | * 16 | * @param bitmap 17 | */ 18 | public void onSuccess(Bitmap bitmap) { 19 | } 20 | 21 | /** 22 | * 处理图片时回调,可以自己定义如何加载图片 23 | * @param data 24 | * @return 25 | */ 26 | public Bitmap onProcessBitmap(byte[] data){ 27 | return null; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/http/callback/HttpCallback.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.http.callback; 2 | 3 | import com.lody.welike.http.HttpRequest; 4 | import com.lody.welike.http.HttpResponse; 5 | 6 | /** 7 | * Http请求的回调基础回调, 8 | * 你只需要复写你需要回调的那部分方法. 9 | * 上传文件时可以使用{@link FileUploadCallback}. 10 | * 11 | * @author lody 12 | */ 13 | public abstract class HttpCallback { 14 | 15 | /** 16 | * 开始请求前回调 17 | * 18 | * @param request 19 | */ 20 | public void onPreRequest(HttpRequest request) { 21 | } 22 | 23 | /** 24 | * 请求成功后回调 25 | * 26 | * @param response 27 | */ 28 | public void onSuccess(HttpResponse response) { 29 | } 30 | 31 | /** 32 | * 请求失败后回调 33 | * 34 | * @param response 35 | */ 36 | public void onFailure(HttpResponse response) { 37 | } 38 | 39 | /** 40 | * 请求完成后回调(无论成功与否,都会回调) 41 | * 42 | * @param response 43 | */ 44 | public void onFinish(HttpResponse response) { 45 | } 46 | 47 | /** 48 | * 请求取消时回调 49 | * 50 | * @param request 51 | */ 52 | public void onCancel(HttpRequest request) { 53 | } 54 | 55 | 56 | } 57 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/http/callback/HttpResultCallback.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.http.callback; 2 | 3 | /** 4 | * 如果只关注请求结果的内容,可以选择使用本类. 5 | * 6 | * @author Lody 7 | * @version 1.0 8 | */ 9 | public abstract class HttpResultCallback extends HttpCallback { 10 | 11 | /** 12 | * 请求成功时返回的响应结果文本内容 13 | * 14 | * @param content 15 | */ 16 | public void onSuccess(String content) { 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/reflect/NULL.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.reflect; 2 | 3 | /** 4 | * 用来表示null的类. 5 | * 6 | * @author Lody 7 | * @version 1.0 8 | */ 9 | public class NULL { 10 | } -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/reflect/ReflectException.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.reflect; 2 | 3 | /** 4 | * @author Lody 5 | */ 6 | public class ReflectException extends RuntimeException { 7 | 8 | private static final long serialVersionUID = 663038727503637969L; 9 | 10 | public ReflectException(String message) { 11 | super(message); 12 | } 13 | 14 | public ReflectException(String message, Throwable cause) { 15 | super(message, cause); 16 | } 17 | 18 | public ReflectException() { 19 | super(); 20 | } 21 | 22 | public ReflectException(Throwable cause) { 23 | super(cause); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/ui/DynamicActivityBinder.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.ui; 2 | 3 | import android.app.Activity; 4 | import android.view.View; 5 | import android.widget.Button; 6 | 7 | import com.lody.welike.ui.annotation.InitData; 8 | import com.lody.welike.ui.annotation.JoinView; 9 | 10 | import java.lang.reflect.Field; 11 | import java.lang.reflect.Method; 12 | import java.util.ArrayList; 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.concurrent.ConcurrentHashMap; 17 | 18 | /** 19 | * @author Lody 20 | * @version 1.0 21 | */ 22 | public class DynamicActivityBinder { 23 | 24 | private static Map> activityInitDataMethodMap = new ConcurrentHashMap<>(); 25 | private static Map> activityFieldMap = new HashMap<>(); 26 | 27 | /** 28 | * 遍历所有包含InitData字段的方法,调用它们 29 | * 30 | * @param activity 31 | */ 32 | public static void invokeInitDataMethod(Activity activity) { 33 | List initDataMethod = activityInitDataMethodMap.get(activity.getClass().getName()); 34 | if (initDataMethod == null) { 35 | initDataMethod = new ArrayList<>(2); 36 | for (Method method : activity.getClass().getDeclaredMethods()) { 37 | if (method.getAnnotation(InitData.class) != null) { 38 | method.setAccessible(true); 39 | initDataMethod.add(method); 40 | } 41 | } 42 | activityInitDataMethodMap.put(activity.getClass().getName(), initDataMethod); 43 | } 44 | 45 | for (Method method : initDataMethod) { 46 | try { 47 | method.invoke(activity); 48 | } catch (Throwable ignored) { 49 | } 50 | } 51 | } 52 | 53 | /** 54 | * 遍历所有包含JoinView注解的字段,将它们绑定. 55 | * 56 | * @param activity 57 | */ 58 | public static void joinAllView(WelikeActivity activity) { 59 | List fields = activityFieldMap.get(activity.getClass().getName()); 60 | if (fields == null) { 61 | fields = new ArrayList<>(6); 62 | for (Field field : activity.getClass().getDeclaredFields()) { 63 | JoinView joinView = field.getAnnotation(JoinView.class); 64 | if (joinView != null) { 65 | field.setAccessible(true); 66 | fields.add(field); 67 | } 68 | } 69 | activityFieldMap.put(activity.getClass().getName(), fields); 70 | } 71 | 72 | for (Field field : fields) { 73 | JoinView joinView = field.getAnnotation(JoinView.class); 74 | 75 | int id = joinView.id(); 76 | String name = joinView.name(); 77 | View view = null; 78 | if (id != 0) { 79 | try { 80 | view = activity.findViewById(id); 81 | } catch (Throwable ignored) { 82 | } 83 | } else if (name.trim().length() != 0) { 84 | String packageName = activity.getPackageName(); 85 | id = activity.getResources().getIdentifier(name, "id", packageName); 86 | view = activity.findViewById(id); 87 | } 88 | if (view != null) { 89 | try { 90 | field.set(activity, view); 91 | } catch (Throwable ignored) { 92 | } 93 | if (joinView.click() || field.getType().isAssignableFrom(Button.class)) { 94 | view.setOnClickListener(activity); 95 | } 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/ui/WelikeActivity.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.ui; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | 7 | import com.lody.welike.utils.MultiAsyncTask; 8 | 9 | /** 10 | * 定义了一套回调标准的Activity 11 | * 12 | * @author Lody 13 | * @version 1.2 14 | */ 15 | public class WelikeActivity extends Activity implements View.OnClickListener { 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | 21 | new MultiAsyncTask() { 22 | @Override 23 | public Void onTask(Void... _null) { 24 | //在子线程调用所有包含@initData的方法 25 | DynamicActivityBinder.invokeInitDataMethod(WelikeActivity.this); 26 | return null; 27 | } 28 | 29 | @Override 30 | public void onResult(Void _null) { 31 | super.onResult(_null); 32 | //数据加载完成 33 | onDataLoaded(); 34 | } 35 | }.execute(); 36 | initRootView(savedInstanceState); 37 | initGlobalView(savedInstanceState); 38 | DynamicActivityBinder.joinAllView(this); 39 | initWidget(); 40 | } 41 | 42 | 43 | /** 44 | * 加载根视图.
45 | * 已过期,请视图initRootView(bundle) 46 | * @param savedInstanceState bundle 47 | */ 48 | @Deprecated 49 | public void initGlobalView(Bundle savedInstanceState) { 50 | 51 | } 52 | 53 | /** 54 | * 数据加载完成后回调 55 | */ 56 | public void onDataLoaded() { 57 | } 58 | 59 | /** 60 | * 加载根视图.
61 | */ 62 | public void initRootView(Bundle bundle) { 63 | } 64 | 65 | 66 | /** 67 | * 在这个回调上加载组件 68 | */ 69 | public void initWidget() { 70 | } 71 | 72 | /** 73 | * 当一个Widget被点击时,本方法回调. 74 | * 75 | * @param widget 76 | */ 77 | public void onWidgetClick(View widget) { 78 | } 79 | 80 | 81 | @Override 82 | public final void onClick(View v) { 83 | onWidgetClick(v); 84 | } 85 | 86 | 87 | } 88 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/ui/WelikeToast.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.ui; 2 | 3 | import android.widget.Toast; 4 | 5 | import com.lody.welike.WelikeContext; 6 | 7 | /** 8 | * @author Lody 9 | * @version 1.0 10 | */ 11 | public class WelikeToast { 12 | 13 | /** 14 | * 直接显示一个Toast 15 | * 16 | * @param msg 内容 17 | */ 18 | public static void toast(String msg) { 19 | makeToast(msg).show(); 20 | } 21 | 22 | /** 23 | * 直接返回一个Toast 24 | * 25 | * @param msg 内容 26 | * @return 27 | */ 28 | public static Toast makeToast(String msg) { 29 | return Toast.makeText(WelikeContext.getApplication(), msg, Toast.LENGTH_SHORT); 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/ui/annotation/InitData.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.ui.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * @author Lody 10 | * @version 1.0 11 | */ 12 | @Target(ElementType.METHOD) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface InitData { 15 | } 16 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/ui/annotation/JoinView.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.ui.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * {@link com.lody.welike.ui.WelikeActivity} 会将添加本注解的View自动绑定. 10 | * 免去了findViewByID以及强制转换的繁琐. 11 | * 12 | * @author Lody 13 | * @version 1.0 14 | */ 15 | @Target(ElementType.FIELD) 16 | @Retention(RetentionPolicy.RUNTIME) 17 | public @interface JoinView { 18 | int id() default 0; 19 | 20 | String name() default ""; 21 | 22 | boolean click() default false; 23 | } 24 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/utils/AppUtils.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.utils; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | 7 | import com.lody.welike.WelikeContext; 8 | 9 | /** 10 | * @author Lody 11 | *

12 | * 针对Android SDK版本的工具类 13 | */ 14 | public class AppUtils { 15 | 16 | private static int APP_VERSION = 0; 17 | 18 | /** 19 | * 取得当前App版本号 20 | * 21 | * @return app版本, 获取不到则返回1. 22 | */ 23 | public static int getAppVersion() { 24 | 25 | if (APP_VERSION == 0) { 26 | try { 27 | Context application = WelikeContext.getApplication(); 28 | PackageInfo info = application.getPackageManager().getPackageInfo(application.getPackageName(), 0); 29 | APP_VERSION = info.versionCode; 30 | } catch (PackageManager.NameNotFoundException e) { 31 | APP_VERSION = 1; 32 | } 33 | } 34 | 35 | return APP_VERSION; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/utils/ByteArrayPool.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.utils; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.Comparator; 6 | import java.util.LinkedList; 7 | import java.util.List; 8 | 9 | /** 10 | * 字节数组缓冲池: 11 | *

12 | * byte[] 的回收池,用于 byte[] 的回收再利用,减少了内存的分配和回收。 13 | * 主要通过一个元素长度从小到大排序的ArrayList作为 byte[] 的缓存, 14 | * 另有一个按使用时间先后排序的ArrayList属性用于缓存满时清理元素。 15 | * 16 | * @author Lody 17 | * @version 1.0 18 | */ 19 | public class ByteArrayPool { 20 | 21 | 22 | /** 23 | * ByteArrayPool的单例. 24 | */ 25 | private static ByteArrayPool sPool = new ByteArrayPool(4096); 26 | 27 | /** 28 | * @return ByteArrayPool的单例 29 | */ 30 | public static ByteArrayPool get() { 31 | return sPool; 32 | } 33 | 34 | /** 35 | * 按使用的先后时间顺序排序 36 | */ 37 | private List mBuffersByLastUse = new LinkedList<>(); 38 | /** 39 | * 按大小顺序排序 40 | */ 41 | private List mBuffersBySize = new ArrayList<>(64); 42 | 43 | /** 44 | * 池中所有byte[]的长度之和 45 | */ 46 | private int mCurrentSize = 0; 47 | 48 | /** 49 | * 池中单个byte[]的最大长度 50 | */ 51 | private final int mSizeLimit; 52 | 53 | /** 54 | * 比较器,用于排序,按byte[]的字节长度进行排序 55 | */ 56 | protected static final Comparator BUF_COMPARATOR = new Comparator() { 57 | @Override 58 | public int compare(byte[] lhs, byte[] rhs) { 59 | return lhs.length - rhs.length; 60 | } 61 | }; 62 | 63 | /** 64 | * 创建byte[]缓冲池,并设定池中单个byte[]的最大长度 65 | * 66 | * @param sizeLimit 缓存池上限(字节为单位) 67 | */ 68 | public ByteArrayPool(int sizeLimit) { 69 | mSizeLimit = sizeLimit; 70 | } 71 | 72 | /** 73 | * 从池中获取一个可用的byte[],如果没有,就创建一个。参数为想要获取多大长度的byte[]. 74 | * 75 | * @param len 需要的字节数组的最小长度,取得的数组往往长度大于这个值 76 | * @return 池中的或新建的数组 77 | */ 78 | public synchronized byte[] getBuf(int len) { 79 | //遍历按长度排序的池 80 | for (int i = 0; i < mBuffersBySize.size(); i++) { 81 | byte[] buf = mBuffersBySize.get(i); 82 | //如果当前的byte[]的长度大于给定的长度,就返回该byte[] 83 | if (buf.length >= len) { 84 | //池中所有byte[]的长度之和减去返回出去的byte[]的长度 85 | mCurrentSize -= buf.length; 86 | //从按顺序排列的池中移除该byte[] 87 | mBuffersBySize.remove(i); 88 | //从按使用顺序排列的池中移除该byte[]表示该byte[]正在使用中,其他不能再使用该byte[] 89 | mBuffersByLastUse.remove(buf); 90 | return buf; 91 | } 92 | } 93 | //创建一个新的byte[] 94 | return new byte[len]; 95 | } 96 | 97 | /** 98 | * 当使用完一个byte[]后,将该byte[]返回到池中 99 | * 100 | * @param buf 返回池中的数组 101 | */ 102 | public synchronized void returnBuf(byte[] buf) { 103 | //如果为空或者超过了设定的单个byte[]的最大长度 那么就不再池中保存该byte[] 104 | if (buf == null || buf.length > mSizeLimit) { 105 | return; 106 | } 107 | //在按使用时间顺序排序的池中添加该byte[] 108 | mBuffersByLastUse.add(buf); 109 | //利用二分查找法,找出在按大小排序的池中该byte[]应该存放的位置 110 | int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR); 111 | //如果找不到,则返回-1 112 | if (pos < 0) { 113 | //当找不到时,也就是在0位置添加 114 | pos = -pos - 1; 115 | } 116 | mBuffersBySize.add(pos, buf); 117 | //增加最大长度 118 | mCurrentSize += buf.length; 119 | //清理,不能超过字节总数最大值 120 | trim(); 121 | } 122 | 123 | /** 124 | * 回收字节数组池 125 | */ 126 | private synchronized void trim() { 127 | //当现有字节总数超过了设定的界限,那么需要清理 128 | while (mCurrentSize > mSizeLimit) { 129 | //按照使用的先后顺序来倾全力,最新使用的最先被清除 130 | byte[] buf = mBuffersByLastUse.remove(0); 131 | //同样在该池中也清除 132 | mBuffersBySize.remove(buf); 133 | //减小现有字节最大长度 134 | mCurrentSize -= buf.length; 135 | } 136 | } 137 | 138 | } -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/utils/HashUtils.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.utils; 2 | 3 | import java.security.MessageDigest; 4 | import java.security.NoSuchAlgorithmException; 5 | 6 | /** 7 | * 用于计算Hash值的工具类 8 | * 9 | * @author Lody 10 | */ 11 | public class HashUtils { 12 | 13 | private HashUtils(){} 14 | 15 | /** 16 | * 得到传入的Key的MD5值 17 | * 18 | * @param key 19 | * @return 20 | */ 21 | public static String hashKey(String key) { 22 | String cacheKey; 23 | try { 24 | final MessageDigest mDigest = MessageDigest.getInstance("MD5"); 25 | mDigest.update(key.getBytes()); 26 | cacheKey = bytesToHexString(mDigest.digest()); 27 | } catch (NoSuchAlgorithmException e) { 28 | cacheKey = String.valueOf(key.hashCode()); 29 | } 30 | return cacheKey; 31 | } 32 | 33 | private static String bytesToHexString(byte[] bytes) { 34 | StringBuilder sb = new StringBuilder(); 35 | for (int i = 0; i < bytes.length; i++) { 36 | String hex = Integer.toHexString(0xFF & bytes[i]); 37 | if (hex.length() == 1) { 38 | sb.append('0'); 39 | } 40 | sb.append(hex); 41 | } 42 | return sb.toString(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/utils/IOUtils.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.utils; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.OutputStream; 9 | 10 | /** 11 | * 高效的IO流的操纵类, 12 | * 使用了{@link PoolingByteArrayOutputStream}替代ByteArrayOutputStream以提高性能. 13 | * 14 | * @author Lody 15 | */ 16 | public class IOUtils { 17 | 18 | /** 19 | * 将一个输入流转换为一个byte[]数组. 20 | * 21 | * @param input 22 | * @return 23 | * @throws IOException 24 | */ 25 | public static byte[] toByteArray(InputStream input) 26 | throws IOException { 27 | ByteArrayOutputStream output = new PoolingByteArrayOutputStream(ByteArrayPool.get()); 28 | copy(input, output); 29 | return output.toByteArray(); 30 | } 31 | 32 | /** 33 | * 将一个输入流转换为一个byte[]数组. 34 | * 35 | * @param input 36 | * @return 37 | * @throws IOException 38 | */ 39 | public static byte[] toByteArray(InputStream input, int len) 40 | throws IOException { 41 | 42 | ByteArrayOutputStream output = new PoolingByteArrayOutputStream(ByteArrayPool.get(), len); 43 | copy(input, output); 44 | return output.toByteArray(); 45 | } 46 | 47 | /** 48 | * 将一个输入流拷贝到一个输出流 49 | * 50 | * @param input 51 | * @param output 52 | * @return 53 | * @throws IOException 54 | */ 55 | public static int copy(InputStream input, OutputStream output) 56 | throws IOException { 57 | long count = copyLarge(input, output); 58 | if (count > 2147483647L) { 59 | return -1; 60 | } 61 | return (int) count; 62 | } 63 | 64 | /** 65 | * 将一个输入流拷贝到输出流 66 | * 67 | * @param input 68 | * @param output 69 | * @return 70 | * @throws IOException 71 | */ 72 | public static long copyLarge(InputStream input, OutputStream output) 73 | throws IOException { 74 | byte[] buffer = ByteArrayPool.get().getBuf(5096); 75 | long count = 0L; 76 | int n; 77 | while (-1 != (n = input.read(buffer))) { 78 | output.write(buffer, 0, n); 79 | count += n; 80 | } 81 | return count; 82 | } 83 | 84 | 85 | /** 86 | * 将文件转换为字节数组 87 | */ 88 | public static byte[] getBytes(File f) throws Exception { 89 | FileInputStream in = new FileInputStream(f); 90 | ByteArrayOutputStream out = new PoolingByteArrayOutputStream(ByteArrayPool.get()); 91 | byte[] b = ByteArrayPool.get().getBuf(1024); 92 | int n; 93 | while ((n = in.read(b)) != -1) { 94 | out.write(b, 0, n); 95 | } 96 | out.flush(); 97 | in.close(); 98 | try{ 99 | return out.toByteArray(); 100 | }finally{ 101 | out.close(); 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/utils/NoLeakHandler.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.utils; 2 | 3 | import android.os.Handler; 4 | import android.os.Looper; 5 | import android.os.Message; 6 | 7 | import java.lang.ref.WeakReference; 8 | 9 | 10 | /** 11 | * 不会发生内存泄露的Handler 12 | * (只是一个包装,实际操作对象还是Handler,把它当Handler一样用就好) 13 | * 14 | * @see com.lody.welike.utils.NoLeakHandlerInterface 15 | */ 16 | public class NoLeakHandler implements NoLeakHandlerInterface { 17 | private final NoLeakHandlerInterface _host; 18 | private final WeakRefHandler _handler; 19 | 20 | public NoLeakHandler() { 21 | _host = this; 22 | _handler = new WeakRefHandler(_host); 23 | } 24 | 25 | public NoLeakHandler(NoLeakHandlerInterface host) { 26 | _host = host; 27 | _handler = new WeakRefHandler(_host); 28 | } 29 | 30 | public NoLeakHandler(Looper looper) { 31 | _host = this; 32 | _handler = new WeakRefHandler(looper, _host); 33 | } 34 | 35 | public NoLeakHandler(Looper looper, NoLeakHandlerInterface host) { 36 | _host = host; 37 | _handler = new WeakRefHandler(looper, _host); 38 | } 39 | 40 | public final Handler handler() { 41 | return _handler; 42 | } 43 | 44 | private final NoLeakHandlerInterface innerHandler() { 45 | return _host; 46 | } 47 | 48 | public final void removeMessages(int what) { 49 | handler().removeMessages(what); 50 | } 51 | 52 | public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { 53 | return handler().sendEmptyMessageDelayed(what, delayMillis); 54 | } 55 | 56 | public final boolean sendEmptyMessageDelayedWithRef(int what, long delayMillis) { 57 | Message msg = Message.obtain(handler(), what, innerHandler()); 58 | return handler().sendMessageDelayed(msg, delayMillis); 59 | } 60 | 61 | public final Message obtainMessage(int what, int arg1, int arg2) { 62 | return handler().obtainMessage(what, arg1, arg2); 63 | } 64 | 65 | public final boolean sendMessage(Message msg) { 66 | return handler().sendMessage(msg); 67 | } 68 | 69 | public final boolean sendMessageAtFrontOfQueue(Message msg) { 70 | return handler().sendMessageAtFrontOfQueue(msg); 71 | } 72 | 73 | public final boolean sendEmptyMessage(int what) { 74 | return handler().sendEmptyMessage(what); 75 | } 76 | 77 | public final void removeCallbacksAndMessages(Object token) { 78 | handler().removeCallbacksAndMessages(token); 79 | } 80 | 81 | public final boolean hasMessages(int what) { 82 | return handler().hasMessages(what); 83 | } 84 | 85 | public final Message obtainMessage() { 86 | return handler().obtainMessage(); 87 | } 88 | 89 | public final Message obtainMessage(int what) { 90 | return handler().obtainMessage(what); 91 | } 92 | 93 | public final Message obtainMessage(int what, Object obj) { 94 | return handler().obtainMessage(what, obj); 95 | } 96 | 97 | public final Message obtainMessage(int what, int arg1, int arg2, Object obj) { 98 | return handler().obtainMessage(what, arg1, arg2, obj); 99 | } 100 | 101 | public final Looper getLooper() { 102 | return handler().getLooper(); 103 | } 104 | 105 | public final boolean sendMessageDelayed(Message msg, long delayMillis) { 106 | return handler().sendMessageDelayed(msg, delayMillis); 107 | } 108 | 109 | @Override 110 | public boolean isValid() { 111 | return true; 112 | } 113 | 114 | @Override 115 | public void handleMessage(Message msg) { 116 | } 117 | 118 | /** 119 | * Callback使用弱引用以防内存泄露发生的Handler 120 | */ 121 | private static class WeakRefHandler extends Handler { 122 | private final WeakReference _host; 123 | 124 | public WeakRefHandler(NoLeakHandlerInterface host) { 125 | _host = new WeakReference<>(host); 126 | } 127 | 128 | public WeakRefHandler(Looper looper, NoLeakHandlerInterface host) { 129 | super(looper); 130 | _host = new WeakReference<>(host); 131 | } 132 | 133 | @Override 134 | public void handleMessage(Message msg) { 135 | NoLeakHandlerInterface host = (null != _host) ? _host.get() : null; 136 | if (null != host && host.isValid()) { 137 | host.handleMessage(msg); 138 | } 139 | } 140 | } 141 | 142 | ; 143 | } 144 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/utils/NoLeakHandlerInterface.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.utils; 2 | 3 | import android.os.Looper; 4 | import android.os.Message; 5 | 6 | /** 7 | * @author Lody 8 | * 实现此接口以替代Handler 9 | * @see NoLeakHandler 10 | * @see NoLeakHandler#NoLeakHandler(NoLeakHandlerInterface) 11 | * @see NoLeakHandler#NoLeakHandler(Looper, NoLeakHandlerInterface) 12 | * @see NoLeakHandler#innerHandler() 13 | */ 14 | public interface NoLeakHandlerInterface { 15 | boolean isValid(); 16 | 17 | void handleMessage(Message msg); 18 | } 19 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/utils/PixelDipConverter.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.utils; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | import android.util.DisplayMetrics; 6 | 7 | /** 8 | * Px - Dp 之间的转换工具类 9 | * 10 | * @author Lody 11 | */ 12 | public final class PixelDipConverter { 13 | 14 | private PixelDipConverter() { 15 | } 16 | 17 | /** 18 | * 把Dp转换为Px 19 | * 20 | * @param dp 21 | * @param context 22 | * @return 23 | */ 24 | public static float convertDpToPixel(final float dp, final Context context) { 25 | final Resources resources = context.getResources(); 26 | final DisplayMetrics metrics = resources.getDisplayMetrics(); 27 | return dp * metrics.densityDpi / 160f; 28 | } 29 | 30 | /** 31 | * 把Px转换为Dp 32 | * 33 | * @param px 34 | * @param context 35 | * @return 36 | */ 37 | public static float convertPixelsToDp(final float px, final Context context) { 38 | final Resources resources = context.getResources(); 39 | final DisplayMetrics metrics = resources.getDisplayMetrics(); 40 | return px / (metrics.densityDpi / 160f); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/utils/PoolingByteArrayOutputStream.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.utils; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | 6 | /** 7 | * 继承自ByteArrayOutputStream, 8 | * 自带的 ByteArrayOutputStream 中用于接受写入 bytes 的 buf, 9 | * 每次空间不足时便会 new 一个更大容量的 byte[], 10 | * 而 PoolingByteArrayOutputStream 使用了 {@link ByteArrayPool} 作为 Byte[] 缓存来减少这种操作,从而提高性能。 11 | * 12 | * @author Lody 13 | * @version 1.0 14 | */ 15 | public class PoolingByteArrayOutputStream extends ByteArrayOutputStream { 16 | /** 17 | * 默认byte[]的大小 18 | */ 19 | private static final int DEFAULT_SIZE = 256; 20 | 21 | /** 22 | * byte[]的缓冲池 23 | */ 24 | private final ByteArrayPool mPool; 25 | 26 | /** 27 | * 带byte[]缓冲池的输出流,使用默认的byte[]长度 28 | */ 29 | public PoolingByteArrayOutputStream(ByteArrayPool pool) { 30 | this(pool, DEFAULT_SIZE); 31 | } 32 | 33 | public PoolingByteArrayOutputStream(ByteArrayPool pool, int size) { 34 | mPool = pool; 35 | /** 36 | * buf,该输出流将要内容写入的目标byte[],如果多次写入,buf长度不够的时候需要扩展长度 37 | */ 38 | buf = mPool.getBuf(Math.max(size, DEFAULT_SIZE)); 39 | } 40 | 41 | @Override 42 | public void close() throws IOException { 43 | //当输出流关闭的时候,释放该byte[]回到byte缓冲池中 44 | mPool.returnBuf(buf); 45 | buf = null; 46 | super.close(); 47 | } 48 | 49 | 50 | @Override 51 | public void finalize() { 52 | //当垃圾回收机制准备回收该输出流时,将该byte[]回收到缓冲池 53 | mPool.returnBuf(buf); 54 | } 55 | 56 | /** 57 | * 扩充当前输出流正在使用的byte[]的大小 58 | */ 59 | private void expand(int i) { 60 | if (count + i <= buf.length) { 61 | //当已经写入的字节数加上预计扩展的字节数之和,仍然不大于当前的byte[]的长度时,不需要扩展 62 | return; 63 | } 64 | //当当前的byte[]不再满足时,需要从byte[]缓冲池中获取一个byte[],大小为(count + i) * 2 65 | byte[] newBuf = mPool.getBuf((count + i) * 2); 66 | //将当前的byte[]内容复制到新的byte[]中 67 | System.arraycopy(buf, 0, newBuf, 0, count); 68 | //将旧的byte[]进行回收到byte[]缓冲池中 69 | mPool.returnBuf(buf); 70 | buf = newBuf; 71 | } 72 | 73 | /** 74 | * 从buffer的offset位置读len长度的内容,写入到输出流的byte[](buf)中 75 | */ 76 | @Override 77 | public synchronized void write(byte[] buffer, int offset, int len) { 78 | expand(len); 79 | super.write(buffer, offset, len); 80 | } 81 | 82 | @Override 83 | public synchronized void write(int oneByte) { 84 | //扩展1个字节长度 85 | expand(1); 86 | super.write(oneByte); 87 | } 88 | } -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/utils/ScreenUtils.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.utils; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Rect; 7 | import android.util.DisplayMetrics; 8 | import android.view.View; 9 | import android.view.WindowManager; 10 | 11 | /** 12 | * 屏幕有关的工具类 13 | * 14 | * @author Lody 15 | * @version 1.1 16 | */ 17 | public class ScreenUtils { 18 | 19 | private ScreenUtils() { 20 | } 21 | 22 | 23 | /** 24 | * 获得屏幕宽度和高度 25 | * 26 | * @param context 上下文 27 | * @return 宽度和高度 28 | */ 29 | public static int[] getScreenWidthAndHeight(Context context) { 30 | 31 | WindowManager wm = (WindowManager) context 32 | .getSystemService(Context.WINDOW_SERVICE); 33 | DisplayMetrics outMetrics = new DisplayMetrics(); 34 | wm.getDefaultDisplay().getMetrics(outMetrics); 35 | return new int[]{outMetrics.widthPixels, outMetrics.heightPixels}; 36 | 37 | } 38 | 39 | /** 40 | * 获得屏幕高度 41 | * 42 | * @param context 43 | * @return 宽度 44 | */ 45 | public static int getScreenWidth(Context context) { 46 | 47 | WindowManager wm = (WindowManager) context 48 | .getSystemService(Context.WINDOW_SERVICE); 49 | DisplayMetrics outMetrics = new DisplayMetrics(); 50 | wm.getDefaultDisplay().getMetrics(outMetrics); 51 | return outMetrics.widthPixels; 52 | 53 | } 54 | 55 | /** 56 | * 获得屏幕宽度 57 | * 58 | * @param context 59 | * @return 高度 60 | */ 61 | public static int getScreenHeight(Context context) { 62 | 63 | WindowManager wm = (WindowManager) context 64 | .getSystemService(Context.WINDOW_SERVICE); 65 | DisplayMetrics outMetrics = new DisplayMetrics(); 66 | wm.getDefaultDisplay().getMetrics(outMetrics); 67 | return outMetrics.heightPixels; 68 | 69 | } 70 | 71 | /** 72 | * 获得状态栏的高度 73 | * 74 | * @param context 75 | * @return 状态栏高度 76 | */ 77 | public static int getStatusHeight(Context context) { 78 | 79 | 80 | int statusHeight = -1; 81 | try { 82 | 83 | Class clazz = Class.forName("com.android.internal.R$dimen"); 84 | Object object = clazz.newInstance(); 85 | int height = Integer.parseInt(clazz.getField("status_bar_height") 86 | .get(object).toString()); 87 | statusHeight = context.getResources().getDimensionPixelSize(height); 88 | 89 | } catch (Exception e) { 90 | 91 | e.printStackTrace(); 92 | 93 | } 94 | return statusHeight; 95 | 96 | } 97 | 98 | /** 99 | * 获取当前屏幕截图,包含状态栏 100 | * 101 | * @param activity 102 | * @return 103 | */ 104 | public static Bitmap snapShotWithStatusBar(Activity activity) { 105 | 106 | View view = activity.getWindow().getDecorView(); 107 | view.setDrawingCacheEnabled(true); 108 | view.buildDrawingCache(); 109 | Bitmap bmp = view.getDrawingCache(); 110 | int width = getScreenWidth(activity); 111 | int height = getScreenHeight(activity); 112 | Bitmap bp = null; 113 | bp = Bitmap.createBitmap(bmp, 0, 0, width, height); 114 | view.destroyDrawingCache(); 115 | return bp; 116 | 117 | 118 | } 119 | 120 | /** 121 | * 获取当前屏幕截图,不包含状态栏 122 | * 123 | * @param activity 要截图的Activity 124 | * @return 截图 125 | */ 126 | public static Bitmap snapShotWithoutStatusBar(Activity activity) { 127 | 128 | View view = activity.getWindow().getDecorView(); 129 | view.setDrawingCacheEnabled(true); 130 | view.buildDrawingCache(); 131 | Bitmap bmp = view.getDrawingCache(); 132 | Rect frame = new Rect(); 133 | activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); 134 | int statusBarHeight = frame.top; 135 | 136 | int width = getScreenWidth(activity); 137 | int height = getScreenHeight(activity); 138 | Bitmap bp; 139 | bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height 140 | - statusBarHeight); 141 | view.destroyDrawingCache(); 142 | return bp; 143 | 144 | 145 | } 146 | 147 | 148 | } -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/utils/UiHandler.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.utils; 2 | 3 | 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | 7 | /** 8 | * 封装了在子线程时主线程运行一段逻辑的操作. 9 | * 10 | * @author Lody 11 | * @version 1.0 12 | */ 13 | public class UiHandler { 14 | 15 | private static Handler sUiHandler; 16 | 17 | 18 | /** 19 | * 在主线程运行一段逻辑 20 | * 21 | * @param runnable 22 | */ 23 | public static void runOnUiThread(Runnable runnable) { 24 | initUIHandlerIfNeed(); 25 | sUiHandler.post(runnable); 26 | } 27 | 28 | /** 29 | * 在主线程延时运行一段逻辑 30 | * 31 | * @param runnable 32 | * @param delayMills 33 | */ 34 | public static void runOnUiThreadDelayed(Runnable runnable, long delayMills) { 35 | initUIHandlerIfNeed(); 36 | sUiHandler.postDelayed(runnable, delayMills); 37 | } 38 | 39 | private static void initUIHandlerIfNeed() { 40 | if (sUiHandler == null) { 41 | synchronized (UiHandler.class) { 42 | if (sUiHandler == null) { 43 | sUiHandler = new Handler(Looper.getMainLooper()); 44 | } 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /WelikeAndroid/src/com/lody/welike/utils/WeLog.java: -------------------------------------------------------------------------------- 1 | package com.lody.welike.utils; 2 | 3 | import android.util.Log; 4 | 5 | import com.lody.welike.WelikeContext; 6 | 7 | import java.io.BufferedReader; 8 | import java.io.IOException; 9 | import java.io.InputStreamReader; 10 | 11 | /** 12 | * @author Lody 13 | * Logcat工具类,能够控制Logcat的显示和关闭. 14 | * 同时不需要每次加上TAG,免去繁琐. 15 | */ 16 | public final class WeLog { 17 | 18 | private static String weTag = "We-Like"; 19 | private static boolean openLog = true; 20 | 21 | 22 | private WeLog() { 23 | } 24 | 25 | 26 | /** 27 | * 设置Log标签 28 | * 29 | * @param tag 30 | * @return 31 | */ 32 | public static void setTAG(String tag) { 33 | if (tag != null) { 34 | weTag = tag; 35 | } 36 | 37 | } 38 | 39 | /** 40 | * 打开Log 41 | * 42 | * @return 43 | */ 44 | public static void openLog() { 45 | openLog = true; 46 | } 47 | 48 | /** 49 | * 关闭Log 50 | * 51 | * @return 52 | */ 53 | public static void closeLog() { 54 | openLog = false; 55 | } 56 | 57 | /** 58 | * 打印一个info级别的消息 59 | * 60 | * @param msg 61 | * @return 62 | */ 63 | public static void i(String msg) { 64 | if (openLog) { 65 | Log.i(weTag, msg); 66 | } 67 | } 68 | 69 | /** 70 | * 打印一个debug级别的消息 71 | * 72 | * @param msg 73 | * @return 74 | */ 75 | public static void d(String msg) { 76 | if (openLog) { 77 | Log.d(weTag, msg); 78 | } 79 | } 80 | 81 | /** 82 | * 打印一个verbose级别的消息 83 | * 84 | * @param msg 85 | * @return 86 | */ 87 | public static void v(String msg) { 88 | if (openLog) { 89 | Log.v(weTag, msg); 90 | } 91 | } 92 | 93 | 94 | /** 95 | * 打印一个berbose级别的消息 96 | * 97 | * @param msg 98 | * @return 99 | */ 100 | public static void w(String msg) { 101 | if (openLog) { 102 | Log.w(weTag, msg); 103 | } 104 | } 105 | 106 | /** 107 | * 打印一个error级别的消息 108 | * 109 | * @param msg 110 | * @return 111 | */ 112 | public static void e(String msg) { 113 | if (openLog) { 114 | Log.e(weTag, msg); 115 | } 116 | } 117 | 118 | /** 119 | * 打印一个info级别的消息,并换行 120 | * 121 | * @param msg 122 | * @return 123 | */ 124 | public static void iNewLine(String msg) { 125 | if (openLog) { 126 | Log.i(weTag, msg + "\n"); 127 | } 128 | } 129 | 130 | /** 131 | * 打印一个debug级别的消息,并换行 132 | * 133 | * @param msg 134 | * @return 135 | */ 136 | public static void dNewLine(String msg) { 137 | if (openLog) { 138 | Log.d(weTag, msg + "\n"); 139 | } 140 | } 141 | 142 | /** 143 | * 打印一个verbose级别的消息,并换行 144 | * 145 | * @param msg 146 | * @return 147 | */ 148 | public static void vNewLine(String msg) { 149 | if (openLog) { 150 | Log.v(weTag, msg + "\n"); 151 | } 152 | } 153 | 154 | /** 155 | * 打印一个verbose级别的消息,并换行 156 | * 157 | * @param msg 158 | * @return 159 | */ 160 | public static void wNewLine(String msg) { 161 | if (openLog) { 162 | Log.w(weTag, msg + "\n"); 163 | } 164 | } 165 | 166 | 167 | /** 168 | * 打印一个error级别的消息,并换行 169 | * 170 | * @param msg 171 | * @return 172 | */ 173 | public static void eNewLine(String msg) { 174 | if (openLog) { 175 | Log.e(weTag, msg + "\n"); 176 | } 177 | } 178 | 179 | 180 | /** 181 | * 对超过4000字的log进行分组处理. 182 | * 183 | * @param str 184 | */ 185 | public static void il(String str) { 186 | int length = 3998; 187 | if (str.length() > length) { 188 | Log.i(weTag, "|_" + str.substring(0, length)); 189 | il(str.substring(length)); 190 | } else 191 | Log.i(weTag, "|_" + str); 192 | } 193 | 194 | 195 | /** 196 | * 读取当前应用的Logcat 197 | * 198 | * @return 199 | */ 200 | public static String readLogCat() { 201 | StringBuilder log = new StringBuilder(); 202 | try { 203 | Process process = Runtime.getRuntime().exec("logcat -d -v time " + WelikeContext.getApplication().getPackageName() + ":E *:S"); 204 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); 205 | 206 | String line; 207 | while ((line = bufferedReader.readLine()) != null) { 208 | log.append(line); 209 | } 210 | } catch (IOException e) { 211 | } 212 | return log.toString(); 213 | } 214 | 215 | 216 | } 217 | -------------------------------------------------------------------------------- /WelikeSample/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /WelikeSample/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | WelikeSample 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /WelikeSample/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 3 | org.eclipse.jdt.core.compiler.compliance=1.6 4 | org.eclipse.jdt.core.compiler.source=1.6 5 | -------------------------------------------------------------------------------- /WelikeSample/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /WelikeSample/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalLody/WelikeAndroid/6decca49562606b24f1117c4350b5a5109526984/WelikeSample/ic_launcher-web.png -------------------------------------------------------------------------------- /WelikeSample/libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalLody/WelikeAndroid/6decca49562606b24f1117c4350b5a5109526984/WelikeSample/libs/android-support-v4.jar -------------------------------------------------------------------------------- /WelikeSample/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /WelikeSample/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-22 15 | android.library.reference.1=../WelikeAndroid 16 | -------------------------------------------------------------------------------- /WelikeSample/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalLody/WelikeAndroid/6decca49562606b24f1117c4350b5a5109526984/WelikeSample/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /WelikeSample/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalLody/WelikeAndroid/6decca49562606b24f1117c4350b5a5109526984/WelikeSample/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /WelikeSample/res/drawable-xhdpi/common_btn_green_normal.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalLody/WelikeAndroid/6decca49562606b24f1117c4350b5a5109526984/WelikeSample/res/drawable-xhdpi/common_btn_green_normal.9.png -------------------------------------------------------------------------------- /WelikeSample/res/drawable-xhdpi/common_btn_green_pressed.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalLody/WelikeAndroid/6decca49562606b24f1117c4350b5a5109526984/WelikeSample/res/drawable-xhdpi/common_btn_green_pressed.9.png -------------------------------------------------------------------------------- /WelikeSample/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalLody/WelikeAndroid/6decca49562606b24f1117c4350b5a5109526984/WelikeSample/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /WelikeSample/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalLody/WelikeAndroid/6decca49562606b24f1117c4350b5a5109526984/WelikeSample/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /WelikeSample/res/drawable/common_btn_green.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /WelikeSample/res/drawable/welike_android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FinalLody/WelikeAndroid/6decca49562606b24f1117c4350b5a5109526984/WelikeSample/res/drawable/welike_android.png -------------------------------------------------------------------------------- /WelikeSample/res/layout/bitmap_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 |