├── images └── 0.jpg ├── ic_launcher-web.png ├── libs ├── android-support-v4.jar └── universal-image-loader-1.8.6.jar ├── res ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xhdpi │ ├── ic_launcher.png │ ├── round_conner_bg.9.png │ └── default_round_avatar2.png ├── drawable-xxhdpi │ └── ic_launcher.png ├── values-sw600dp │ └── dimens.xml ├── values │ ├── dimens.xml │ ├── strings.xml │ ├── attrs_weblimitimageview.xml │ └── styles.xml ├── menu │ └── main.xml ├── values-sw720dp-land │ └── dimens.xml ├── values-v11 │ └── styles.xml ├── values-v14 │ └── styles.xml └── layout │ └── activity_main.xml ├── .settings └── org.eclipse.jdt.core.prefs ├── README.md ├── src └── com │ └── example │ ├── cache │ ├── IImageCache.java │ ├── CacheHelper.java │ ├── ImageLoaderHandler.java │ ├── MemImageCache.java │ ├── LocalCache.java │ ├── DiskImageCache.java │ └── ImageLoader.java │ ├── widget │ ├── ArcFourConnerAvatarImageView.java │ ├── WebImageView.java │ ├── WebLimitImageView.java │ └── ArcAvatarImageView.java │ ├── android_arcavatarimageview │ └── MainActivity.java │ ├── MyApp.java │ ├── support │ ├── ConfigWrapper.java │ ├── ConnectivitySupport.java │ ├── MediaFile.java │ └── SystemSupport.java │ └── utils │ ├── ImageLoaderUtils.java │ ├── CommUtils.java │ ├── BitmapUtils.java │ ├── BitmapWorkerTask.java │ └── Utils.java ├── .classpath ├── project.properties ├── proguard-project.txt ├── .project └── AndroidManifest.xml /images/0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/ArcImageView/HEAD/images/0.jpg -------------------------------------------------------------------------------- /ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/ArcImageView/HEAD/ic_launcher-web.png -------------------------------------------------------------------------------- /libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/ArcImageView/HEAD/libs/android-support-v4.jar -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/ArcImageView/HEAD/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/ArcImageView/HEAD/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/ArcImageView/HEAD/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /libs/universal-image-loader-1.8.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/ArcImageView/HEAD/libs/universal-image-loader-1.8.6.jar -------------------------------------------------------------------------------- /res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/ArcImageView/HEAD/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/round_conner_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/ArcImageView/HEAD/res/drawable-xhdpi/round_conner_bg.9.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/default_round_avatar2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xuningjack/ArcImageView/HEAD/res/drawable-xhdpi/default_round_avatar2.png -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /res/values-sw600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ArcImageView 2 | Custom ImageView is designed to support loading network and local image, which has rounded corners, or is rounded (支持加载网络、本地的图片的四角圆角或圆形的ImageView) 3 | 效果图: 4 | ![Alt text](https://github.com/xuningjack/ArcImageView/raw/master/images/0.jpg) 5 | -------------------------------------------------------------------------------- /res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /res/values-sw720dp-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 128dp 8 | 9 | 10 | -------------------------------------------------------------------------------- /res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/com/example/cache/IImageCache.java: -------------------------------------------------------------------------------- 1 | package com.example.cache; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | /** 6 | * 图片缓存的接口 7 | * @author Jack 8 | */ 9 | public interface IImageCache { 10 | 11 | public Bitmap getBitmap(String url); 12 | 13 | public boolean putBitmap(String url, Bitmap bitmap); 14 | 15 | public boolean putBitmap(String url, byte[] imageData); 16 | 17 | public void clearImage(); 18 | 19 | public boolean hasImage(String url); 20 | 21 | public boolean removeImage(String url); 22 | } 23 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Android_ArcAvatarImageView 5 | Settings 6 | Hello world! 7 | 8 | 刚刚 9 | 分钟前 10 | 小时前 11 | 天前 12 | 您没有安装SD卡哦! 13 | SD卡存储空间不足! 14 | 15 | -------------------------------------------------------------------------------- /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-19 15 | -------------------------------------------------------------------------------- /src/com/example/widget/ArcFourConnerAvatarImageView.java: -------------------------------------------------------------------------------- 1 | package com.example.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.util.AttributeSet; 6 | 7 | 8 | 9 | /** 10 | * 四角圆角背景图ImageView 11 | * @author Jack 12 | * @version 创建时间:2013-9-5 下午2:55:12 13 | */ 14 | public class ArcFourConnerAvatarImageView extends ArcAvatarImageView { 15 | 16 | public ArcFourConnerAvatarImageView(Context context, AttributeSet attrs) { 17 | super(context, attrs); 18 | } 19 | 20 | /** 21 | * 圆角头像图片显示 22 | */ 23 | public void setImageBitmap(Bitmap bm) { 24 | setImageBitmapRoundConer(bm); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/com/example/widget/WebImageView.java: -------------------------------------------------------------------------------- 1 | package com.example.widget; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.widget.ImageView; 6 | 7 | 8 | /** 9 | * 可以加载指定url图片的ImageView 10 | */ 11 | public class WebImageView extends ImageView { 12 | 13 | protected String mCurrentUrl; 14 | 15 | public WebImageView(Context context) { 16 | this(context, null); 17 | } 18 | 19 | public WebImageView(Context context, AttributeSet attributes) { 20 | super(context, attributes); 21 | } 22 | 23 | /** 24 | * @return the mImageUrl 25 | */ 26 | public String getImageUrl() { 27 | return mCurrentUrl; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/com/example/cache/CacheHelper.java: -------------------------------------------------------------------------------- 1 | 2 | package com.example.cache; 3 | 4 | /** 5 | * 缓存的辅助类: 6 | * 1、获得url图片的后缀 7 | * 2、由url字符串生成本地文件名。 8 | * @author Jack 9 | */ 10 | 11 | public class CacheHelper { 12 | public static String getSuffix(String remote) { 13 | int start = remote.lastIndexOf("."); 14 | int end = remote.lastIndexOf("?version="); 15 | end = (-1 == end || end <= start) ? remote.length() : end; 16 | String suffix = remote.substring(start, end); 17 | 18 | return suffix; 19 | } 20 | 21 | public static String getFileNameFromUrl(String url) { 22 | // replace all special URI characters with a single + symbol 23 | return url.replaceAll("[:/,%?&=]", "+").replaceAll("[+]+", "+") + getSuffix(url); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Android_ArcAvatarImageView 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 | -------------------------------------------------------------------------------- /res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 14 | 15 | 16 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /res/values/attrs_weblimitimageview.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/com/example/android_arcavatarimageview/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.android_arcavatarimageview; 2 | 3 | import com.example.utils.ImageLoaderUtils; 4 | import com.example.widget.ArcAvatarImageView; 5 | import com.example.widget.ArcFourConnerAvatarImageView; 6 | import com.nostra13.universalimageloader.core.ImageLoader; 7 | import android.os.Bundle; 8 | import android.app.Activity; 9 | 10 | /** 11 | * @author Jack 12 | */ 13 | public class MainActivity extends Activity { 14 | 15 | private ArcAvatarImageView mAvatar; 16 | private ArcFourConnerAvatarImageView mFourAvatar; 17 | private String url = "http://www.baidu.com/img/bdlogo.gif"; 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_main); 23 | 24 | mAvatar = (ArcAvatarImageView)findViewById(R.id.avatar); 25 | ImageLoader.getInstance().displayImage(url, mAvatar, ImageLoaderUtils.getDefaultOptions()); 26 | 27 | mFourAvatar = (ArcFourConnerAvatarImageView)findViewById(R.id.roundconneravatar); 28 | ImageLoader.getInstance().displayImage(url, mFourAvatar, ImageLoaderUtils.getDefaultOptions()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 13 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/com/example/cache/ImageLoaderHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.cache; 2 | 3 | import android.graphics.Bitmap; 4 | import android.os.Bundle; 5 | import android.os.Handler; 6 | import android.os.Message; 7 | 8 | /** 9 | * 线程池中的线程下载完成后的回调Handler基类。 10 | * @author Jack 11 | */ 12 | public abstract class ImageLoaderHandler extends Handler { 13 | @Override 14 | public final void handleMessage(Message msg) { 15 | if (msg.what == ImageLoader.HANDLER_MESSAGE_ID) { 16 | Bundle data = msg.getData(); 17 | String url = data.getString(ImageLoader.IMAGE_URL_EXTRA); 18 | if (data.getBoolean(ImageLoader.IMAGE_LIMIT_EXTRA, false)) { 19 | handleImageLimited(url); 20 | } else { 21 | Bitmap bitmap = (Bitmap) msg.obj; 22 | handleImageLoaded(url, bitmap); 23 | } 24 | } 25 | else if(msg.what==ImageLoader.HANDLER_MESSAGE_ID1){ 26 | handleImagePercent((int)(((double)msg.arg1 / msg.arg2) * 255)); 27 | } 28 | } 29 | 30 | protected boolean handleImageLimited(String url) { 31 | return false; 32 | } 33 | 34 | protected abstract boolean handleImageLoaded(String url, Bitmap bitmap); 35 | 36 | protected abstract boolean handleImagePercent(int percent); 37 | } 38 | -------------------------------------------------------------------------------- /src/com/example/MyApp.java: -------------------------------------------------------------------------------- 1 | package com.example; 2 | 3 | import android.app.Application; 4 | import com.example.cache.ImageLoader; 5 | import com.example.support.ConfigWrapper; 6 | import com.example.utils.BitmapWorkerTask; 7 | import com.example.utils.ImageLoaderUtils; 8 | import com.example.utils.Utils; 9 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; 10 | 11 | public class MyApp extends Application { 12 | 13 | public static int screenWidth; 14 | public static int screenHeight; 15 | 16 | @Override 17 | public void onCreate() { 18 | 19 | super.onCreate(); 20 | ConfigWrapper.initialize(getApplicationContext()); 21 | ImageLoader.initialize(this); 22 | ImageLoader.startConnectivityMonitor(this); 23 | ImageLoader.setThreadPoolSize(10); 24 | ImageLoaderConfiguration config = ImageLoaderUtils 25 | .getApplicationOptions(screenWidth, screenHeight, 26 | getApplicationContext()); 27 | // 配置 28 | com.nostra13.universalimageloader.core.ImageLoader.getInstance().init(config); 29 | } 30 | 31 | public void setScreenWH() { 32 | int[] screenHeightAndWidth = Utils 33 | .getScreenHeightAndWidth(getApplicationContext()); 34 | screenWidth = screenHeightAndWidth[0]; 35 | if (screenWidth <= 480) { 36 | BitmapWorkerTask.getInstance().setMAX_IMAGE_SIZE(false); 37 | } 38 | screenHeight = screenHeightAndWidth[1]; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 8 | 9 | 10 | 17 | 18 | 23 | 24 | 25 | 31 | 32 | 37 | 38 | 43 | 44 | -------------------------------------------------------------------------------- /src/com/example/support/ConfigWrapper.java: -------------------------------------------------------------------------------- 1 | package com.example.support; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | 6 | /** 7 | * 对SharedPreferences的封装 8 | * @author Jack 9 | */ 10 | public class ConfigWrapper { 11 | private static final String PREF_NAME = "config"; 12 | 13 | private static SharedPreferences pref; 14 | 15 | private static SharedPreferences.Editor editor; 16 | 17 | public static void initialize(Context context) { 18 | pref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE); 19 | editor = pref.edit(); 20 | } 21 | 22 | public synchronized static boolean contains(String key) { 23 | return pref.contains(key); 24 | } 25 | 26 | public synchronized static boolean get(String key, boolean defValue) { 27 | return pref.getBoolean(key, defValue); 28 | } 29 | 30 | public synchronized static float get(String key, float defValue) { 31 | return pref.getFloat(key, defValue); 32 | } 33 | 34 | public synchronized static int get(String key, int defValue) { 35 | return pref.getInt(key, defValue); 36 | } 37 | 38 | public synchronized static long get(String key, long defValue) { 39 | return pref.getLong(key, defValue); 40 | } 41 | 42 | public synchronized static String get(String key, String defValue) { 43 | return pref.getString(key, defValue); 44 | } 45 | 46 | public synchronized static void put(String key, boolean value) { 47 | editor.putBoolean(key, value); 48 | } 49 | 50 | public synchronized static void put(String key, float value) { 51 | editor.putFloat(key, value); 52 | } 53 | 54 | public synchronized static void put(String key, int value) { 55 | editor.putInt(key, value); 56 | } 57 | 58 | public synchronized static void put(String key, long value) { 59 | editor.putLong(key, value); 60 | } 61 | 62 | public synchronized static void put(String key, String value) { 63 | editor.putString(key, value); 64 | } 65 | 66 | public synchronized static void commit() { 67 | editor.commit(); 68 | } 69 | 70 | public synchronized static void clear() { 71 | editor.clear(); 72 | } 73 | 74 | public synchronized static void remove(String key) { 75 | editor.remove(key); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/com/example/cache/MemImageCache.java: -------------------------------------------------------------------------------- 1 | package com.example.cache; 2 | 3 | import java.lang.ref.SoftReference; 4 | import java.util.LinkedHashMap; 5 | 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapFactory; 8 | 9 | /** 10 | * 内存-图片缓存:内存中缓存的是SoftReference,而不是真正的Bitmap 11 | * 12 | * @author Jack 13 | */ 14 | public class MemImageCache extends LinkedHashMap> 15 | implements IImageCache { 16 | private static final int DEFAULT_CACHE_CAPACITY = 30; 17 | 18 | private int CACHE_CAPACITY; 19 | 20 | private static final long serialVersionUID = 4687950469523498447L; 21 | 22 | @Override 23 | protected boolean removeEldestEntry(LinkedHashMap.Entry> eldest) { 24 | if (size() > CACHE_CAPACITY) { 25 | return true; 26 | } else 27 | return false; 28 | } 29 | 30 | public MemImageCache() { 31 | this(DEFAULT_CACHE_CAPACITY); 32 | } 33 | 34 | public MemImageCache(int capacity) { 35 | super(capacity / 2, 0.75f, true); 36 | CACHE_CAPACITY = capacity; 37 | } 38 | 39 | @Override 40 | public synchronized Bitmap getBitmap(String url) { 41 | final SoftReference sr = super.get(url); 42 | if (sr != null) { 43 | final Bitmap bitmap = sr.get(); 44 | if (null == bitmap) { 45 | remove(url); 46 | } else { 47 | remove(url); 48 | put(url, sr); 49 | return bitmap; 50 | } 51 | } 52 | return null; 53 | } 54 | 55 | @Override 56 | public synchronized boolean putBitmap(String url, Bitmap bitmap) { 57 | put(url, new SoftReference(bitmap)); 58 | return true; 59 | } 60 | 61 | @Override 62 | public synchronized boolean putBitmap(String url, byte[] imageData) { 63 | boolean result = false; 64 | 65 | if (imageData != null) { 66 | Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0, 67 | imageData.length, null); 68 | result = putBitmap(url, bitmap); 69 | } 70 | 71 | return result; 72 | } 73 | 74 | @Override 75 | public synchronized void clearImage() { 76 | super.clear(); 77 | } 78 | 79 | @Override 80 | public boolean hasImage(String url) { 81 | return super.containsKey(url); 82 | } 83 | 84 | @Override 85 | public boolean removeImage(String url) { 86 | super.remove(url); 87 | return super.containsKey(url); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/com/example/cache/LocalCache.java: -------------------------------------------------------------------------------- 1 | package com.example.cache; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.Collections; 6 | import java.util.Comparator; 7 | import java.util.List; 8 | 9 | import com.example.utils.BitmapWorkerTask; 10 | import com.example.utils.CommUtils; 11 | 12 | import android.content.Context; 13 | 14 | /** 15 | * 本地缓存 16 | * @author Jack 17 | */ 18 | public enum LocalCache { 19 | 20 | /** 图片缓存 */ 21 | IMAGE("image", 50 * 1024 * 1024); 22 | 23 | private static File DIR = null; 24 | private String path; // 路径 25 | private StringBuilder localPathSb; 26 | private long maxSize; // 最大大小 27 | 28 | private LocalCache(String name, long maxSize) { 29 | this.path = name; 30 | this.maxSize = maxSize; 31 | } 32 | 33 | public File getPath(Context ctx) { 34 | File dir = new File(getDir(ctx), path); 35 | dir.mkdirs(); 36 | return dir; 37 | } 38 | 39 | public String getLocalImgPath(Context ctx, String url) { 40 | if (localPathSb == null) localPathSb = new StringBuilder(); 41 | if (DIR == null) getDir(ctx); 42 | synchronized (localPathSb) { 43 | localPathSb.delete(0, localPathSb.length()); 44 | localPathSb.append(DIR.getAbsolutePath()).append("/") 45 | .append(CommUtils.getMD5(url)); 46 | } 47 | return localPathSb.toString(); 48 | } 49 | 50 | /** 51 | * 清空缓存 52 | * @param ctx 53 | */ 54 | public static void clear(Context ctx) { 55 | List fileList = fileList(getDir(ctx)); 56 | for (File file : fileList) { 57 | file.delete(); 58 | } 59 | BitmapWorkerTask.getInstance().clearImageCache(); 60 | BitmapWorkerTask.getInstance().clearLoadCache(); 61 | } 62 | 63 | /** 64 | * 检查缓存大小 65 | * @param ctx 66 | * @param cachePath 67 | */ 68 | public static long checkSize(Context ctx) { 69 | long size = 0; 70 | for (LocalCache cache : values()) { 71 | List fileList = fileList(getDir(ctx)); 72 | 73 | //文件最后修改时间排序 74 | Collections.sort(fileList, new Comparator() { 75 | @Override 76 | public int compare(File f1, File f2) { 77 | return (int) (f2.lastModified() - f1.lastModified()); 78 | } 79 | }); 80 | 81 | for (File file : fileList) { 82 | if (size <= cache.maxSize) { 83 | size += file.length(); 84 | } else file.delete(); 85 | } 86 | } 87 | return size; 88 | } 89 | 90 | /** 91 | * 获得目录 92 | */ 93 | private static File getDir(Context ctx) { 94 | if (DIR != null) return DIR; 95 | DIR = ctx.getCacheDir(); 96 | DIR.mkdirs(); 97 | return DIR; 98 | } 99 | 100 | /** 101 | * 获得文件列表 102 | */ 103 | private static List fileList(File dir) { 104 | List fileList = new ArrayList(); 105 | if (dir == null || !dir.canWrite() || !dir.canRead()) return fileList; 106 | if (dir.isFile()) { 107 | fileList.add(dir); 108 | return fileList; 109 | } 110 | 111 | String fileArray[] = dir.list(); 112 | for (String name : fileArray) { 113 | File file = new File(dir, name); 114 | if (file.isFile()) fileList.add(file); 115 | else fileList.addAll(fileList(file));//递归 116 | } 117 | 118 | return fileList; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /src/com/example/widget/WebLimitImageView.java: -------------------------------------------------------------------------------- 1 | package com.example.widget; 2 | 3 | import java.util.Map.Entry; 4 | import java.util.WeakHashMap; 5 | 6 | import android.content.Context; 7 | import android.content.res.TypedArray; 8 | import android.graphics.Bitmap; 9 | import android.graphics.drawable.BitmapDrawable; 10 | import android.text.TextUtils; 11 | import android.util.AttributeSet; 12 | import android.view.View; 13 | 14 | import com.example.android_arcavatarimageview.R; 15 | import com.example.utils.BitmapWorkerTask; 16 | import com.example.utils.BitmapWorkerTask.Callback; 17 | import com.example.utils.Utils; 18 | 19 | 20 | 21 | /** 22 | * 具有二级缓存的、能够限制自动下载的、网络图片ImageView。 23 | * @author Jack 24 | */ 25 | public class WebLimitImageView extends WebImageView { 26 | 27 | protected boolean mIsLoadSmallImg = false; 28 | protected final int limit_background; 29 | protected final int limit_background_loading; 30 | protected WeakHashMap mListeners; 31 | 32 | @Override 33 | public boolean isInEditMode() { 34 | return true; 35 | } 36 | 37 | /** 38 | * @param context 39 | */ 40 | public WebLimitImageView(Context context) { 41 | this(context, null); 42 | } 43 | 44 | /** 45 | * @param context 46 | * @param attributes 47 | */ 48 | public WebLimitImageView(Context context, AttributeSet attrs) { 49 | super(context, attrs); 50 | TypedArray a = context.obtainStyledAttributes(attrs, 51 | R.styleable.WebLimitImageView); 52 | limit_background = a.getResourceId( 53 | R.styleable.WebLimitImageView_limit_background, 54 | android.R.drawable.ic_dialog_info); 55 | limit_background_loading = a.getResourceId( 56 | R.styleable.WebLimitImageView_limit_background_loading, 57 | android.R.drawable.ic_dialog_alert); 58 | a.recycle(); 59 | } 60 | 61 | public void setLoadSmallImg(boolean isLoadSmallImg) { 62 | mIsLoadSmallImg = isLoadSmallImg; 63 | } 64 | 65 | /** 66 | * 传入的是本地地址,不要传入网络url地址 67 | * @param path 68 | */ 69 | public void loadLocalImage(String path) { 70 | if(path == null || path.length() == 0) return; 71 | Bitmap bitmap = null; 72 | try { 73 | if(mIsLoadSmallImg) { 74 | bitmap = Utils.createSmallBitmap(path); 75 | } else { 76 | bitmap = Utils.create1MBitmap(path); 77 | } 78 | } catch (OutOfMemoryError e) { 79 | e.printStackTrace(); 80 | } 81 | if(bitmap != null) { 82 | setImageDrawable(new BitmapDrawable(getResources(), bitmap)); 83 | } 84 | } 85 | 86 | /** 87 | * @param url 88 | */ 89 | public void loadWebImage(String url) { 90 | mCurrentUrl = url; 91 | Callback callback = new Callback() { 92 | 93 | @Override 94 | public void setImage(View v, Bitmap img, String url) { 95 | if (img != null) { 96 | // 如果是当前View的url 97 | if (!TextUtils.isEmpty(mCurrentUrl) && mCurrentUrl.equalsIgnoreCase(url)) { 98 | setImageDrawable(new BitmapDrawable(getContext().getResources(), img)); 99 | } else { 100 | img.recycle(); 101 | } 102 | if (mListeners != null && !mListeners.isEmpty()) { 103 | for (Entry entry : mListeners.entrySet()) { 104 | entry.getKey().onImagLoadFinish(); 105 | } 106 | } 107 | } 108 | } 109 | 110 | @Override 111 | public boolean isContinue() { 112 | return true; 113 | } 114 | 115 | @Override 116 | public Bitmap formatBitmap(Bitmap img) { 117 | return img; 118 | } 119 | }; 120 | loadWebImage(url, callback, true); 121 | } 122 | 123 | /** 124 | * @param url 125 | * @param position ListView中不同位置用于判断同一张图片 126 | * @param callback 127 | * @param isCache 128 | */ 129 | public void loadWebImage(String url, Callback callback, boolean isCache) { 130 | BitmapWorkerTask.getInstance().load(this, url, callback, isCache); 131 | } 132 | 133 | public void setOnImageLoadFinish(OnLoadFinish l) { 134 | if (mListeners == null) mListeners = new WeakHashMap(); 135 | if (!mListeners.containsKey(l)) mListeners.put(l, ""); 136 | } 137 | 138 | public interface OnLoadFinish { 139 | void onImagLoadFinish(); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/com/example/support/ConnectivitySupport.java: -------------------------------------------------------------------------------- 1 | package com.example.support; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Timer; 6 | import java.util.TimerTask; 7 | 8 | import android.content.Context; 9 | import android.net.ConnectivityManager; 10 | import android.net.NetworkInfo; 11 | 12 | /** 13 | * 网络状态监听器,单实例 14 | * @author Jack 15 | * @version 创建时间:2014-3-6 上午9:47:39 16 | */ 17 | public class ConnectivitySupport { 18 | 19 | public enum NetState { 20 | NET_NOT_CONNECT, // 没有网落连接 21 | 22 | NET_CONNECT_WIFI, // WIFI 23 | 24 | NET_CONNECT_MOBILE, // MOBILE.3GNET / MOBILE.CMNET / MOBILE.UNINET / 25 | // MOBILE.CTNET / MOBILE.INTERNET 26 | 27 | NET_CONNECT_WAP, // MOBILE.WAP 28 | 29 | NET_CONNECT_UNKNOW, // 未知的网络连接类型 30 | } 31 | 32 | public static final String APN_3G = "3GNET"; 33 | 34 | public static final String APN_CMNET = "CMNET"; 35 | 36 | public static final String APN_UNINET = "UNINET"; 37 | 38 | public static final String APN_CTNET = "CTNET"; 39 | 40 | public static final String APN_INTERNET = "INTERNET"; 41 | 42 | public static final int DEFAULT_DELAY = 0; 43 | 44 | public static final int DEFAULT_PERIOD = 4 * 1000; 45 | 46 | public static NetState getConnectivityState(Context context) { 47 | NetState net_state = NetState.NET_NOT_CONNECT; 48 | ConnectivityManager connMgr = (ConnectivityManager) context 49 | .getSystemService(Context.CONNECTIVITY_SERVICE); 50 | NetworkInfo netinfo = connMgr.getActiveNetworkInfo(); 51 | if (null != netinfo && netinfo.isAvailable() && netinfo.isConnected()) { 52 | int nettype = netinfo.getType(); 53 | switch (nettype) { 54 | case ConnectivityManager.TYPE_WIFI: 55 | net_state = NetState.NET_CONNECT_WIFI; 56 | break; 57 | case ConnectivityManager.TYPE_MOBILE: 58 | String extrainfo = netinfo.getExtraInfo(); 59 | if (null != extrainfo) { 60 | if (APN_3G.equalsIgnoreCase(extrainfo) 61 | || APN_CMNET.equalsIgnoreCase(extrainfo) 62 | || APN_UNINET.equalsIgnoreCase(extrainfo) 63 | || APN_CTNET.equalsIgnoreCase(extrainfo) 64 | || APN_INTERNET.equalsIgnoreCase(extrainfo)) { 65 | net_state = NetState.NET_CONNECT_MOBILE; 66 | } else { 67 | net_state = NetState.NET_CONNECT_UNKNOW; 68 | } 69 | } else { 70 | net_state = NetState.NET_CONNECT_WAP; 71 | } 72 | break; 73 | default: 74 | net_state = NetState.NET_CONNECT_UNKNOW; 75 | break; 76 | } 77 | } else { 78 | net_state = NetState.NET_NOT_CONNECT; 79 | } 80 | return net_state; 81 | } 82 | 83 | public interface IConnectivityListener { 84 | public void onConnectivityChanged(NetState oldstate, NetState newstate); 85 | } 86 | 87 | private NetState mNetState = NetState.NET_CONNECT_WIFI; 88 | 89 | private Timer mTimer; 90 | 91 | private List mListeners = new ArrayList( 92 | 3); 93 | 94 | private static ConnectivitySupport s_intance; 95 | 96 | private ConnectivitySupport() { 97 | } 98 | 99 | public static ConnectivitySupport getInstance() { 100 | if (null == s_intance) { 101 | s_intance = new ConnectivitySupport(); 102 | } 103 | return s_intance; 104 | } 105 | 106 | public NetState getNetState() { 107 | return mNetState; 108 | } 109 | 110 | public void registerConnectivityListener(Context context, 111 | IConnectivityListener listener) { 112 | if (!mListeners.contains(listener)) { 113 | mListeners.add(listener); 114 | if (1 == mListeners.size()) { 115 | mTimer = startConnectivityMonitor(context); 116 | } 117 | } 118 | } 119 | 120 | public void unregisterConnectivityListener(IConnectivityListener listener) { 121 | mListeners.remove(listener); 122 | if (0 == mListeners.size()) { 123 | mTimer.cancel(); 124 | } 125 | } 126 | 127 | private Timer startConnectivityMonitor(final Context context) { 128 | Timer timer = new Timer(true); 129 | timer.schedule(new TimerTask() { 130 | @Override 131 | public void run() { 132 | NetState state = getConnectivityState(context); 133 | if (mNetState != state) { 134 | for (IConnectivityListener listener : mListeners) { 135 | listener.onConnectivityChanged(mNetState, state); 136 | } 137 | mNetState = state; 138 | } 139 | } 140 | }, DEFAULT_DELAY, DEFAULT_PERIOD); 141 | return timer; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/com/example/widget/ArcAvatarImageView.java: -------------------------------------------------------------------------------- 1 | package com.example.widget; 2 | 3 | import java.util.Map.Entry; 4 | 5 | import android.content.Context; 6 | import android.content.res.TypedArray; 7 | import android.graphics.Bitmap; 8 | import android.text.TextUtils; 9 | import android.util.AttributeSet; 10 | import android.view.MotionEvent; 11 | import android.view.View; 12 | 13 | import com.example.android_arcavatarimageview.R; 14 | import com.example.cache.ImageLoader; 15 | import com.example.cache.ImageLoaderHandler; 16 | import com.example.utils.BitmapUtils; 17 | import com.example.utils.BitmapWorkerTask.Callback; 18 | 19 | /** 20 | * 圆形头像 继承自WebLimitImageView 21 | * @author Jack 22 | */ 23 | public class ArcAvatarImageView extends WebLimitImageView { 24 | 25 | private boolean mIsLoad = false; 26 | private boolean mIsLimit = false; 27 | private final int limit_background; 28 | private final int limit_background_loading; 29 | 30 | 31 | /** 32 | * 33 | * @param context 34 | * @param attrs 35 | */ 36 | public ArcAvatarImageView(Context context, AttributeSet attrs) { 37 | 38 | super(context, attrs); 39 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WebLimitImageView); 40 | limit_background = a.getResourceId(R.styleable.WebLimitImageView_limit_background, 41 | android.R.drawable.ic_dialog_info); 42 | limit_background_loading = a.getResourceId( 43 | R.styleable.WebLimitImageView_limit_background_loading, 44 | android.R.drawable.ic_dialog_alert); 45 | a.recycle(); 46 | } 47 | 48 | @Override 49 | public void loadWebImage(String url) { 50 | mCurrentUrl = url; 51 | Callback callback = new Callback() { 52 | 53 | @Override 54 | public void setImage(View v, Bitmap img, String url) { 55 | if (img != null) { 56 | // 如果是当前View的url 57 | if (!TextUtils.isEmpty(mCurrentUrl) && mCurrentUrl.equalsIgnoreCase(url)) { 58 | setImageBitmap(BitmapUtils.getRoundCornerImage(img, 5)); 59 | } else { 60 | img.recycle(); 61 | } 62 | if (mListeners != null && !mListeners.isEmpty()) { 63 | for (Entry entry : mListeners.entrySet()) { 64 | entry.getKey().onImagLoadFinish(); 65 | } 66 | } 67 | } 68 | } 69 | 70 | @Override 71 | public boolean isContinue() { 72 | return true; 73 | } 74 | 75 | @Override 76 | public Bitmap formatBitmap(Bitmap img) { 77 | return img; 78 | } 79 | }; 80 | loadWebImage(url, callback, true); 81 | } 82 | 83 | private class WebLimitImageViewHandler extends ImageLoaderHandler { 84 | @Override 85 | protected boolean handleImageLoaded(String url, Bitmap bitmap) { 86 | if (url.equalsIgnoreCase(mCurrentUrl)) { 87 | if (null != bitmap) { 88 | setImageBitmap(BitmapUtils.getRoundCornerImage(bitmap, 5)); 89 | requestLayout(); 90 | invalidate(); 91 | mIsLoad = true; 92 | return true; 93 | } 94 | } 95 | return false; 96 | } 97 | @Override 98 | protected boolean handleImageLimited(String url) { 99 | if (url.equalsIgnoreCase(mCurrentUrl)) { 100 | mIsLimit = true; 101 | setImageResource(limit_background); 102 | } 103 | return false; 104 | } 105 | @Override 106 | protected boolean handleImagePercent(int percent) { 107 | return false; 108 | } 109 | } 110 | 111 | /** 112 | * 圆角头像图片显示 113 | */ 114 | @Override 115 | public void setImageBitmap(Bitmap bm) { 116 | super.setImageBitmap(BitmapUtils.toRoundBitmap(bm)); //图片圆形显示 117 | } 118 | 119 | /** 120 | * 图片四角带弧度显示 121 | * @param bm 122 | */ 123 | public void setImageBitmapRoundConer(Bitmap bm) { 124 | super.setImageBitmap(BitmapUtils.getRoundCornerImage(bm, 5)); //图片四角带弧度显示 125 | } 126 | 127 | 128 | @Override 129 | public boolean onTouchEvent(MotionEvent event) { 130 | if (mIsLimit && !mIsLoad && null != mCurrentUrl) { 131 | switch (event.getAction()) { 132 | case MotionEvent.ACTION_DOWN: 133 | ImageLoader.start(mCurrentUrl, new WebLimitImageViewHandler()); 134 | setImageResource(limit_background_loading); 135 | return true; 136 | case MotionEvent.ACTION_CANCEL: 137 | case MotionEvent.ACTION_UP: 138 | case MotionEvent.ACTION_OUTSIDE: 139 | return false; 140 | } 141 | } 142 | return super.onTouchEvent(event); 143 | } 144 | } -------------------------------------------------------------------------------- /src/com/example/cache/DiskImageCache.java: -------------------------------------------------------------------------------- 1 | package com.example.cache; 2 | 3 | import java.io.BufferedOutputStream; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | 9 | import android.content.Context; 10 | import android.graphics.Bitmap; 11 | import android.os.Environment; 12 | import android.util.Log; 13 | 14 | import com.example.utils.BitmapUtils; 15 | 16 | /** 17 | * 本地磁盘-图片缓存 18 | * @author Jack 19 | */ 20 | public class DiskImageCache implements IImageCache { 21 | 22 | private static String mRootDir; 23 | private static Context mContext; 24 | 25 | public static String getDiskCacheDir() { 26 | return mRootDir; 27 | } 28 | 29 | public DiskImageCache(Context context) { 30 | Context appContext = context.getApplicationContext(); 31 | mContext = appContext; 32 | 33 | if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { 34 | // SD-card available 35 | mRootDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + appContext.getPackageName() + "/cache"; 36 | } 37 | else { 38 | File internalCacheDir = appContext.getCacheDir(); 39 | // apparently on some configurations this can come back as null 40 | mRootDir = internalCacheDir.getAbsolutePath(); 41 | } 42 | 43 | File outFile = new File(mRootDir); 44 | if (outFile.mkdirs()) { 45 | File nomedia = new File(mRootDir, ".nomedia"); 46 | try { 47 | nomedia.createNewFile(); 48 | } 49 | catch (IOException e) { 50 | Log.w("l99", e); 51 | } 52 | } 53 | } 54 | 55 | public static String getLocalPathFromUrl(String url) { 56 | String filename = CacheHelper.getFileNameFromUrl(url); 57 | return new StringBuilder(mRootDir).append(File.separator).append(filename).toString(); 58 | } 59 | 60 | @Override 61 | public synchronized Bitmap getBitmap(String url) { 62 | Bitmap bitmap = null; 63 | String path = getLocalPathFromUrl(url); 64 | /* 65 | File file = new File(path); 66 | if (file.exists()) { 67 | try { 68 | BitmapFactory.Options opts = new BitmapFactory.Options(); 69 | DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); 70 | opts.inTargetDensity = metrics.densityDpi; 71 | opts.inScaled = true; 72 | 73 | opts.inDither = false; // Disable Dithering mode 74 | opts.inPurgeable = true; // Tell to gc that whether it needs free memory, the Bitmap can be cleared 75 | opts.inInputShareable = true; 76 | 77 | bitmap = BitmapFactory.decodeFile(path, opts); 78 | } catch (Throwable e) { 79 | Log.w("l99", e); 80 | } 81 | if (null == bitmap) { 82 | Log.e("l99", String.format("Diskcache decode file failed:(url=%s)", url)); 83 | file.delete(); 84 | } 85 | } 86 | else { 87 | //Log.d("l99", "Disk Cache the file does not exist: " + path); 88 | } 89 | return bitmap;*/ 90 | bitmap = BitmapUtils.decodeBitmapFromDescriptor(mContext, path); 91 | return bitmap; 92 | } 93 | 94 | @Override 95 | public synchronized boolean putBitmap(String url, Bitmap bitmap) { 96 | boolean result = false; 97 | 98 | String path = getLocalPathFromUrl(url); 99 | String suffix = CacheHelper.getSuffix(path); 100 | 101 | Bitmap.CompressFormat format = Bitmap.CompressFormat.JPEG; 102 | if (suffix.equalsIgnoreCase(".png")) { 103 | format = Bitmap.CompressFormat.PNG; 104 | } 105 | 106 | try { 107 | FileOutputStream fos = new FileOutputStream(path); 108 | result = bitmap.compress(format, 100, fos); 109 | } catch (FileNotFoundException e) { 110 | Log.w("l99", e); 111 | } 112 | 113 | return result; 114 | } 115 | 116 | @Override 117 | public synchronized boolean putBitmap(String url, byte[] imageData) { 118 | boolean result = false; 119 | 120 | String path = getLocalPathFromUrl(url); 121 | File file = new File(path); 122 | if (file.exists()) { 123 | // file.delete(); 124 | result = true; 125 | Log.e("l99", String.format("Diskcache file already exist: url=%s", url)); 126 | } else { 127 | try { 128 | file.createNewFile(); 129 | BufferedOutputStream ostream = new BufferedOutputStream(new FileOutputStream(file), 8192); 130 | ostream.write(imageData); 131 | ostream.close(); 132 | 133 | result = true; 134 | } catch (FileNotFoundException e) { 135 | Log.w("l99", e); 136 | } catch (IOException e) { 137 | Log.w("l99", e); 138 | } 139 | } 140 | 141 | return result; 142 | } 143 | 144 | @Override 145 | public synchronized void clearImage() { 146 | } 147 | 148 | @Override 149 | public synchronized boolean hasImage(String url) { 150 | String path = DiskImageCache.getLocalPathFromUrl(url); 151 | return new File(path).exists(); 152 | } 153 | 154 | @Override 155 | public synchronized boolean removeImage(String url) { 156 | boolean result = false; 157 | String path = DiskImageCache.getLocalPathFromUrl(url); 158 | File file = new File(path); 159 | if (file.exists()) { 160 | result = file.delete(); 161 | Log.e("l99", String.format("Delete bad image %s: %s.", url, result)); 162 | } 163 | return result; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/com/example/utils/ImageLoaderUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.utils; 2 | 3 | import java.io.File; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Bitmap.CompressFormat; 7 | import com.example.android_arcavatarimageview.R; 8 | import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache; 9 | import com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache; 10 | import com.nostra13.universalimageloader.core.DisplayImageOptions; 11 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; 12 | import com.nostra13.universalimageloader.core.assist.ImageScaleType; 13 | import com.nostra13.universalimageloader.core.assist.QueueProcessingType; 14 | import com.nostra13.universalimageloader.utils.StorageUtils; 15 | 16 | 17 | /** 18 | * 图片加载配置工具类 19 | * @author Jack 20 | */ 21 | public class ImageLoaderUtils { 22 | 23 | public static ImageLoaderConfiguration getApplicationOptions(int width,int height,Context context){ 24 | File cacheDir = StorageUtils.getCacheDirectory(context); 25 | ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context) 26 | // .memoryCacheExtraOptions(width,height) 27 | // .discCacheExtraOptions(width, height, CompressFormat.JPEG, 70, null) 28 | /** 长图保存最大高度为屏幕的屏高*5 **/ 29 | .memoryCacheExtraOptions(width, height*5) 30 | // .discCacheExtraOptions(width, height*5, CompressFormat.JPEG, 75, null) 31 | .threadPoolSize(5) // default 32 | // .threadPriority(Thread.NORM_PRIORITY - 1) // default 33 | .tasksProcessingOrder(QueueProcessingType.FIFO) // default 34 | .memoryCache(new LruMemoryCache(4 * 1024 * 1024)) 35 | .memoryCacheSize(4 * 1024 * 1024) 36 | .discCache(new UnlimitedDiscCache(cacheDir)) // default 37 | .discCacheSize(50 * 1024 * 1024) 38 | .discCacheFileCount(100) 39 | .writeDebugLogs() 40 | .build(); 41 | return config; 42 | } 43 | 44 | public static ImageLoaderConfiguration getMediaLoadOptions(int width,int height,Context context){ 45 | File cacheDir = StorageUtils.getCacheDirectory(context); 46 | ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context) 47 | .memoryCacheExtraOptions(width,height) 48 | .discCacheExtraOptions(width, height, CompressFormat.JPEG, 70, null) 49 | .threadPoolSize(30) // default 50 | // .threadPriority(Thread.NORM_PRIORITY - 1) // default 51 | .tasksProcessingOrder(QueueProcessingType.FIFO) // default 52 | .memoryCache(new LruMemoryCache(4 * 1024 * 1024)) 53 | .memoryCacheSize(4 * 1024 * 1024) 54 | .discCache(new UnlimitedDiscCache(cacheDir)) // default 55 | .discCacheSize(50 * 1024 * 1024) 56 | .discCacheFileCount(100) 57 | .writeDebugLogs() 58 | .build(); 59 | return config; 60 | } 61 | 62 | /** 63 | * 默认配置 64 | * @return 65 | */ 66 | public static DisplayImageOptions getDefaultOptions(){ 67 | DisplayImageOptions options = new DisplayImageOptions.Builder() 68 | .cacheInMemory(true) 69 | .cacheOnDisc(true) 70 | .resetViewBeforeLoading(true) 71 | .build(); 72 | return options; 73 | } 74 | 75 | /** 76 | * 活动相关 77 | */ 78 | public static DisplayImageOptions getActionOptions() { 79 | DisplayImageOptions options = new DisplayImageOptions.Builder() 80 | .cacheInMemory(true) 81 | .cacheOnDisc(true) 82 | .resetViewBeforeLoading(true) 83 | // .showImageForEmptyUri(R.drawable.default_avatar) 84 | // .showImageOnFail(R.drawable.default_avatar) 85 | // .showStubImage(R.drawable.default_avatar) 86 | .imageScaleType(ImageScaleType.EXACTLY) 87 | .build(); 88 | return options; 89 | } 90 | 91 | public static DisplayImageOptions getMediaOptions() { 92 | DisplayImageOptions options = new DisplayImageOptions.Builder() 93 | .cacheInMemory(true) 94 | .cacheOnDisc(false) 95 | .bitmapConfig(Bitmap.Config.RGB_565) 96 | .build(); 97 | return options; 98 | } 99 | 100 | /** 101 | * 时间轴 单篇文章等使用多张图片的加载 102 | * @return 103 | */ 104 | public static DisplayImageOptions getPhotosItemOptions(){ 105 | DisplayImageOptions options = new DisplayImageOptions.Builder() 106 | .cacheInMemory(true) 107 | .cacheOnDisc(true) 108 | .build(); 109 | return options; 110 | } 111 | 112 | 113 | 114 | /** 115 | * 大学广场、单个大学中图片的加载; 116 | * add by wenqiang 09-04 117 | * @return 118 | */ 119 | public static DisplayImageOptions getUniversityItemOptions(){ 120 | DisplayImageOptions options = new DisplayImageOptions.Builder() 121 | .cacheInMemory(true) 122 | .cacheOnDisc(true) 123 | .bitmapConfig(Bitmap.Config.RGB_565) 124 | 125 | // .displayer(new FadeInBitmapDisplayer(100)) 126 | 127 | // .imageScaleType(ImageScaleType.IN_SAMPLE_INT) 128 | // .imageScaleType(ImageScaleType.EXACTLY) 129 | .build(); 130 | return options; 131 | } 132 | 133 | /** 134 | * 个人空间中个性封面图片的加载; 135 | * add by wenqiang 09-07 136 | * @return 137 | */ 138 | public static DisplayImageOptions getUserDomainCoverOptions(){ 139 | DisplayImageOptions options = new DisplayImageOptions.Builder() 140 | .cacheInMemory(true) 141 | .cacheOnDisc(true) 142 | .bitmapConfig(Bitmap.Config.RGB_565) 143 | // .imageScaleType(ImageScaleType.IN_SAMPLE_INT) 144 | // .imageScaleType(ImageScaleType.EXACTLY) 145 | .build(); 146 | return options; 147 | } 148 | 149 | /** 150 | * 默认配置 151 | * @return 152 | */ 153 | public static DisplayImageOptions getCircleAvatarOptions(){ 154 | DisplayImageOptions options = new DisplayImageOptions.Builder() 155 | // .showImageForEmptyUri(R.drawable.default_avatar) 156 | // .cacheInMemory(true) 157 | // .cacheOnDisc(false) 158 | // .bitmapConfig(Bitmap.Config.RGB_565) 159 | // .imageScaleType(ImageScaleType.IN_SAMPLE_INT) 160 | .build(); 161 | return options; 162 | } 163 | 164 | /** 165 | * 活动加载头像 166 | * @return 167 | */ 168 | public static DisplayImageOptions getAvactorOptions() { 169 | DisplayImageOptions options = new DisplayImageOptions.Builder() 170 | .cacheInMemory(true) 171 | .cacheOnDisc(true) 172 | .resetViewBeforeLoading(true) 173 | .showImageForEmptyUri(R.drawable.default_round_avatar2) 174 | .showImageOnFail(R.drawable.default_round_avatar2) 175 | // .showStubImage(R.drawable.default_avatar) 176 | // .imageScaleType(ImageScaleType.EXACTLY) 177 | .build(); 178 | return options; 179 | } 180 | 181 | } 182 | -------------------------------------------------------------------------------- /src/com/example/utils/CommUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.utils; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.security.MessageDigest; 9 | import java.security.NoSuchAlgorithmException; 10 | 11 | import android.content.Context; 12 | import android.graphics.Bitmap; 13 | import android.graphics.Bitmap.Config; 14 | import android.graphics.Canvas; 15 | import android.graphics.Paint; 16 | import android.graphics.PorterDuff.Mode; 17 | import android.graphics.PorterDuffXfermode; 18 | import android.graphics.RectF; 19 | import android.net.ConnectivityManager; 20 | import android.net.NetworkInfo; 21 | import android.text.TextUtils; 22 | import android.util.DisplayMetrics; 23 | 24 | public class CommUtils { 25 | public static final String APP_CLIENT_VERSION = "MIGAMEAPP_1.0.0"; 26 | /** 27 | * 调试日志的 28 | */ 29 | public static final boolean DEBUG = true; 30 | 31 | protected static final int BYTES_IN_MEGA = 1048576; 32 | protected static final int BYTES_IN_KILO = 1024; 33 | 34 | private final static String[] hexDigits = { "0", "1", "2", "3", "4", "5", 35 | "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; 36 | /** 37 | * URL 加密密码 38 | */ 39 | private static final byte[] URL_KEY = "_&L^W%&*20120724#$U%I)M%I^@" 40 | .getBytes(); 41 | private static final byte[] HASH_KEY = "_&W^A%&*20120814#$D%T)M%R^@" 42 | .getBytes(); 43 | 44 | /** 45 | * 客户端显示页面的大小 46 | */ 47 | public static final String PAGE_SIZE = "15"; 48 | public static final int PAGE_COUNT_REQUEST = 15; 49 | 50 | /** 51 | * 获得本地缓存的名字,对url进行hash得到 52 | */ 53 | public static final String getCacheFileName(String url) { 54 | return getMD5(url); 55 | } 56 | 57 | public static final String getMD5(String string) { 58 | if (TextUtils.isEmpty(string)) { 59 | return null; 60 | } 61 | MessageDigest digester = null; 62 | try { 63 | digester = MessageDigest.getInstance("MD5"); 64 | } catch (NoSuchAlgorithmException e) { 65 | if (CommUtils.DEBUG) 66 | e.printStackTrace(); 67 | return null; 68 | } 69 | digester.update(string.getBytes()); 70 | byte[] digest = digester.digest(); 71 | return byteArrayToString(digest); 72 | } 73 | 74 | public static final String getFileMD5(String filename) { 75 | InputStream fis; 76 | byte[] buffer = new byte[1024]; 77 | int numRead = 0; 78 | MessageDigest md5; 79 | try { 80 | fis = new FileInputStream(filename); 81 | } catch (FileNotFoundException e) { 82 | if (CommUtils.DEBUG) 83 | e.printStackTrace(); 84 | return null; 85 | } 86 | 87 | try { 88 | md5 = MessageDigest.getInstance("MD5"); 89 | while ((numRead = fis.read(buffer)) > 0) { 90 | md5.update(buffer, 0, numRead); 91 | } 92 | } catch (NoSuchAlgorithmException e) { 93 | if (CommUtils.DEBUG) 94 | e.printStackTrace(); 95 | return null; 96 | } catch (IOException e) { 97 | if (CommUtils.DEBUG) 98 | e.printStackTrace(); 99 | return null; 100 | } finally { 101 | try { 102 | fis.close(); 103 | } catch (IOException e) { 104 | if (CommUtils.DEBUG) 105 | e.printStackTrace(); 106 | } 107 | } 108 | 109 | return byteArrayToString(md5.digest()); 110 | } 111 | 112 | private static String byteArrayToString(byte[] b) { 113 | StringBuffer resultSb = new StringBuffer(); 114 | for (int i = 0; i < b.length; i++) { 115 | resultSb.append(byteToHexString(b[i])); 116 | } 117 | return resultSb.toString(); 118 | } 119 | 120 | private static String byteToHexString(byte b) { 121 | int n = b; 122 | if (n < 0) { 123 | n = 256 + n; 124 | } 125 | int d1 = n / 16; 126 | int d2 = n % 16; 127 | return hexDigits[d1] + hexDigits[d2]; 128 | } 129 | 130 | public static boolean isConnected(Context context) { 131 | if (context == null) 132 | return false; 133 | ConnectivityManager connManager = (ConnectivityManager) context 134 | .getSystemService(Context.CONNECTIVITY_SERVICE); 135 | NetworkInfo networkInfo = connManager.getActiveNetworkInfo(); 136 | return networkInfo != null && networkInfo.isConnectedOrConnecting(); 137 | } 138 | 139 | public static boolean isWifiConnected(Context context) { 140 | if (null == context) 141 | return false; 142 | ConnectivityManager connManager = (ConnectivityManager) context 143 | .getSystemService(Context.CONNECTIVITY_SERVICE); 144 | NetworkInfo networkInfo = connManager.getActiveNetworkInfo(); 145 | return (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI); 146 | } 147 | 148 | public static boolean isMobileConnected(Context context) { 149 | if (null == context) 150 | return false; 151 | ConnectivityManager connManager = (ConnectivityManager) context 152 | .getSystemService(Context.CONNECTIVITY_SERVICE); 153 | NetworkInfo networkInfo = connManager.getActiveNetworkInfo(); 154 | return (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_MOBILE); 155 | } 156 | 157 | public static boolean isLandscape(Context context) { 158 | if (context == null) 159 | throw new IllegalAccessError("Contex is Null"); 160 | DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 161 | float widthDp = metrics.widthPixels / metrics.density; 162 | if (widthDp > 480) { 163 | return true; 164 | } else { 165 | return false; 166 | } 167 | } 168 | 169 | public static Bitmap makeRoundImage(Bitmap bm, int rx, int ry) { 170 | if (bm == null) { 171 | return null; 172 | } 173 | 174 | int width = bm.getWidth(); 175 | int height = bm.getHeight(); 176 | Bitmap round = Bitmap.createBitmap(width, height, Config.ARGB_8888); 177 | Canvas canvas = new Canvas(round); 178 | 179 | final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 180 | int minRound = Math.min(width, height) / 3; 181 | rx = Math.min(rx, minRound); 182 | ry = Math.min(ry, minRound); 183 | 184 | canvas.drawARGB(0, 0, 0, 0); 185 | paint.setColor(0xff424242); 186 | canvas.drawRoundRect(new RectF(0, 0, width, height), rx, ry, paint); 187 | 188 | paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 189 | canvas.drawBitmap(bm, 0, 0, paint); 190 | bm.recycle(); 191 | 192 | return round; 193 | } 194 | 195 | /** 196 | * 数据加密 197 | * @param src 198 | */ 199 | public static byte[] encrypt(byte[] src, byte[] pass) { 200 | if (null == src) 201 | return null; 202 | if (null == pass) 203 | return src; 204 | final int srcLen = src.length; 205 | final int passLen = pass.length; 206 | byte[] res = new byte[srcLen]; 207 | for (int i = 0; i < srcLen; i += passLen) { 208 | for (int j = 0; j < passLen && (i + j < srcLen); j++) { 209 | res[i + j] = (byte) (src[i + j] ^ pass[j]); 210 | } 211 | } 212 | return res; 213 | } 214 | 215 | /** 216 | * 对URL进行加密 217 | * @param src 218 | * @return 219 | */ 220 | public static byte[] encryptUrl(byte[] src) { 221 | return encrypt(src, URL_KEY); 222 | } 223 | 224 | /** 225 | * 对HASH 进行加密 226 | * @return 227 | */ 228 | public static byte[] encryptApkHash(byte[] src) { 229 | return encrypt(src, HASH_KEY); 230 | } 231 | 232 | /** 233 | * 删除文件 234 | * @param dir 235 | * @param numDays 236 | * @return 237 | */ 238 | public static int clearCacheFolder(File dir, long numDays) { 239 | int deletedFiles = 0; 240 | if (dir != null && dir.isDirectory()) { 241 | try { 242 | for (File child : dir.listFiles()) { 243 | if (child.isDirectory()) { 244 | deletedFiles += clearCacheFolder(child, numDays); 245 | } 246 | if (numDays == 0 247 | || (numDays != 0 && child.lastModified() < numDays)) { 248 | if (child.delete()) { 249 | deletedFiles++; 250 | } 251 | } 252 | } 253 | } catch (Exception e) { 254 | e.printStackTrace(); 255 | } 256 | } 257 | return deletedFiles; 258 | } 259 | 260 | public static String getSuffix(String remote) { 261 | int start = remote.lastIndexOf("."); 262 | int end = remote.lastIndexOf("?"); 263 | end = (-1 == end || end <= start) ? remote.length() : end; 264 | String suffix = remote.substring(start, end); 265 | 266 | return suffix; 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /src/com/example/support/MediaFile.java: -------------------------------------------------------------------------------- 1 | package com.example.support; 2 | 3 | import java.util.HashMap; 4 | import java.util.Iterator; 5 | 6 | 7 | /** 8 | * 判断媒体文件的具体类型的工具类 9 | * MediaScanner helper class. 10 | * @author Jack 11 | */ 12 | public class MediaFile { 13 | // comma separated list of all file extensions supported by the media scanner 14 | public static String sFileExtensions; 15 | 16 | // Audio file types 17 | public static final int FILE_TYPE_MP3 = 1; 18 | public static final int FILE_TYPE_M4A = 2; 19 | public static final int FILE_TYPE_WAV = 3; 20 | public static final int FILE_TYPE_AMR = 4; 21 | public static final int FILE_TYPE_AWB = 5; 22 | public static final int FILE_TYPE_WMA = 6; 23 | public static final int FILE_TYPE_OGG = 7; 24 | private static final int FIRST_AUDIO_FILE_TYPE = FILE_TYPE_MP3; 25 | private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_OGG; 26 | 27 | // MIDI file types 28 | public static final int FILE_TYPE_MID = 11; 29 | public static final int FILE_TYPE_SMF = 12; 30 | public static final int FILE_TYPE_IMY = 13; 31 | private static final int FIRST_MIDI_FILE_TYPE = FILE_TYPE_MID; 32 | private static final int LAST_MIDI_FILE_TYPE = FILE_TYPE_IMY; 33 | 34 | // Video file types 35 | public static final int FILE_TYPE_MP4 = 21; 36 | public static final int FILE_TYPE_M4V = 22; 37 | public static final int FILE_TYPE_3GPP = 23; 38 | public static final int FILE_TYPE_3GPP2 = 24; 39 | public static final int FILE_TYPE_WMV = 25; 40 | private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4; 41 | private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_WMV; 42 | 43 | // Image file types 44 | public static final int FILE_TYPE_JPEG = 31; 45 | public static final int FILE_TYPE_GIF = 32; 46 | public static final int FILE_TYPE_PNG = 33; 47 | public static final int FILE_TYPE_BMP = 34; 48 | public static final int FILE_TYPE_WBMP = 35; 49 | public static final int FILE_TYPE_BIN = 36; 50 | private static final int FIRST_IMAGE_FILE_TYPE = FILE_TYPE_JPEG; 51 | private static final int LAST_IMAGE_FILE_TYPE = FILE_TYPE_BIN; 52 | 53 | // Playlist file types 54 | public static final int FILE_TYPE_M3U = 41; 55 | public static final int FILE_TYPE_PLS = 42; 56 | public static final int FILE_TYPE_WPL = 43; 57 | private static final int FIRST_PLAYLIST_FILE_TYPE = FILE_TYPE_M3U; 58 | private static final int LAST_PLAYLIST_FILE_TYPE = FILE_TYPE_WPL; 59 | 60 | public static class MediaFileType { 61 | public final int fileType; 62 | public final String mimeType; 63 | 64 | MediaFileType(int fileType, String mimeType) { 65 | this.fileType = fileType; 66 | this.mimeType = mimeType; 67 | } 68 | } 69 | 70 | private static HashMap sFileTypeMap 71 | = new HashMap(); 72 | private static HashMap sMimeTypeMap 73 | = new HashMap(); 74 | 75 | static void addFileType(String extension, int fileType, String mimeType) { 76 | sFileTypeMap.put(extension, new MediaFileType(fileType, mimeType)); 77 | sMimeTypeMap.put(mimeType, Integer.valueOf(fileType)); 78 | } 79 | 80 | static { 81 | addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg"); 82 | addFileType("M4A", FILE_TYPE_M4A, "audio/mp4"); 83 | addFileType("WAV", FILE_TYPE_WAV, "audio/x-wav"); 84 | addFileType("AMR", FILE_TYPE_AMR, "audio/amr"); 85 | addFileType("AWB", FILE_TYPE_AWB, "audio/amr-wb"); 86 | addFileType("WMA", FILE_TYPE_WMA, "audio/x-ms-wma"); 87 | addFileType("OGG", FILE_TYPE_OGG, "application/ogg"); 88 | 89 | addFileType("MID", FILE_TYPE_MID, "audio/midi"); 90 | addFileType("XMF", FILE_TYPE_MID, "audio/midi"); 91 | addFileType("RTTTL", FILE_TYPE_MID, "audio/midi"); 92 | addFileType("SMF", FILE_TYPE_SMF, "audio/sp-midi"); 93 | addFileType("IMY", FILE_TYPE_IMY, "audio/imelody"); 94 | 95 | addFileType("MP4", FILE_TYPE_MP4, "video/mp4"); 96 | addFileType("M4V", FILE_TYPE_M4V, "video/mp4"); 97 | addFileType("3GP", FILE_TYPE_3GPP, "video/3gpp"); 98 | addFileType("3GPP", FILE_TYPE_3GPP, "video/3gpp"); 99 | addFileType("3G2", FILE_TYPE_3GPP2, "video/3gpp2"); 100 | addFileType("3GPP2", FILE_TYPE_3GPP2, "video/3gpp2"); 101 | addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv"); 102 | 103 | addFileType("JPG", FILE_TYPE_JPEG, "image/jpeg"); 104 | addFileType("JPEG", FILE_TYPE_JPEG, "image/jpeg"); 105 | addFileType("GIF", FILE_TYPE_GIF, "image/gif"); 106 | addFileType("PNG", FILE_TYPE_PNG, "image/png"); 107 | addFileType("BMP", FILE_TYPE_BMP, "image/x-ms-bmp"); 108 | addFileType("WBMP", FILE_TYPE_WBMP, "image/vnd.wap.wbmp"); 109 | addFileType("BIN", FILE_TYPE_BIN, "image/bin"); 110 | 111 | addFileType("M3U", FILE_TYPE_M3U, "audio/x-mpegurl"); 112 | addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls"); 113 | addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl"); 114 | 115 | // compute file extensions list for native Media Scanner 116 | StringBuilder builder = new StringBuilder(); 117 | Iterator iterator = sFileTypeMap.keySet().iterator(); 118 | 119 | while (iterator.hasNext()) { 120 | if (builder.length() > 0) { 121 | builder.append(','); 122 | } 123 | builder.append(iterator.next()); 124 | } 125 | sFileExtensions = builder.toString(); 126 | } 127 | 128 | public static final String UNKNOWN_STRING = ""; 129 | 130 | public static boolean isAudioFileType(int fileType) { 131 | return ((fileType >= FIRST_AUDIO_FILE_TYPE && 132 | fileType <= LAST_AUDIO_FILE_TYPE) || 133 | (fileType >= FIRST_MIDI_FILE_TYPE && 134 | fileType <= LAST_MIDI_FILE_TYPE)); 135 | } 136 | 137 | public static boolean isVideoFileType(int fileType) { 138 | return (fileType >= FIRST_VIDEO_FILE_TYPE && 139 | fileType <= LAST_VIDEO_FILE_TYPE); 140 | } 141 | 142 | public static boolean isImageFileType(int fileType) { 143 | return (fileType >= FIRST_IMAGE_FILE_TYPE && 144 | fileType <= LAST_IMAGE_FILE_TYPE); 145 | } 146 | 147 | public static boolean isGifFileType(int fileType){ 148 | return fileType == FILE_TYPE_GIF; 149 | } 150 | 151 | public static boolean isPlayListFileType(int fileType) { 152 | return (fileType >= FIRST_PLAYLIST_FILE_TYPE && 153 | fileType <= LAST_PLAYLIST_FILE_TYPE); 154 | } 155 | 156 | public static MediaFileType getFileType(String path) { 157 | int lastDot = path.lastIndexOf("."); 158 | if (lastDot < 0) 159 | return null; 160 | return sFileTypeMap.get(path.substring(lastDot + 1).toUpperCase()); 161 | } 162 | 163 | /** 164 | * 根据音频文件路径判断文件类型 165 | * @param path 166 | * @return 167 | */ 168 | public static boolean isAudioFileType(String path) { //自己增加 169 | MediaFileType type = getFileType(path); 170 | if(null != type) { 171 | return isAudioFileType(type.fileType); 172 | } 173 | return false; 174 | } 175 | 176 | /** 177 | * 根据图片文件路径判断文件类型 178 | * @param path 179 | * @return 180 | */ 181 | public static boolean isImageFileType(String path) { //自己增加 182 | MediaFileType type = getFileType(path); 183 | if(null != type) { 184 | return isImageFileType(type.fileType); 185 | } 186 | return false; 187 | } 188 | 189 | public static boolean isGifFileType(String path){ 190 | MediaFileType type = getFileType(path); 191 | if(null != type){ 192 | return isGifFileType(type.fileType); 193 | } 194 | return false; 195 | } 196 | 197 | /** 198 | * 根据mime类型查看文件类型 199 | * @param mimeType 200 | * @return 201 | */ 202 | public static int getFileTypeForMimeType(String mimeType) { 203 | Integer value = sMimeTypeMap.get(mimeType); 204 | return (value == null ? 0 : value.intValue()); 205 | } 206 | 207 | } 208 | -------------------------------------------------------------------------------- /src/com/example/support/SystemSupport.java: -------------------------------------------------------------------------------- 1 | package com.example.support; 2 | 3 | import java.io.File; 4 | import android.app.Activity; 5 | import android.content.ContentResolver; 6 | import android.content.ContentValues; 7 | import android.content.Context; 8 | import android.content.Intent; 9 | import android.database.Cursor; 10 | import android.net.ConnectivityManager; 11 | import android.net.NetworkInfo; 12 | import android.net.Uri; 13 | import android.os.Environment; 14 | import android.os.StatFs; 15 | import android.provider.MediaStore; 16 | import android.provider.MediaStore.Images; 17 | import android.view.View; 18 | import android.view.inputmethod.InputMethodManager; 19 | 20 | /** 21 | * 一些通用的函数,对Android系统的一些操作。 22 | * @author Jack 23 | */ 24 | public class SystemSupport { 25 | public static final String MIME_TYPE_EMAIL = "message/rfc822"; 26 | public static final String MIME_TYPE_TEXT = "text/*"; 27 | 28 | /** 29 | * @param message 30 | */ 31 | public static Intent getStartMessageIntent(String message) { 32 | return getStartMessageWithNumberIntent(message, null); 33 | } 34 | 35 | /** 36 | * @param message 37 | * @param number 38 | */ 39 | public static Intent getStartMessageWithNumberIntent(String message, 40 | String number) { 41 | Uri uri = null; 42 | if (number != null) { 43 | uri = Uri.parse("smsto:" + number); 44 | } else { 45 | uri = Uri.parse("smsto:"); 46 | } 47 | Intent intent = new Intent(Intent.ACTION_SENDTO, uri); 48 | intent.putExtra("sms_body", message); 49 | return intent; 50 | } 51 | 52 | /** 53 | * @param email 54 | * @param subject 55 | * @param message 56 | */ 57 | public static Intent getStartEmailIntent(String[] email, String subject, 58 | String body) { 59 | Intent data = new Intent(Intent.ACTION_SENDTO); 60 | data.setData(Uri.parse("mailto: ")); 61 | data.putExtra(Intent.EXTRA_SUBJECT, subject); 62 | data.putExtra(Intent.EXTRA_TEXT, body); 63 | return data; 64 | } 65 | 66 | /** 67 | * @param context 68 | * @param req_code 69 | */ 70 | public static Intent getStartGalleryIntent() { 71 | Intent intent = new Intent(Intent.ACTION_PICK, null); 72 | intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*"); 73 | return intent; 74 | } 75 | 76 | /** 77 | * @param save_path 78 | * @param file_name 79 | */ 80 | public static Intent getStartCameraIntent(File save_file) { 81 | Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 82 | intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(save_file)); 83 | return intent; 84 | } 85 | 86 | /** 87 | * @param srcLat 88 | * @param srcLng 89 | * @param tarLat 90 | * @param tarLng 91 | */ 92 | public static Intent getStartTraficLineIntent(String srcLat, String srcLng, 93 | String tarLat, String tarLng) { 94 | String url = String 95 | .format("http://ditu.google.cn/maps?f=d&source=s_d&saddr=%s,%s&daddr=%s,%s", 96 | srcLat, srcLng, tarLat, tarLng); 97 | Uri uri = Uri.parse(url); 98 | Intent intent = new Intent(Intent.ACTION_VIEW, uri); 99 | return intent; 100 | } 101 | 102 | /** 103 | * @return 104 | */ 105 | public static Intent getStartSecuritySettingsIntent() { 106 | Intent intent = new Intent("android.settings.LOCATION_SOURCE_SETTINGS"); 107 | return intent; 108 | } 109 | 110 | public static Intent getInstallApkIntent(String apk) { 111 | Intent intent = new Intent(Intent.ACTION_VIEW); 112 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 113 | intent.setDataAndType(Uri.parse("file://" + apk), 114 | "application/vnd.android.package-archive"); 115 | return intent; 116 | } 117 | 118 | /** 119 | * @param context 120 | * @param contentUri 121 | * @return 122 | */ 123 | public static String getRealPathFromURI(Context context, Uri contentUri) { 124 | String[] proj = { MediaStore.Images.Media.DATA }; 125 | ContentResolver cr = context.getContentResolver(); 126 | Cursor cursor = cr.query(contentUri, proj, null, null, null); 127 | String file_name = null; 128 | if (null != cursor && cursor.moveToFirst()) { 129 | try { 130 | int column_index = cursor 131 | .getColumnIndexOrThrow(MediaStore.Images.Media.DATA); 132 | file_name = cursor.getString(column_index); 133 | } catch (Exception e) { 134 | e.printStackTrace(); 135 | } 136 | } else { 137 | file_name = contentUri.getPath(); 138 | } 139 | if (cursor != null) 140 | cursor.close(); 141 | 142 | return file_name; 143 | } 144 | 145 | public static boolean saveImage2Gallery(Context context, File file) { 146 | final Uri STORAGE_URI = Images.Media.EXTERNAL_CONTENT_URI; 147 | String IMAGE_MIME_TYPE = "image/png"; 148 | ContentValues values = new ContentValues(7); 149 | values.put(Images.Media.TITLE, file.getName()); 150 | values.put(Images.Media.DISPLAY_NAME, file.getName()); 151 | values.put(Images.Media.DATE_TAKEN, System.currentTimeMillis()); 152 | values.put(Images.Media.MIME_TYPE, IMAGE_MIME_TYPE); 153 | values.put(Images.Media.ORIENTATION, 0); 154 | values.put(Images.Media.DATA, file.getAbsolutePath()); 155 | values.put(Images.Media.SIZE, 0); 156 | Uri uri = context.getContentResolver().insert(STORAGE_URI, values); 157 | return null != uri; 158 | } 159 | 160 | /** 161 | * 162 | * // 1.调用显示系统默认的输入法 // 方法一、 InputMethodManager imm = (InputMethodManager) 163 | * getSystemService(Context.INPUT_METHOD_SERVICE); 164 | * imm.showSoftInput(m_receiverView 165 | * (接受软键盘输入的视图(View)),InputMethodManager.SHOW_FORCED 166 | * (提供当前操作的标记,SHOW_FORCED表示强制显示)); // 方法二、 InputMethodManager 167 | * m=(InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); 168 | * m.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); 169 | * (这个方法可以实现输入法在窗口上切换显示,如果输入法在窗口上已经显示,则隐藏,如果隐藏,则显示输入法到窗口上) 170 | * 171 | * // 2.调用隐藏系统默认的输入法 172 | * ((InputMethodManager)getSystemService(INPUT_METHOD_SERVICE 173 | * )).hideSoftInputFromWindow 174 | * (WidgetSearchActivity.this.getCurrentFocus().getWindowToken(), 175 | * InputMethodManager.HIDE_NOT_ALWAYS); (WidgetSearchActivity是当前的Activity) 176 | * 177 | * // 3.获取输入法打开的状态 InputMethodManager imm = 178 | * (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); 179 | * boolean isOpen=imm.isActive(); // isOpen若返回true,则表示输入法打开 180 | * @param context 181 | */ 182 | public static boolean toggleSoftKeyboard(Context context) { 183 | InputMethodManager imm = (InputMethodManager) context 184 | .getSystemService(Activity.INPUT_METHOD_SERVICE); 185 | return imm.isActive(); 186 | } 187 | 188 | public static void hideSoftKeyboard(Context context, View v) { 189 | InputMethodManager imm = (InputMethodManager) context 190 | .getSystemService(Activity.INPUT_METHOD_SERVICE); 191 | if (v != null) { 192 | 193 | imm.hideSoftInputFromWindow(v.getApplicationWindowToken(), 194 | InputMethodManager.HIDE_NOT_ALWAYS); 195 | } 196 | } 197 | 198 | public static void showSoftKeyboard(Context context, View v) { 199 | InputMethodManager imm = (InputMethodManager) context 200 | .getSystemService(Activity.INPUT_METHOD_SERVICE); 201 | imm.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT); 202 | imm.showSoftInputFromInputMethod(v.getApplicationWindowToken(), 203 | InputMethodManager.SHOW_IMPLICIT); 204 | } 205 | 206 | public static long readSDCard() { 207 | String state = Environment.getExternalStorageState(); 208 | if (Environment.MEDIA_MOUNTED.equals(state)) { 209 | File sdcardDir = Environment.getExternalStorageDirectory(); 210 | StatFs sf = new StatFs(sdcardDir.getPath()); 211 | long blockSize = sf.getBlockSize(); 212 | long availCount = sf.getAvailableBlocks(); 213 | return availCount * blockSize / 1024; 214 | } else { 215 | return 0; 216 | } 217 | } 218 | 219 | /** 220 | * 判断是什么网络 221 | * @param ctx 222 | * @return 1移动网络 2wifi 3无网络 223 | */ 224 | public static DoveBoxNetState getNetState(Context ctx) { 225 | if (ctx == null) 226 | throw new IllegalAccessError("Context is Null!!!"); 227 | ConnectivityManager connManager = (ConnectivityManager) ctx 228 | .getSystemService(Context.CONNECTIVITY_SERVICE); 229 | if (connManager != null) { 230 | NetworkInfo info = connManager.getActiveNetworkInfo(); 231 | if (info == null) 232 | return DoveBoxNetState.UNKOWN; 233 | else if (info.getType() == ConnectivityManager.TYPE_MOBILE) 234 | return DoveBoxNetState.MOBILE; 235 | } 236 | return DoveBoxNetState.WIFI; 237 | } 238 | 239 | /** 240 | * 得到网络类型 241 | * 1联通2g 2移动2g 4电信2g 242 | * 5 6 12电信3G 3 8联通3G 243 | * 244 | * @param ctx 245 | * @return 246 | */ 247 | public static int getNetMobileType(Context ctx) { 248 | if (ctx != null) { 249 | ConnectivityManager connManager = (ConnectivityManager) ctx 250 | .getSystemService(Context.CONNECTIVITY_SERVICE); 251 | if (connManager != null) { 252 | NetworkInfo info = connManager.getActiveNetworkInfo(); 253 | if (info != null 254 | && info.getType() == ConnectivityManager.TYPE_MOBILE) { 255 | return info.getSubtype(); 256 | } 257 | } 258 | } 259 | return -1; 260 | } 261 | 262 | public enum DoveBoxNetState { 263 | /** 264 | * 无网络 265 | */ 266 | UNKOWN, 267 | /** 268 | * wifi 269 | */ 270 | WIFI, 271 | /** 272 | * 移动网络 273 | */ 274 | MOBILE; 275 | } 276 | } 277 | -------------------------------------------------------------------------------- /src/com/example/utils/BitmapUtils.java: -------------------------------------------------------------------------------- 1 | package com.example.utils; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | 9 | import android.content.Context; 10 | import android.graphics.Bitmap; 11 | import android.graphics.Bitmap.CompressFormat; 12 | import android.graphics.Bitmap.Config; 13 | import android.graphics.BitmapFactory; 14 | import android.graphics.BitmapFactory.Options; 15 | import android.graphics.Canvas; 16 | import android.graphics.Color; 17 | import android.graphics.ColorMatrix; 18 | import android.graphics.ColorMatrixColorFilter; 19 | import android.graphics.Matrix; 20 | import android.graphics.Paint; 21 | import android.graphics.PorterDuff; 22 | import android.graphics.PorterDuff.Mode; 23 | import android.graphics.PorterDuffXfermode; 24 | import android.graphics.Rect; 25 | import android.graphics.RectF; 26 | import android.util.DisplayMetrics; 27 | import android.util.Log; 28 | 29 | /** 30 | * Bitmap处理辅助类 31 | * 32 | * @author Jack 33 | */ 34 | public class BitmapUtils { 35 | private static Canvas m_canvas = null; 36 | private static Paint s_paint_eraser = null; 37 | private static Paint s_paint_outline = null; 38 | static { 39 | m_canvas = new Canvas(); 40 | s_paint_eraser = new Paint(); 41 | s_paint_eraser.setAntiAlias(true); 42 | s_paint_eraser.setDither(true); 43 | s_paint_eraser.setColor(0xFFFFFFFF); 44 | s_paint_eraser.setStrokeWidth(20); 45 | s_paint_eraser.setStyle(Paint.Style.STROKE); 46 | s_paint_eraser.setStrokeJoin(Paint.Join.ROUND); 47 | s_paint_eraser.setStrokeCap(Paint.Cap.ROUND); 48 | s_paint_eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR)); 49 | s_paint_outline = new Paint(); 50 | s_paint_outline.setColor(Color.WHITE); 51 | s_paint_outline.setStrokeWidth(20); 52 | } 53 | private static Paint s_paint_gray = null; 54 | static { 55 | s_paint_gray = new Paint(); 56 | ColorMatrix matrix = new ColorMatrix(); 57 | matrix.setSaturation(0.0f); // 饱和度 58 | ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix); 59 | s_paint_gray.setColorFilter(filter); 60 | } 61 | 62 | public static Bitmap toGray(Bitmap image) { 63 | Bitmap grayscalBitmap = Bitmap.createBitmap(image.getWidth(), 64 | image.getHeight(), Config.ARGB_4444); 65 | m_canvas.setBitmap(grayscalBitmap); 66 | m_canvas.drawBitmap(image, 0, 0, s_paint_gray); 67 | return grayscalBitmap; 68 | } 69 | 70 | /** 71 | * Returns a new bitmap to be used as the object outline, e.g. to visualize 72 | * the drop location. Responsibility for the bitmap is transferred to the 73 | * caller. 74 | */ 75 | public static Bitmap toOutline(Bitmap image) { 76 | Bitmap bitmap1 = Bitmap.createBitmap(image.getWidth(), 77 | image.getHeight(), Bitmap.Config.ARGB_4444); 78 | m_canvas.setBitmap(bitmap1); 79 | // m_canvas.save(); 80 | m_canvas.drawBitmap(image, 0, 0, null); 81 | m_canvas.drawBitmap(image, 0, 0, s_paint_eraser); 82 | Bitmap bitmap2 = bitmap1.extractAlpha(); 83 | Bitmap bitmap3 = Bitmap.createBitmap(image.getWidth(), 84 | image.getHeight(), Bitmap.Config.ARGB_4444); 85 | m_canvas.setBitmap(bitmap3); 86 | m_canvas.drawBitmap(bitmap2, 0, 0, s_paint_outline); 87 | // m_canvas.restore(); 88 | bitmap1.recycle(); 89 | bitmap1 = null; 90 | bitmap2.recycle(); 91 | bitmap2 = null; 92 | return bitmap3; 93 | } 94 | 95 | public static Bitmap scale(String file, int size, int density) { 96 | Options opts = new Options(); 97 | opts.inJustDecodeBounds = true; 98 | BitmapFactory.decodeFile(file, opts); 99 | Log.d("l99", String.format( 100 | "opts.outWidth=%d, opts.outHeight=%d, opts.outMimeType=%s", 101 | opts.outWidth, opts.outHeight, opts.outMimeType)); 102 | if (opts.outWidth <= size && opts.outHeight <= size) { 103 | opts.inJustDecodeBounds = false; 104 | return decodeBitmapFromDescriptor(file, opts); 105 | } else { 106 | opts.inScaled = true; 107 | opts.inTargetDensity = density; 108 | opts.inSampleSize = opts.outWidth / size; 109 | opts.inJustDecodeBounds = false; 110 | return decodeBitmapFromDescriptor(file, opts); 111 | } 112 | } 113 | 114 | /** 115 | * 保存图片到指定的路径 116 | * @param bitmap 要保存的bitmap 117 | * @param path 保存到的路径 118 | * @throws IOException IO异常 119 | */ 120 | public static void saveBitmap(Bitmap bitmap, String path) 121 | throws IOException { 122 | File file = new File(path); 123 | if (!file.getParentFile().exists()) 124 | file.getParentFile().mkdirs(); 125 | if (!file.exists()) { 126 | file.createNewFile(); 127 | } 128 | FileOutputStream stream = new FileOutputStream(file); 129 | bitmap.compress(CompressFormat.JPEG, 80, stream); 130 | } 131 | 132 | /** 133 | * 利用Matrix旋转图片 134 | * @param bm 需要旋转的图片 135 | * @param degree 旋转角度 136 | * @return 旋转后的图片 137 | */ 138 | public static Bitmap rotate(Bitmap bm, int degree) { 139 | Matrix matrix = new Matrix(); 140 | matrix.postRotate(degree); 141 | Bitmap bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), 142 | bm.getHeight(), matrix, true); 143 | bm.recycle(); 144 | return bitmap; 145 | } 146 | 147 | /** 148 | * 根据已有bitmap重新绘制圆角bitmap 149 | * @param bitmap 已有bitmap 150 | * @param roundPixels 圆角半径 151 | * @return 152 | */ 153 | public static Bitmap getRoundCornerImage(Bitmap bitmap, int roundPixels) { 154 | Bitmap roundConcerImage = Bitmap.createBitmap(bitmap.getWidth(), 155 | bitmap.getHeight(), Config.ARGB_8888); 156 | Canvas canvas = new Canvas(roundConcerImage); 157 | Paint paint = new Paint(); 158 | Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); 159 | RectF rectF = new RectF(rect); 160 | paint.setAntiAlias(true); 161 | canvas.drawRoundRect(rectF, roundPixels, roundPixels, paint); 162 | paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 163 | canvas.drawBitmap(bitmap, null, rect, paint); 164 | return roundConcerImage; 165 | } 166 | 167 | public static Bitmap decodeBitmapFromDescriptor(Context context, String filePath) { 168 | BitmapFactory.Options bfOptions = new BitmapFactory.Options(); 169 | DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 170 | bfOptions.inTargetDensity = metrics.densityDpi; 171 | bfOptions.inScaled = true; 172 | bfOptions.inDither = false; // Disable Dithering mode 173 | bfOptions.inPurgeable = true; // Tell to gc that whether it needs free memory, the Bitmap can be cleared 174 | bfOptions.inInputShareable = true; // Which kind of reference will be used to recover the Bitmap data 175 | // after being clear, when it will be used in the future 176 | bfOptions.inTempStorage = new byte[12 * 1024]; 177 | 178 | File file = new File(filePath); 179 | FileInputStream fs = null; 180 | try { 181 | fs = new FileInputStream(file); 182 | } catch (FileNotFoundException e) { 183 | e.printStackTrace(); 184 | } 185 | 186 | if (fs != null) { 187 | try { 188 | return BitmapFactory.decodeFileDescriptor(fs.getFD(), null, 189 | bfOptions); 190 | } catch (IOException e) { 191 | e.printStackTrace(); 192 | } finally { 193 | if (fs != null) { 194 | try { 195 | fs.close(); 196 | } catch (IOException e) { 197 | e.printStackTrace(); 198 | } 199 | } 200 | } 201 | } 202 | return null; 203 | } 204 | 205 | public static Bitmap decodeBitmapFromDescriptor(String filePath, BitmapFactory.Options bfOptions) { 206 | bfOptions.inScaled = true; 207 | bfOptions.inDither = false; // Disable Dithering mode 208 | bfOptions.inPurgeable = true; // Tell to gc that whether it needs free 209 | // memory, the Bitmap can be cleared 210 | bfOptions.inInputShareable = true; // Which kind of reference will be 211 | // used to recover the Bitmap data 212 | // after being clear, when it will 213 | // be used in the future 214 | bfOptions.inTempStorage = new byte[12 * 1024]; 215 | 216 | File file = new File(filePath); 217 | FileInputStream fs = null; 218 | try { 219 | fs = new FileInputStream(file); 220 | } catch (FileNotFoundException e) { 221 | e.printStackTrace(); 222 | } 223 | 224 | if (fs != null) { 225 | try { 226 | return BitmapFactory.decodeFileDescriptor(fs.getFD(), null, 227 | bfOptions); 228 | } catch (IOException e) { 229 | e.printStackTrace(); 230 | } finally { 231 | if (fs != null) { 232 | try { 233 | fs.close(); 234 | } catch (IOException e) { 235 | e.printStackTrace(); 236 | } 237 | } 238 | } 239 | } 240 | return null; 241 | } 242 | 243 | /** 244 | * 转换图片成圆形 245 | * @param bitmap 传入需要转换的Bitmap对象 246 | * @return 转换后圆形的图片 247 | */ 248 | public static Bitmap toRoundBitmap(Bitmap bitmap) { 249 | 250 | int width = bitmap.getWidth(); 251 | int height = bitmap.getHeight(); 252 | float roundPx; 253 | float left, top, right, bottom, dst_left, dst_top, dst_right, dst_bottom; 254 | 255 | if (width <= height) { 256 | roundPx = width / 2; 257 | top = 0; 258 | bottom = width; 259 | left = 0; 260 | right = width; 261 | height = width; 262 | dst_left = 0; 263 | dst_top = 0; 264 | dst_right = width; 265 | dst_bottom = width; 266 | } else { 267 | roundPx = height / 2; 268 | float clip = (width - height) / 2; 269 | left = clip; 270 | right = width - clip; 271 | top = 0; 272 | bottom = height; 273 | width = height; 274 | dst_left = 0; 275 | dst_top = 0; 276 | dst_right = height; 277 | dst_bottom = height; 278 | } 279 | 280 | Bitmap output = Bitmap.createBitmap(width, height, Config.ARGB_8888); 281 | Canvas canvas = new Canvas(output); 282 | final int color = 0xff424242; 283 | final Paint paint = new Paint(); 284 | final Rect src = new Rect((int) left, (int) top, (int) right, 285 | (int) bottom); 286 | final Rect dst = new Rect((int) dst_left, (int) dst_top, 287 | (int) dst_right, (int) dst_bottom); 288 | final RectF rectF = new RectF(dst); 289 | paint.setAntiAlias(true); 290 | canvas.drawARGB(0, 0, 0, 0); 291 | paint.setColor(color); 292 | canvas.drawRoundRect(rectF, roundPx, roundPx, paint); 293 | paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 294 | canvas.drawBitmap(bitmap, src, dst, paint); 295 | return output; 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /src/com/example/cache/ImageLoader.java: -------------------------------------------------------------------------------- 1 | package com.example.cache; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.IOException; 5 | import java.net.HttpURLConnection; 6 | import java.net.URL; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | import java.util.concurrent.Executors; 11 | import java.util.concurrent.ThreadPoolExecutor; 12 | import android.content.Context; 13 | import android.graphics.Bitmap; 14 | import android.graphics.BitmapFactory; 15 | import android.os.Bundle; 16 | import android.os.Message; 17 | import android.os.SystemClock; 18 | import android.util.DisplayMetrics; 19 | import android.util.Log; 20 | import com.example.support.ConfigWrapper; 21 | import com.example.support.ConnectivitySupport; 22 | import com.example.support.ConnectivitySupport.IConnectivityListener; 23 | import com.example.support.ConnectivitySupport.NetState; 24 | 25 | 26 | /** 27 | * 图片加载类,它封装了一个ThreadPoolExecutor,线程池FixedThreadPool。 它为每一个网络图片启动一个线程,去下载。 28 | * 但当同一张网络图片,被同时load多次时,将对应的handler放入mHandlersCache中,而不是启动多个线程。 29 | * @author Jack 30 | */ 31 | public class ImageLoader implements Runnable{ 32 | 33 | /** 34 | * The limit ImageLoader code 35 | */ 36 | private static final String KEY_LIMIT = "key_limit_webimageview"; 37 | 38 | public static int S_LIMIT; // 300K 39 | 40 | // private boolean isNull=false; 41 | 42 | private static ConnectivitySupport s_ConnectivitySupport; 43 | 44 | private static IConnectivityListener s_ConnectivityListener; 45 | 46 | public static void startConnectivityMonitor(Context context) { 47 | setLimit(ConfigWrapper.get(KEY_LIMIT, 300)); 48 | s_ConnectivitySupport = ConnectivitySupport.getInstance(); 49 | s_ConnectivityListener = new IConnectivityListener() { 50 | 51 | @Override 52 | public void onConnectivityChanged(NetState oldstate, 53 | NetState newstate) { 54 | Log.d("l99", String.format( 55 | "onConnectivityChanged(oldstate=%s, newstate=%s)", 56 | oldstate, newstate)); 57 | } 58 | }; 59 | s_ConnectivitySupport.registerConnectivityListener(context, 60 | s_ConnectivityListener); 61 | } 62 | 63 | public static void stopConnectivityMonitor() { 64 | s_ConnectivitySupport 65 | .unregisterConnectivityListener(s_ConnectivityListener); 66 | } 67 | 68 | public static void setLimit(int limit) { 69 | S_LIMIT = limit * 1024; 70 | 71 | ConfigWrapper.put(KEY_LIMIT, limit); 72 | ConfigWrapper.commit(); 73 | } 74 | 75 | /** 76 | * The original ImageLoader code 77 | */ 78 | public static final int HANDLER_MESSAGE_ID1 = 1; 79 | public static final int HANDLER_MESSAGE_ID = 0; 80 | public static final String IMAGE_URL_EXTRA = "imageloader:extra_image_url"; 81 | public static final String IMAGE_LIMIT_EXTRA = "imageloader:extra_image_limit"; 82 | 83 | private static final int DEFAULT_RETRY_HANDLER_SLEEP_TIME = 1000; 84 | private static final int DEFAULT_NUM_RETRIES = 2; 85 | 86 | // the default thread pool size 87 | private static final int DEFAULT_POOL_SIZE = 6; 88 | 89 | private static ThreadPoolExecutor executor; 90 | private static MemImageCache mMemCache; 91 | private static DiskImageCache mDiskCache; 92 | private static int numRetries = DEFAULT_NUM_RETRIES; 93 | 94 | private static Context mContext; 95 | 96 | // private static ImageLoaderHandler mHandler; 97 | 98 | // private static DownloadListener myListener=null; 99 | 100 | /** 101 | * @param numThreads 102 | * the maximum number of threads that will be started to download 103 | * images in parallel 104 | */ 105 | public static void setThreadPoolSize(int numThreads) { 106 | executor.setMaximumPoolSize(numThreads); 107 | } 108 | 109 | /** 110 | * @param numAttempts 111 | * how often the image loader should retry the image download if 112 | * network connection fails 113 | */ 114 | public static void setMaxDownloadAttempts(int numAttempts) { 115 | ImageLoader.numRetries = numAttempts; 116 | } 117 | 118 | public static synchronized void initialize(Context context) { 119 | mContext = context.getApplicationContext(); 120 | if (executor == null) { 121 | executor = (ThreadPoolExecutor) Executors 122 | .newFixedThreadPool(DEFAULT_POOL_SIZE); 123 | } 124 | if (mMemCache == null) { 125 | mMemCache = new MemImageCache(10); 126 | } 127 | if (mDiskCache == null) { 128 | mDiskCache = new DiskImageCache(context); 129 | } 130 | } 131 | 132 | public static synchronized void clearMemCache() { 133 | if (mMemCache == null) { 134 | mMemCache.clearImage(); 135 | } 136 | } 137 | 138 | private static ConcurrentHashMap> mHandlersCache = new ConcurrentHashMap>(); 139 | private final String mImageUrl; 140 | private final boolean mImageLimit; 141 | private ImageLoaderHandler mHandler; 142 | 143 | private ImageLoader(ImageLoaderHandler handler, String url, boolean limit) { 144 | mHandler=handler; 145 | mImageUrl = url; 146 | mImageLimit = limit; 147 | } 148 | 149 | public static void start(String imageUrl, ImageLoaderHandler handler) { 150 | start(imageUrl, handler, false); 151 | } 152 | 153 | public static void start(String imageUrl, ImageLoaderHandler handler, 154 | boolean limit) { 155 | // Log.d("l99", String.format("start(%s)", imageUrl)); 156 | Bitmap bitmap = mMemCache.getBitmap(imageUrl); 157 | if (null == bitmap) { 158 | List handlers = mHandlersCache.get(imageUrl); 159 | if (null == handlers) { 160 | handlers = new ArrayList(3); 161 | // Log.d("l99", 162 | // String.format("new ArrayList(6):%s", 163 | // imageUrl)); 164 | handlers.add(handler); 165 | mHandlersCache.put(imageUrl, handlers); 166 | executor.execute(new ImageLoader(handler, imageUrl, limit)); 167 | } else { 168 | handlers.add(handler); 169 | // Log.d("l99", String.format("handlers.add(handler):%s", 170 | // imageUrl)); 171 | } 172 | } else { 173 | // do not go through message passing, handle directly instead 174 | handler.handleImageLoaded(imageUrl, bitmap); 175 | } 176 | } 177 | 178 | @Override 179 | public void run() { 180 | DownLoadResult result = null; 181 | Bitmap bitmap = mDiskCache.getBitmap(mImageUrl); 182 | if (null != bitmap) { 183 | result = new DownLoadResult(bitmap, false); 184 | mMemCache.putBitmap(mImageUrl, bitmap); 185 | } else { 186 | result = downloadImage(mHandler); 187 | } 188 | notifyImageLoaded(mImageUrl, result.bitmap, result.limit); 189 | } 190 | 191 | class DownLoadResult { 192 | public final Bitmap bitmap; 193 | public final boolean limit; 194 | 195 | public DownLoadResult(Bitmap bitmap, boolean limit) { 196 | this.bitmap = bitmap; 197 | this.limit = limit; 198 | } 199 | } 200 | 201 | // TODO: we could probably improve performance by re-using connections 202 | // instead of closing them 203 | // after each and every download 204 | protected DownLoadResult downloadImage(ImageLoaderHandler handler) { 205 | boolean save_image = true; 206 | int timesTried = 1; 207 | Bitmap bitmap = null; 208 | boolean limit = false; 209 | while (timesTried <= numRetries) { 210 | try { 211 | URL url = new URL(mImageUrl); 212 | HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 213 | 214 | int fileSize = getContentLength(connection); 215 | if (fileSize < 0) { 216 | Log.e("l99", String.format("downloadImage(fileSize=%d): %s", fileSize,mImageUrl)); 217 | } else { 218 | if (mImageLimit&& NetState.NET_CONNECT_MOBILE == s_ConnectivitySupport.getNetState() && fileSize > S_LIMIT) { 219 | limit = true; 220 | connection.disconnect(); 221 | break; 222 | } else { 223 | byte[] imageData = retrieveImageData(handler,connection,fileSize); 224 | connection.disconnect(); 225 | if (imageData != null) { 226 | BitmapFactory.Options opts = new BitmapFactory.Options(); 227 | DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); 228 | opts.inTargetDensity = metrics.densityDpi; 229 | opts.inScaled = true; 230 | opts.inDither = false; // Disable Dithering mode 231 | opts.inPurgeable = true; // Tell to gc that whether 232 | // it needs free memory, 233 | // the Bitmap can be 234 | // cleared 235 | opts.inInputShareable = true; 236 | 237 | bitmap = BitmapFactory.decodeByteArray(imageData,0, imageData.length, opts); 238 | mMemCache.putBitmap(mImageUrl, bitmap); 239 | save_image = mDiskCache.putBitmap(mImageUrl,imageData); 240 | 241 | break; 242 | } 243 | } 244 | } 245 | } catch (Throwable e) { 246 | Log.w("l99", e); 247 | } finally { 248 | SystemClock.sleep(DEFAULT_RETRY_HANDLER_SLEEP_TIME); 249 | timesTried++; 250 | } 251 | } 252 | 253 | if (!save_image) { 254 | mDiskCache.removeImage(mImageUrl); 255 | } 256 | return new DownLoadResult(bitmap, limit); 257 | } 258 | 259 | public static boolean isCached(String imageUrl) { 260 | return mDiskCache.hasImage(imageUrl); 261 | } 262 | 263 | protected int getContentLength(HttpURLConnection connection) { 264 | // determine the image size and allocate a buffer 265 | int fileSize = connection.getContentLength(); 266 | return fileSize; 267 | } 268 | 269 | protected byte[] retrieveImageData(ImageLoaderHandler handler,HttpURLConnection connection,int fileSize) throws IOException { 270 | byte[] imageData = new byte[fileSize]; 271 | 272 | handler.sendMessage(handler.obtainMessage(ImageLoader.HANDLER_MESSAGE_ID1, 0, fileSize)); 273 | // download the file 274 | BufferedInputStream istream = new BufferedInputStream(connection.getInputStream(), 8192); 275 | int bytesRead = 0; 276 | int offset = 0; 277 | while (bytesRead != -1 && offset < fileSize) { 278 | bytesRead = istream.read(imageData, offset, fileSize - offset); 279 | offset += bytesRead; 280 | 281 | handler.sendMessage(handler.obtainMessage(ImageLoader.HANDLER_MESSAGE_ID1, offset, fileSize)); 282 | 283 | } 284 | 285 | handler.sendMessage(handler.obtainMessage(ImageLoader.HANDLER_MESSAGE_ID1, fileSize, fileSize)); 286 | // clean up 287 | istream.close(); 288 | return imageData; 289 | } 290 | 291 | public void notifyImageLoaded(String url, Bitmap bitmap, boolean limit) { 292 | List handlers = mHandlersCache.remove(url); 293 | // Log.i("l99", String.format("notifyImageLoaded(%d):limit=%s, %s", 294 | // handlers.size(), limit, mImageUrl)); 295 | for (ImageLoaderHandler handler : handlers) { 296 | Message message = Message.obtain(); 297 | message.what = HANDLER_MESSAGE_ID; 298 | 299 | Bundle data = new Bundle(); 300 | data.putString(IMAGE_URL_EXTRA, url); 301 | data.putBoolean(IMAGE_LIMIT_EXTRA, limit); 302 | message.setData(data); 303 | 304 | message.obj = bitmap; 305 | 306 | handler.sendMessage(message); 307 | } 308 | } 309 | } 310 | -------------------------------------------------------------------------------- /src/com/example/utils/BitmapWorkerTask.java: -------------------------------------------------------------------------------- 1 | package com.example.utils; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.BufferedOutputStream; 5 | import java.io.ByteArrayOutputStream; 6 | import java.io.File; 7 | import java.io.FileOutputStream; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.net.MalformedURLException; 11 | import java.net.URL; 12 | import java.util.Collections; 13 | import java.util.Iterator; 14 | import java.util.Map; 15 | import java.util.Map.Entry; 16 | import java.util.WeakHashMap; 17 | import java.util.concurrent.ExecutorService; 18 | import java.util.concurrent.Executors; 19 | 20 | import android.content.Context; 21 | import android.graphics.Bitmap; 22 | import android.graphics.BitmapFactory; 23 | import android.graphics.BitmapFactory.Options; 24 | import android.os.Handler; 25 | import android.os.Message; 26 | import android.text.TextUtils; 27 | import android.view.View; 28 | import android.widget.ImageSwitcher; 29 | 30 | import com.example.cache.LocalCache; 31 | import com.example.support.MediaFile; 32 | 33 | 34 | /** 35 | * 图片加载 36 | * @author Jack 37 | */ 38 | public class BitmapWorkerTask { 39 | // 大于16M的图片降低图片清晰度 40 | private static int MAX_IMAGE_SIZE = 16 * 1024 * 1024; 41 | public static final int BUFF_SIZE = 1024 * 8; 42 | private static final int _1M = 1024 * 1024; 43 | 44 | private static ExecutorService EXECUTOR = null; 45 | private static BitmapWorkerTask mInstance; 46 | private Map mImageCache; 47 | // 用于判断是否正在加载 48 | private Map mLoadCache; 49 | 50 | /** 51 | * 如果是小于480的屏宽设置最大图片未6M 52 | * @param isBigScreen 是否大于480 53 | */ 54 | public void setMAX_IMAGE_SIZE(boolean isBigScreen) { 55 | if (!isBigScreen) { 56 | MAX_IMAGE_SIZE = 8 * 1024 * 1024; 57 | } 58 | } 59 | 60 | public void clearImageCache(Bitmap bitmap){ 61 | if (bitmap == null) return; 62 | if (mImageCache != null && mImageCache.size() > 0) { 63 | mImageCache.remove(bitmap); 64 | } 65 | } 66 | 67 | public void clearImageCache() { 68 | if (mImageCache != null && !mImageCache.isEmpty()) { 69 | mImageCache.clear(); 70 | } 71 | } 72 | 73 | public void clearLoadCache() { 74 | if (mLoadCache != null && !mLoadCache.isEmpty()) { 75 | mLoadCache.clear(); 76 | } 77 | } 78 | 79 | public static BitmapWorkerTask getInstance() { 80 | if (mInstance == null) { 81 | mInstance = new BitmapWorkerTask(); 82 | } 83 | 84 | if (EXECUTOR == null) { 85 | EXECUTOR = Executors.newFixedThreadPool(6); 86 | } 87 | return mInstance; 88 | } 89 | 90 | private BitmapWorkerTask() {} 91 | 92 | /* 93 | * 加载任务 94 | */ 95 | class Task extends Handler implements Runnable { 96 | int width, height; 97 | View view = null; 98 | String url = null; 99 | boolean isCache = true; 100 | boolean isProcessLocal = false; 101 | BitmapWorkerTask.Callback callback = null; 102 | 103 | @Override 104 | public void run() { 105 | Bitmap bitmap = null; 106 | byte[] data = null; 107 | if (callback.isContinue() && !TextUtils.isEmpty(url)) { 108 | bitmap = loadLoaclCache(view.getContext(), url, callback, isProcessLocal); 109 | if (!isProcessLocal && bitmap == null) { 110 | URL m = null; 111 | InputStream in = null; 112 | BufferedInputStream bis = null; 113 | ByteArrayOutputStream out = null; 114 | try { 115 | m = new URL(url); 116 | in = (InputStream) m.getContent(); 117 | if (!callback.isContinue()) return; 118 | if (in != null) { 119 | bis = new BufferedInputStream(in, BUFF_SIZE); 120 | out = new ByteArrayOutputStream(); 121 | int len = 0; 122 | byte[] buffer = new byte[1024]; 123 | while ((len = bis.read(buffer)) != -1) { 124 | out.write(buffer, 0, len); 125 | out.flush(); 126 | } 127 | data = out.toByteArray(); 128 | if (!callback.isContinue()) return; 129 | Options opts = new Options(); 130 | opts.inJustDecodeBounds = true; 131 | BitmapFactory.decodeByteArray(data, 0, data.length, opts); 132 | if (opts.outWidth * opts.outHeight * 4 >= MAX_IMAGE_SIZE) { 133 | opts.inPreferredConfig = Bitmap.Config.ARGB_4444; 134 | } 135 | opts.inJustDecodeBounds = false; 136 | if (width <= 0 && height <= 0) bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opts); 137 | else bitmap = processBitMap(data, width, height); 138 | if (bitmap != null) { 139 | bitmap = callback.formatBitmap(bitmap); 140 | saveLoaclCache(view.getContext(), url, data, bitmap); 141 | } 142 | } 143 | } catch (MalformedURLException e) { 144 | e.printStackTrace(); 145 | } catch (IOException e) { 146 | e.printStackTrace(); 147 | } finally { 148 | try { 149 | if (in != null) in.close(); 150 | if (out != null) out.close(); 151 | if (bis != null) bis.close(); 152 | if (mLoadCache != null) mLoadCache.remove(url); 153 | } catch (Exception e) { 154 | e.printStackTrace(); 155 | } 156 | } 157 | } 158 | } 159 | obtainMessage(513, bitmap).sendToTarget(); 160 | } 161 | 162 | @Override 163 | public void handleMessage(Message msg) { 164 | if (isCache && msg.obj != null) { 165 | if (mImageCache == null) mImageCache = Collections.synchronizedMap(new WeakHashMap()); 166 | mImageCache.put((Bitmap) msg.obj, url); 167 | } 168 | callback.setImage(view, (Bitmap) msg.obj, url);// 设置加载完成 169 | } 170 | } 171 | 172 | /** 173 | * 根据参数宽高获取Bitmap 174 | * @param data 175 | * @param height 176 | * @param width 177 | * @return 178 | */ 179 | private Bitmap processBitMap(byte[] data, int width, int height) { 180 | Options options = new BitmapFactory.Options(); 181 | options.inJustDecodeBounds = true; 182 | BitmapFactory.decodeByteArray(data, 0, data.length, options); 183 | // Calculate inSampleSize 184 | options.inSampleSize = (int) Math.ceil(Math.sqrt(options.outWidth * options.outHeight * 4 / _1M ) ); 185 | // Decode bitmap with inSampleSize set 186 | options.inJustDecodeBounds = false; 187 | 188 | return BitmapFactory.decodeByteArray(data, 0, data.length, options); 189 | } 190 | 191 | /** 192 | * 执行下一个任务 193 | * @param task 194 | */ 195 | private void startNextTask(Task task) { 196 | try { 197 | EXECUTOR.submit(task); 198 | } catch (Exception e) { 199 | e.printStackTrace(); 200 | } 201 | } 202 | 203 | /** 204 | * 带图片参数的加载图片 205 | * @param view 206 | * @param url 207 | * @param callback 208 | * @param width 209 | * @param height 210 | * @param isCache 是否缓存到内存 211 | */ 212 | public void loadWithSize(View view, String url, Callback callback, int width, int height, boolean isCache){ 213 | if (!check(view, url, callback)) 214 | return; 215 | loadStart(view, url, callback, width, height, isCache, false); 216 | } 217 | 218 | /** 219 | * 使用ImageSwitcher加载图片 220 | * @param view 221 | * @param url 222 | * @param callback 223 | * @param isCache 是否缓存到内存 224 | */ 225 | public void loadWithImageSwitcher(ImageSwitcher view, String url, Callback callback, boolean isCache){ 226 | if (!check(view, url, callback)) return; 227 | 228 | loadStart(view, url, callback, 0, 0, isCache, false); 229 | } 230 | 231 | /** 232 | * 加载图片 233 | * @param view 234 | * @param url 235 | * @param callback 236 | * @param isCache 是否缓存到内存 237 | */ 238 | public void load(View view, String url, BitmapWorkerTask.Callback callback, boolean isCache) { 239 | if (!check(view, url, callback)) 240 | return; 241 | 242 | loadStart(view, url, callback, 0, 0, isCache, false); 243 | } 244 | 245 | /** 246 | * @param view 247 | * @param url 248 | * @param callback 249 | * @param isProcessLocal 是否处理本地图片 250 | */ 251 | public void loadLocalFileCallback(View view, String url, BitmapWorkerTask.Callback callback, boolean isProcessLocal) { 252 | if (!check(view, url, callback)) 253 | return; 254 | 255 | loadStart(view, url, callback, 0, 0, true, isProcessLocal); 256 | } 257 | 258 | /** 259 | * 开始加载 260 | * @param view 261 | * @param url 262 | * @param callback 263 | * @param width 264 | * @param height 265 | * @param isCache 是否缓存到内存 266 | * @param isProcessLocal 是否处理本地图片 267 | */ 268 | private void loadStart(View view, String url, BitmapWorkerTask.Callback callback, 269 | int width, int height, boolean isCache, boolean isProcessLocal) { 270 | if (isCache && mImageCache != null && !mImageCache.isEmpty()) { 271 | Iterator> iterator = mImageCache.entrySet().iterator(); 272 | while (iterator.hasNext()) { 273 | Entry entry = iterator.next(); 274 | if (url.equals(entry.getValue())) { 275 | if (entry.getKey() != null && !entry.getKey().isRecycled()) { 276 | callback.setImage(view, entry.getKey(), url); // 直接返回 277 | return; 278 | } else { 279 | mImageCache.remove(entry.getKey()); 280 | break; 281 | } 282 | } 283 | } 284 | } 285 | if (mLoadCache == null) mLoadCache = Collections.synchronizedMap(new WeakHashMap()); 286 | // 如果正在加载返回(还未下载成功) 287 | if (!isProcessLocal && mLoadCache.containsKey(url)) { 288 | File file = localFile(view.getContext(), url); 289 | if (file == null || !file.exists()) { 290 | return; 291 | } 292 | } 293 | 294 | mLoadCache.put(url, ""); 295 | startNextTask(createTask(view, url, callback, width, height, isCache, isProcessLocal)); 296 | } 297 | 298 | /** 299 | * 创建任务 300 | * @param view 301 | * @param url 302 | * @param callback 303 | * @param width 304 | * @param height 305 | * @param isCache 是否缓存到内存 306 | * @param processLocal 是否处理本地图片 307 | * @return 308 | */ 309 | private Task createTask(View view, String url, 310 | BitmapWorkerTask.Callback callback, int width, int height, boolean isCache, boolean processLocal) { 311 | Task task = new Task(); 312 | task.callback = callback; 313 | task.view = view; 314 | task.url = url; 315 | task.width = width; 316 | task.height = height; 317 | task.isCache = isCache; 318 | task.isProcessLocal = processLocal; 319 | return task; 320 | } 321 | 322 | /** 323 | * 是否通过检查 324 | * @param view 325 | * @param url 326 | * @param callback 327 | * @return 328 | */ 329 | private boolean check(View view, String url, BitmapWorkerTask.Callback callback) { 330 | if (view == null) 331 | return false; 332 | if (TextUtils.isEmpty(url)) 333 | return false; 334 | if (callback == null) 335 | return false; 336 | return true; 337 | } 338 | 339 | /** 340 | * 加载本地缓存 341 | * @param ctx 342 | * @param url 343 | * @param callback 344 | * @param isProcessLocal 345 | * @return 346 | */ 347 | private synchronized Bitmap loadLoaclCache(Context ctx, String url, Callback callback, boolean isProcessLocal) { 348 | // 是否处理本地图片 349 | if (!isProcessLocal) { 350 | File file = localFile(ctx, url); 351 | if (file != null && file.exists() && file.canRead()) { 352 | try { 353 | Options opts = new Options(); 354 | opts.inJustDecodeBounds = true; 355 | BitmapFactory.decodeFile(file.getPath(), opts); 356 | if (opts.outWidth * opts.outHeight * 4 >= MAX_IMAGE_SIZE) { 357 | opts.inPreferredConfig = Bitmap.Config.ARGB_4444; 358 | } 359 | opts.inJustDecodeBounds = false; 360 | return BitmapUtils.decodeBitmapFromDescriptor(file.getPath(), opts); 361 | } catch (OutOfMemoryError e1) { 362 | } catch (Exception e) { 363 | } 364 | } 365 | } else { 366 | return callback.formatBitmap(null); 367 | } 368 | return null; 369 | } 370 | 371 | private File localFile(Context ctx, String url) { 372 | if (ctx == null || TextUtils.isEmpty(url)) 373 | return null; 374 | File file = new File(LocalCache.IMAGE.getLocalImgPath(ctx, url)); 375 | return file; 376 | } 377 | 378 | /** 379 | * 保存本地缓存 380 | * @param context 381 | * @param url 382 | * @param buffer 383 | * @param img 384 | */ 385 | private synchronized void saveLoaclCache(Context ctx, String url, byte[] buffer, Bitmap img) { 386 | if (buffer == null) 387 | return; 388 | File file = localFile(ctx, url); 389 | deleteFile(file); 390 | FileOutputStream fos = null; 391 | try { 392 | if (MediaFile.isGifFileType(url)) { 393 | fos = new FileOutputStream(file); 394 | BufferedOutputStream bos = new BufferedOutputStream(fos, BUFF_SIZE); 395 | if (bos != null) { 396 | bos.write(buffer); 397 | bos.flush(); 398 | bos.close(); 399 | } 400 | } else { 401 | fos = new FileOutputStream(file); 402 | img.compress(Bitmap.CompressFormat.PNG, 100, fos); 403 | } 404 | } catch (Exception e) { 405 | e.printStackTrace(); 406 | deleteFile(file); 407 | } finally { 408 | try { 409 | if (fos != null) fos.close(); 410 | } catch (IOException e) { 411 | e.printStackTrace(); 412 | deleteFile(file); 413 | } 414 | } 415 | } 416 | 417 | private void deleteFile(File file) { 418 | if (file != null && file.exists() && file.canWrite()) { 419 | file.delete(); 420 | } 421 | } 422 | 423 | /** 424 | * 加载回调 425 | * @author Mike 426 | */ 427 | public interface Callback { 428 | /** 429 | * 格式化图片 430 | * @param img 431 | * @return img 432 | */ 433 | public Bitmap formatBitmap(Bitmap img); 434 | 435 | /** 436 | * 使用图片 437 | * @param View 438 | * @param img 439 | */ 440 | public void setImage(View v, Bitmap img, String url); 441 | 442 | /** 443 | * 当前任务是否继续 444 | * @return 445 | */ 446 | public boolean isContinue(); 447 | } 448 | } 449 | -------------------------------------------------------------------------------- /src/com/example/utils/Utils.java: -------------------------------------------------------------------------------- 1 | package com.example.utils; 2 | 3 | import java.io.BufferedOutputStream; 4 | import java.io.BufferedReader; 5 | import java.io.ByteArrayInputStream; 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.Closeable; 8 | import java.io.File; 9 | import java.io.FileInputStream; 10 | import java.io.FileOutputStream; 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.io.InputStreamReader; 14 | import java.io.ObjectInputStream; 15 | import java.io.ObjectOutputStream; 16 | import java.io.OutputStream; 17 | import java.io.UnsupportedEncodingException; 18 | import java.net.URLEncoder; 19 | import java.nio.channels.FileChannel; 20 | import java.text.ParseException; 21 | import java.text.SimpleDateFormat; 22 | import java.util.Date; 23 | import java.util.Locale; 24 | import java.util.Set; 25 | import java.util.UUID; 26 | 27 | import android.content.Context; 28 | import android.graphics.Bitmap; 29 | import android.graphics.Bitmap.Config; 30 | import android.graphics.BitmapFactory; 31 | import android.graphics.BitmapFactory.Options; 32 | import android.graphics.Matrix; 33 | import android.os.Bundle; 34 | import android.os.Environment; 35 | import android.text.TextUtils; 36 | import android.util.DisplayMetrics; 37 | import android.util.Log; 38 | 39 | import com.example.android_arcavatarimageview.R; 40 | import com.example.support.SystemSupport; 41 | 42 | 43 | /** 44 | * 一些通用的方法 45 | * @author Jack 46 | */ 47 | public class Utils { 48 | 49 | /** 50 | * The number of bytes in a kilobyte. 51 | */ 52 | public static final long ONE_KB = 1024; 53 | 54 | /** 55 | * The number of bytes in a megabyte. 56 | */ 57 | public static final long ONE_MB = ONE_KB * ONE_KB; 58 | 59 | /** 60 | * The file copy buffer size (30 MB) 61 | */ 62 | private static final long FILE_COPY_BUFFER_SIZE = ONE_MB * 30; 63 | 64 | protected static SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat("MM/dd HH:mm"); 65 | protected static SimpleDateFormat mSimpleDateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm"); 66 | public static final int MEDIA_TYPE_VIDEO_THUMBNAIL = 1; //视频缩略图 67 | public static final int MEDIA_TYPE_VIDEO = 2; //视频 68 | public static final int MEDIA_TYPE_ZIP = 3; //视频 69 | 70 | public static void chmod(String permission, String path) { 71 | try { 72 | String command = "chmod " + permission + " " + path; 73 | Runtime runtime = Runtime.getRuntime(); 74 | runtime.exec(command); 75 | } catch (IOException e) { 76 | e.printStackTrace(); 77 | } 78 | } 79 | 80 | /** 81 | * 82 | * @param is 83 | * @return 84 | * @throws IOException 85 | */ 86 | public static String streamToString(InputStream is) { 87 | return streamToString(is, "UTF-8"); 88 | } 89 | 90 | public static String streamToString(InputStream is, String enc) { 91 | StringBuilder buffer = new StringBuilder(); 92 | String line = null; 93 | try { 94 | BufferedReader reader = new BufferedReader(new InputStreamReader(is, enc), 8192); 95 | while (null != (line = reader.readLine())) { 96 | buffer.append(line); 97 | } 98 | } catch (Exception e) { 99 | e.printStackTrace(); 100 | } finally { 101 | try { 102 | is.close(); 103 | } catch (IOException e) { 104 | e.printStackTrace(); 105 | } 106 | } 107 | return buffer.toString(); 108 | } 109 | 110 | /** 111 | * @param is 112 | * @param os 113 | */ 114 | public static void copyStream(InputStream is, OutputStream os) { 115 | final int buffer_size = 1024; 116 | try { 117 | byte[] bytes = new byte[buffer_size]; 118 | int count = is.read(bytes, 0, buffer_size); 119 | while (-1 != count) { 120 | os.write(bytes, 0, count); 121 | count = is.read(bytes, 0, buffer_size); 122 | } 123 | } catch (Exception ex) { 124 | ex.printStackTrace(); 125 | } 126 | } 127 | 128 | public static String bundle2String(Bundle bundle) throws UnsupportedEncodingException { 129 | if (null != bundle) { 130 | Set keys = bundle.keySet(); 131 | if (null != keys && !keys.isEmpty()) { 132 | StringBuilder buffer = new StringBuilder(); 133 | for (String key : keys) { 134 | String value = bundle.getString(key); 135 | buffer.append("&").append(key).append("=").append(URLEncoder.encode(value, "UTF-8")); 136 | } 137 | return buffer.toString(); 138 | } 139 | } 140 | 141 | return ""; 142 | } 143 | 144 | /** 145 | * px(value)=(int) (dip(value) * density + 0.5) 146 | * 147 | * @param context 148 | * @param dipValue 149 | * @return 150 | */ 151 | public static int dip2px(Context context, float dipValue) { 152 | final float density = context.getResources().getDisplayMetrics().density; 153 | return (int) (dipValue * density + 0.5f); 154 | } 155 | 156 | /** 157 | * dip(value)=(int) (px(value) / density + 0.5) 158 | * 159 | * @param context 160 | * @param pxValue 161 | * @return 162 | */ 163 | public static int px2dip(Context context, float pxValue) { 164 | final float density = context.getResources().getDisplayMetrics().density; 165 | return (int) (pxValue / density + 0.5f); 166 | } 167 | 168 | public static int dip2DeviceWidthPx(Context context, float dipValue) { 169 | final float density = context.getResources().getDisplayMetrics().density; 170 | float widthPixels = context.getResources().getDisplayMetrics().widthPixels; 171 | return (int) (widthPixels - density * 320 + density * dipValue); 172 | } 173 | 174 | /** 175 | * @param date 176 | * @return 177 | */ 178 | public static String getDisplayTime(Long date) { 179 | return new SimpleDateFormat("MM/dd HH:mm").format(date); 180 | } 181 | 182 | /** 183 | * @param date 184 | * @return 185 | */ 186 | public static String getDisplayTime2(Long date) { 187 | return new SimpleDateFormat("yyyy-MM-dd HH:mm").format(date); 188 | } 189 | 190 | /** 191 | * 转换UTC时间 192 | * 193 | * @param utcTime 194 | * @return 195 | */ 196 | public static Date getDateByUTC(String utcTime) { 197 | Date date; 198 | SimpleDateFormat formatter = new SimpleDateFormat("E MMM dd HH:mm:ss ZZZZ yyyy", Locale.ENGLISH); 199 | 200 | try { 201 | date = formatter.parse(utcTime); 202 | } catch (ParseException e) { 203 | e.printStackTrace(); 204 | date = new Date(); 205 | } 206 | 207 | return date; 208 | } 209 | 210 | public static String getDateStringByUTC(String utcTime) { 211 | if (TextUtils.isEmpty(utcTime)) return ""; 212 | return mSimpleDateFormat.format(new Date(utcTime)); 213 | } 214 | 215 | public static String getDateStringByUTC2(String utcTime) { 216 | String timeStr = null; 217 | if (utcTime != null) { 218 | timeStr = mSimpleDateFormat2.format(new Date(utcTime)); 219 | } 220 | return timeStr; 221 | } 222 | 223 | public static String getVideoTimeFormatString(int currentPosition, int duration) { 224 | SimpleDateFormat formatter = new SimpleDateFormat("mm:ss"); 225 | StringBuffer resultStr = new StringBuffer(); 226 | resultStr.append(formatter.format(currentPosition)); 227 | resultStr.append("/"); 228 | resultStr.append(formatter.format(duration)); 229 | return resultStr.toString(); 230 | } 231 | 232 | public static String getVideoTimeFormatString(int time) { 233 | SimpleDateFormat formatter = new SimpleDateFormat("mm:ss"); 234 | StringBuffer resultStr = new StringBuffer(); 235 | resultStr.append(formatter.format(time)); 236 | return resultStr.toString(); 237 | } 238 | 239 | /** 240 | * 格式化时间 241 | * @param time 单位为毫秒级 242 | * @return 243 | */ 244 | public static String formatToDoveBoxDate (Context context, String time) 245 | { 246 | if (context == null) return ""; 247 | final Date currentData = new Date(); 248 | final Date targetData = new Date(time); 249 | int intervalSeconds = (int) ((currentData.getTime() - targetData.getTime()) / 1000); 250 | int intervalMin = intervalSeconds / 60; 251 | if(intervalSeconds < 0 || intervalMin == 0) { 252 | return context.getString(R.string.just_now); 253 | } 254 | StringBuilder sb = new StringBuilder(); 255 | if(intervalMin < 60 && intervalMin > 0) { 256 | sb.append(intervalMin).append(context.getString(R.string.minute_before)); 257 | return sb.toString(); 258 | } 259 | int intervalHour = intervalMin / 60; 260 | if(intervalHour < 24) { 261 | sb.append(intervalHour).append(context.getString(R.string.hour_before)); 262 | return sb.toString(); 263 | } 264 | int currentPassMin = currentData.getHours() * 60 + currentData.getMinutes(); 265 | int targetPassMin = targetData.getHours() * 60 + targetData.getMinutes(); 266 | int intervalDay = (intervalMin - ( targetPassMin - currentPassMin)) / (24 * 60); 267 | if(intervalDay < 3) { 268 | sb.append(intervalDay).append(context.getString(R.string.day_before)); 269 | return sb.toString(); 270 | } 271 | return mSimpleDateFormat2.format(targetData); 272 | } 273 | 274 | public static String getTakephotoFileName() { 275 | String randomUUID = UUID.randomUUID().toString(); 276 | return randomUUID + ".jpg"; 277 | } 278 | 279 | /** 280 | * 获取屏幕高度的方法 281 | * 282 | * @param context 283 | * @return 返回屏幕宽高 284 | */ 285 | public static int[] getScreenHeightAndWidth(Context context){ 286 | int[] returnIntArray = new int[2]; 287 | DisplayMetrics dm = context.getResources().getDisplayMetrics(); 288 | returnIntArray[0] = dm.widthPixels; 289 | returnIntArray[1] = dm.heightPixels; 290 | return returnIntArray; 291 | } 292 | 293 | /** 294 | * 限制图片不要超过1M内存 295 | * 296 | * @param path 297 | * @return 返回小于1M的bitmap 298 | */ 299 | public static Bitmap create1MBitmap(String path) { 300 | Options opts = new Options(); 301 | opts.inJustDecodeBounds = true; 302 | BitmapFactory.decodeFile(path, opts); 303 | float m = 1024 * 1024; 304 | opts.inSampleSize = (int) Math.ceil(Math.sqrt(opts.outWidth * opts.outHeight * 4 / m) ); 305 | opts.inJustDecodeBounds = false; 306 | Bitmap bitmap = null; 307 | try { 308 | bitmap = BitmapFactory.decodeFile(path, opts); 309 | } catch (OutOfMemoryError er) { 310 | bitmap = null; 311 | er.printStackTrace(); 312 | } catch (Exception e) { 313 | bitmap = null; 314 | e.printStackTrace(); 315 | } 316 | return bitmap; 317 | 318 | } 319 | 320 | public static Bitmap create1MBitmap(Bitmap bitmap) { 321 | float m = 1024 * 1024; 322 | int time = (int) Math.ceil(Math.sqrt(bitmap.getWidth() * bitmap.getHeight() * 4 / m) ); 323 | Bitmap bitMap = null; 324 | try { 325 | bitMap = Bitmap.createBitmap(bitmap.getWidth() / time, bitmap.getHeight() / time, Config.ARGB_8888); 326 | } catch (OutOfMemoryError er) { 327 | bitmap = null; 328 | er.printStackTrace(); 329 | } catch (Exception e) { 330 | bitmap = null; 331 | e.printStackTrace(); 332 | } 333 | return bitMap; 334 | } 335 | 336 | /** 337 | * 取小图片 338 | * 339 | * @param path 340 | * @return 341 | */ 342 | public static Bitmap createSmallBitmap(String path) { 343 | Options opts = new Options(); 344 | opts.inJustDecodeBounds = true; 345 | BitmapFactory.decodeFile(path, opts); 346 | float m = 100 * 100; 347 | opts.inSampleSize = (int) Math.ceil(Math.sqrt(opts.outWidth * opts.outHeight * 4 / m) ); 348 | opts.inJustDecodeBounds = false; 349 | Bitmap bitmap = null; 350 | try { 351 | bitmap = BitmapFactory.decodeFile(path, opts); 352 | } catch (OutOfMemoryError er) { 353 | bitmap = null; 354 | er.printStackTrace(); 355 | } catch (Exception e) { 356 | bitmap = null; 357 | e.printStackTrace(); 358 | } 359 | return bitmap; 360 | } 361 | 362 | /** 363 | * 创建小图 364 | * 365 | * @param path 366 | * @return 367 | */ 368 | public static String createSmallImage(String path, String savePath) { 369 | Options opts = new Options(); 370 | opts.inJustDecodeBounds = true; 371 | BitmapFactory.decodeFile(path, opts); 372 | if (opts.outWidth > 200 && opts.outHeight > 200) { 373 | opts.inSampleSize = Math.min(opts.outWidth / 200, opts.outHeight / 200); 374 | } 375 | opts.inJustDecodeBounds = false; 376 | Bitmap bitmap = null; 377 | try { 378 | bitmap = BitmapFactory.decodeFile(path, opts); 379 | } catch (OutOfMemoryError er) { 380 | bitmap = null; 381 | er.printStackTrace(); 382 | } catch (Exception e) { 383 | bitmap = null; 384 | e.printStackTrace(); 385 | } 386 | 387 | StringBuilder sb = new StringBuilder(); 388 | sb.append(savePath); 389 | sb.append(System.currentTimeMillis()); 390 | sb.append("temp.jpg"); 391 | File file = new File(sb.toString()); 392 | if (file.exists()) { 393 | file.delete(); 394 | } 395 | 396 | BufferedOutputStream bos = null; 397 | try { 398 | bos = new BufferedOutputStream(new FileOutputStream(file)); 399 | bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos); 400 | } catch(OutOfMemoryError e) { 401 | Log.e(Utils.class.getSimpleName(), e.toString()); 402 | } catch (Exception e) { 403 | Log.e(Utils.class.getSimpleName(), e.toString()); 404 | return ""; 405 | } finally { 406 | if (bos != null) { 407 | try { 408 | bos.flush(); 409 | bos.close(); 410 | } catch (IOException e1) { 411 | e1.printStackTrace(); 412 | return ""; 413 | } 414 | } 415 | } 416 | return sb.toString(); 417 | } 418 | 419 | /** 420 | * 创建一个新的文件(降低大于50Kb的图片的质量)用于网络传输 421 | * 422 | * @param savePath 423 | * @param bitmap 424 | * @return 返回新的图片或者为空。为空时表示没有生成新图片 425 | */ 426 | public static String create50KBFile(String savePath, Bitmap bitmap, boolean isMake) { 427 | // int width = bitmap.getWidth(); 428 | // int height = bitmap.getHeight(); 429 | // if (!isMake && width * height < 1024 * 50) return ""; 430 | 431 | StringBuilder sb = new StringBuilder(); 432 | sb.append(savePath); 433 | sb.append(System.currentTimeMillis()); 434 | sb.append("temp.jpg"); 435 | File file = new File(sb.toString()); 436 | if (file.exists()) { 437 | file.delete(); 438 | } 439 | 440 | BufferedOutputStream bos = null; 441 | try { 442 | bos = new BufferedOutputStream(new FileOutputStream(file)); 443 | bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos); 444 | } catch(OutOfMemoryError e) { 445 | Log.e(Utils.class.getSimpleName(), e.toString()); 446 | } catch (Exception e) { 447 | Log.e(Utils.class.getSimpleName(), e.toString()); 448 | return ""; 449 | } finally { 450 | if (bos != null) { 451 | try { 452 | bos.flush(); 453 | bos.close(); 454 | } catch (IOException e1) { 455 | e1.printStackTrace(); 456 | return ""; 457 | } 458 | } 459 | } 460 | return sb.toString(); 461 | } 462 | 463 | /** 464 | * 创建一个指定大小的正方形图片 465 | * @param path 466 | * @param width 467 | * @return 468 | */ 469 | public static Bitmap createBitmap(String path, int width, float orientationDegree) { 470 | Bitmap bitmap = null; 471 | Options opts = new Options(); 472 | opts.inJustDecodeBounds = true; 473 | BitmapFactory.decodeFile(path, opts); 474 | if (opts.outWidth > width && opts.outHeight > width) { 475 | opts.inSampleSize = Math.min(opts.outWidth / width, opts.outHeight / width); 476 | } 477 | opts.inJustDecodeBounds = false; 478 | try { 479 | bitmap = BitmapFactory.decodeFile(path, opts); 480 | int height = opts.outHeight; 481 | if (opts.outWidth < width) width = opts.outWidth; 482 | if (height > width) height = width; 483 | if(orientationDegree != 0) { 484 | Matrix m = new Matrix(); 485 | m.setRotate(orientationDegree, (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2); 486 | bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, m, true); 487 | } else { 488 | bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height); 489 | } 490 | } catch (OutOfMemoryError er) { 491 | bitmap = null; 492 | er.printStackTrace(); 493 | } catch (Exception e) { 494 | bitmap = null; 495 | e.printStackTrace(); 496 | } 497 | return bitmap; 498 | } 499 | 500 | /** 501 | * 获取自定义拍摄视频存储路径,缩略图问题待完善 502 | * 503 | * @throws IOException 504 | */ 505 | public static File getOutputMediaFile(Context context, int type, String pathDir) throws IOException { 506 | String state = Environment.getExternalStorageState(); 507 | if (!state.equals(Environment.MEDIA_MOUNTED)) { 508 | throw new IOException(context.getString(R.string.no_sdcard_string)); 509 | } else { 510 | if (SystemSupport.readSDCard() < 3096) { 511 | throw new IOException(context.getString(R.string.no_space_string)); 512 | } 513 | ; 514 | } 515 | File mediaStorageDir = new File(pathDir); 516 | if (!mediaStorageDir.exists()) { 517 | if (!mediaStorageDir.mkdirs()) { 518 | return null; 519 | } 520 | } 521 | // 创建媒体文件名 522 | String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); 523 | File mediaFile; 524 | if (type == MEDIA_TYPE_VIDEO_THUMBNAIL) { 525 | mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp 526 | + ".jpg"); 527 | } else if (type == MEDIA_TYPE_VIDEO) { 528 | mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_" + timeStamp 529 | + ".mp4"); 530 | } else if (type == MEDIA_TYPE_ZIP) 531 | { 532 | mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_" + timeStamp 533 | + ".zip"); 534 | }else { 535 | 536 | return null; 537 | } 538 | return mediaFile; 539 | } 540 | 541 | /** 542 | * 复制文件 543 | * 544 | * @param oldPath 545 | * @param newPath 546 | * @throws IOException 547 | */ 548 | public static void onCopyPic(String oldPath, String newPath) throws IOException { 549 | File from = new File(oldPath); 550 | if (!from.exists() || !from.isFile() || !from.canRead()) { 551 | return; 552 | } 553 | File to = new File(newPath); 554 | if (!to.getParentFile().exists()) { 555 | to.getParentFile().mkdirs(); 556 | } 557 | if (to.exists()) { 558 | to.delete(); 559 | } 560 | 561 | FileInputStream fis = null; 562 | FileOutputStream fos = null; 563 | FileChannel input = null; 564 | FileChannel output = null; 565 | try { 566 | fis = new FileInputStream(from); 567 | fos = new FileOutputStream(to); 568 | input = fis.getChannel(); 569 | output = fos.getChannel(); 570 | long size = input.size(); 571 | long pos = 0; 572 | long count = 0; 573 | while (pos < size) { 574 | count = size - pos > FILE_COPY_BUFFER_SIZE ? FILE_COPY_BUFFER_SIZE : size - pos; 575 | pos += output.transferFrom(input, pos, count); 576 | } 577 | } finally { 578 | closeQuietly(output); 579 | closeQuietly(fos); 580 | closeQuietly(input); 581 | closeQuietly(fis); 582 | } 583 | 584 | if (from.length() != to.length()) { 585 | throw new IOException("Failed to copy full contents from '" + 586 | from + "' to '" + to + "'"); 587 | } 588 | to.setLastModified(from.lastModified()); 589 | } 590 | 591 | public static String getCameraPath() { 592 | String fileDir; 593 | if (new File("sdcard/Camera").exists()) { 594 | fileDir = "sdcard/Camera/"; 595 | } else if (new File("sdcard/DCIM/Camera").exists()) { 596 | fileDir = "sdcard/DCIM/Camera/"; 597 | } else { 598 | fileDir = "sdcard/DCIM/"; 599 | } 600 | return fileDir; 601 | } 602 | 603 | private static void closeQuietly(OutputStream output) { 604 | closeQuietly((Closeable)output); 605 | } 606 | 607 | private static void closeQuietly(Closeable closeable) { 608 | try { 609 | if (closeable != null) { 610 | closeable.close(); 611 | } 612 | } catch (IOException ioe) { 613 | // ignore 614 | } 615 | } 616 | 617 | /** 618 | * 取小图片 619 | * 620 | * @param path 621 | * @return 622 | */ 623 | public static Bitmap createChatBitmap(String path) { 624 | Options opts = new Options(); 625 | opts.inJustDecodeBounds = true; 626 | BitmapFactory.decodeFile(path, opts); 627 | float m = 150 * 150; 628 | opts.inSampleSize = (int) Math.ceil(Math.sqrt(opts.outWidth * opts.outHeight * 4 / m) ); 629 | opts.inJustDecodeBounds = false; 630 | Bitmap bitmap = null; 631 | try { 632 | bitmap = BitmapFactory.decodeFile(path, opts); 633 | } catch (OutOfMemoryError er) { 634 | bitmap = null; 635 | er.printStackTrace(); 636 | } catch (Exception e) { 637 | bitmap = null; 638 | e.printStackTrace(); 639 | } 640 | return bitmap; 641 | } 642 | 643 | public final static Object objectCopy(Object oldObj) { 644 | Object newObj = null; 645 | try { 646 | ByteArrayOutputStream bo = new ByteArrayOutputStream(); 647 | ObjectOutputStream oo = new ObjectOutputStream(bo); 648 | oo.writeObject(oldObj);//源对象 649 | ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); 650 | ObjectInputStream oi= new ObjectInputStream(bi); 651 | newObj = oi.readObject();//目标对象 652 | } catch (IOException e) { 653 | e.printStackTrace(); 654 | }catch (ClassNotFoundException e) { 655 | e.printStackTrace(); 656 | } 657 | return newObj; 658 | } 659 | } 660 | --------------------------------------------------------------------------------