从网络下载图片时,使用多线程同时下载,可以提高下载速度,带来更好的用户体验.
1. 下载图片的线程池管理类
/**
* 下载图片的线程池管理
*/
public class ThreadPoolManager {
public static ExecutorService cachePool = Executors.newFixedThreadPool(10);
public static ExecutorService savePool; // 保存文件
public static void startThread() {
cachePool = Executors.newFixedThreadPool(10);
}
public static void shutdownThread() {
cachePool.shutdownNow();
cachePool = null;
}
public static void restoration() {
shutdownThread();
startThread();
}
public static void startSavePool(Thread thread) {
if (savePool == null) {
savePool = Executors.newFixedThreadPool(1);
} else {
savePool.execute(thread);
}
}
public static void shutdownSavePool() {
cachePool.shutdownNow();
cachePool = null;
}
}
2. 下载图片管理类 BitmapCache
public class BitmapCache {
public final String CACHE_PATH = Environment.getExternalStorageDirectory()
+ "/vodbitmapcache/"; // 文件缓存的路径
public final String CACHE_FILE = "vodbitmapcache"; // 缓存文件夹名称
private FileUtils fileUtils;
private List<Bitmap> listCache;
private boolean iso = false;
public BitmapCache() {
fileUtils = new FileUtils();
if (!fileUtils.isFileExist(CACHE_FILE)) {
fileUtils.createSDDir(CACHE_FILE);
}
if (listCache == null) {
listCache = new ArrayList<Bitmap>();
} else {
for (int i = 0; i < listCache.size(); i++) {
listCache.get(i).recycle();
}
listCache.clear();
}
}
public void getBitmap(final String url, final int position,
final BitmapCallBack bitmapCallBack) {
if (position == 0) {
if (iso == true) {
return;
}
iso = true;
}
final Handler handler = new Handler() {
public void handleMessage(Message message) {
bitmapCallBack.load((Bitmap) message.obj);
}
};
if (ThreadPoolManager.cachePool != null
&& !ThreadPoolManager.cachePool.isShutdown()) {
ThreadPoolManager.cachePool.execute(new Thread(new Runnable() {
@Override
public void run() {
Bitmap bitmap = getLocalImage(getFilePath(url)); // 取本地
if (bitmap == null) {
bitmap = downBitmap(url); // 网络下载
if (null != bitmap) {
listCache.add(bitmap);
Message message = handler.obtainMessage(0, bitmap);
message.sendToTarget();
}
} else {
listCache.add(bitmap);
Message message = handler.obtainMessage(0, bitmap);
message.sendToTarget();
}
/*if(bitmap == null){
bitmap = downBitmap(url);
listCache.add(bitmap);
Message message = handler.obtainMessage(0, bitmap);
message.sendToTarget();
}*/
}
}));
}
}
public String getFilePath(String url) {
return CACHE_FILE + "/" + url.substring(url.lastIndexOf("/") + 1);
}
public String getFileName(String url) {
return url.substring(url.lastIndexOf("/") + 1);
}
// 清空map中所有的数据
public void clearBitmap() {
if (listCache != null) {
LogUtil.i("回收所有图片", listCache.size() + "");
for (int i = 0; i < listCache.size(); i++) {
listCache.get(i).recycle();
}
listCache.clear();
}
iso = false;
}
// 删除保存在sd中的图片
public void deleteFile() {
fileUtils.deleteDir(new File(Environment.getExternalStorageDirectory()
+ "/" + CACHE_FILE));
}
public Bitmap downBitmap(String url) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Config.RGB_565;//
InputStream is = null;
HttpURLConnection conn = null;
Bitmap bitmap = null;
try {
URL u = new URL(url);
conn = (HttpURLConnection) u.openConnection();
conn.setConnectTimeout(10000);
is = conn.getInputStream();
// bitmap = BitmapFactory.decodeStream(is);
List<InputStream> list = AppUtil.copyInputStream(is, 3);
if (list != null && list.size() == 3) {
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(list.get(0), null, options);
sampleSize(options, 200, 250);// 根据图片宽高压缩图片
bitmap = BitmapFactory.decodeStream(list.get(1), null, options);
saveBitmap(url, list.get(2)); // 保存图片
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
closeIO(is);
conn.disconnect();
}
return bitmap;
// return getRoundedCornerBitmap(bitmap);
}
// 保存图片
public void saveBitmap(final String url, final InputStream inputStream) {
ThreadPoolManager.startSavePool(new Thread(new Runnable() {
@Override
public void run() {
String fileName = CACHE_FILE + "/" + getFileName(url);
if (!fileUtils.isFileExist(fileName)) {
fileUtils.write2SDFromInput(fileName, inputStream); // 保存到本地
}
}
}));
}
// sd卡取值
public Bitmap getLocalImage(String path) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Config.RGB_565;//
if (fileUtils.isFileExist(path)) {
Bitmap dump = null;
try {
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileUtils.getSDPATH() + path, options);
sampleSize(options, 200, 250);
dump = BitmapFactory.decodeFile(fileUtils.getSDPATH() + path,
options);
} catch (OutOfMemoryError oom) {
oom.printStackTrace();
}
return dump;
}
return null;
}
public void closeIO(Closeable io) {
if (io != null) {
try {
io.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 根据图片宽高压缩图片
public void sampleSize(BitmapFactory.Options options, int w, int h) {
options.inJustDecodeBounds = false;
if (w <= 0 || h <= 0) {
options.inSampleSize = 1;
}
int initialSize = (int) Math.ceil(Math.sqrt(options.outWidth
* options.outHeight / (w * h)));
initialSize = Math.max(initialSize,
Math.max(options.outWidth / w, options.outHeight / h));
if (initialSize < 1) {
options.inSampleSize = 1;
} else {
options.inSampleSize = initialSize;
}
if (initialSize < 1) {
options.inSampleSize = 1;
} else {
options.inSampleSize = initialSize;
}
}
public Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
if(bitmap==null){
return null;
}
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.RGB_565);
// 得到画布
Canvas canvas = new Canvas(output);
// 将画布的四角圆化
final int color = Color.RED;
final Paint paint = new Paint();
// 得到与图像相同大小的区域 由构造的四个值决定区域的位置以及大小
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
// 值越大角度越明显
final float roundPx = 20;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
// drawRoundRect的第2,3个参数一样则画的是正圆的一角,如果数值不同则是椭圆的一角
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
}
3.使用到的文件工具类
public class FileUtils {
/**
* 需要知道当前SD卡的目录,Environment.getExternalStorageDierctory()
*/
private String SDPATH;
public String getSDPATH() {
return SDPATH;
}
public FileUtils() { // 目录名/sdcard
SDPATH = Environment.getExternalStorageDirectory() + "/";
}
// 在sdcard卡上创建文件
public File createSDFile(String fileName) throws IOException {
File file = new File(SDPATH + fileName);
file.createNewFile();
return file;
}
// 在sd卡上创建目录
public File createSDDir(String dirName) {
File dir = new File(SDPATH + dirName);
// mkdir只能创建一级目录 ,mkdirs可以创建多级目录
dir.mkdir();
return dir;
}
// 判断sd卡上的文件夹是否存在
public boolean isFileExist(String fileName) {
File file = new File(SDPATH + fileName);
return file.exists();
}
public void deleteFile(String fileName) {
File file = new File(SDPATH + fileName);
file.delete();
}
/**
* 将一个inputstream里面的数据写入SD卡中 第一个参数为目录名 第二个参数为文件名
*/
public File write2SDFromInput(String path, InputStream inputstream) {
File file = null;
OutputStream output = null;
try {
file = createSDFile(path);
output = new FileOutputStream(file);
// 4k为单位,每4K写一次
byte buffer[] = new byte[4 * 1024];
int temp = 0;
while ((temp = inputstream.read(buffer)) != -1) {
// 获取指定信,防止写入没用的信息
output.write(buffer, 0, temp);
}
output.flush();
LogUtil.i("保存文件", path);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(output!=null){
output.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return file;
}
public void deleteDir(File file) {
if (file.isDirectory()) {
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++) {
deleteDir(files[i]);
}
}
file.delete();
}
}
4. AppUtil
public class AppUtil {
public final static String TAG = "AppUtil";
// 应用版本
public static String getAppVersionCode(Context context) {
String packageName = context.getPackageName();
try {
String versionCode = context.getPackageManager().getPackageInfo(
packageName, 0).versionName;
return versionCode;
} catch (NameNotFoundException e) {
throw new RuntimeException("System fault!!!", e);
}
}
// 获取系统语言
public static String getSystemLanguage(Context context) {
Locale locale = context.getResources().getConfiguration().locale;
String language = locale.getLanguage();
// Locale l = Locale.getDefault();
// String language = String.format("%s-%s", l.getLanguage(),
// l.getCountry());
return language;
}
// 获取包名
public static String getAppPackageName(Context context) {
try {
String pkName = context.getPackageName();
return pkName;
} catch (Exception e) {
}
return null;
}
// 复制InputStream
public static List<InputStream> copyInputStream(InputStream input, int size) {
List<InputStream> list = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) > -1) {
baos.write(buffer, 0, len);
}
baos.flush();
list = new ArrayList<InputStream>();
for (int i = 0; i < size; i++) {
InputStream stream1 = new ByteArrayInputStream(
baos.toByteArray());
list.add(stream1);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return list;
}
}
5.缩略图工具类
public class BitmapUtils {
// 缩略图缓存
private final static int maxMemory = (int) Runtime.getRuntime().maxMemory();// 获取当前应用程序所分配的最大内存
private final static int cacheSize = (int) (maxMemory / 8);// 只分 ?
// 分之一用来做图片缓存
public static LruCache<String, Bitmap> mLruCache = new LruCache<String, Bitmap>(
cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {// 复写sizeof()方法
return bitmap.getRowBytes() * bitmap.getHeight();
}
};
public static ExecutorService pool = Executors.newFixedThreadPool(10);
public interface BitmapCallBack {
void load(Bitmap bm);
};
public interface HomeBitmapCallBack {
void load(Bitmap bm, int index);
}
// ************************
public static Bitmap createImageThumbnail(String filePath) {
Bitmap bitmap = null;
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, opts);
opts.inSampleSize = computeSampleSize(opts, -1, 128 * 128);
opts.inJustDecodeBounds = false;
try {
bitmap = BitmapFactory.decodeFile(filePath, opts);
} catch (Exception e) {
// TODO: handle exception
}
return bitmap;
}
public static int computeSampleSize(BitmapFactory.Options options,
int minSideLength, int maxNumOfPixels) {
int initialSize = computeInitialSampleSize(options, minSideLength,
maxNumOfPixels);
int roundedSize;
if (initialSize <= 8) {
roundedSize = 1;
while (roundedSize < initialSize) {
roundedSize <<= 1;
}
} else {
roundedSize = (initialSize + 7) / 8 * 8;
}
return roundedSize;
}
private static int computeInitialSampleSize(BitmapFactory.Options options,
int minSideLength, int maxNumOfPixels) {
double w = options.outWidth;
double h = options.outHeight;
int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math
.sqrt(w * h / maxNumOfPixels));
int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(
Math.floor(w / minSideLength), Math.floor(h / minSideLength));
if (upperBound < lowerBound) {
// return the larger one when there is no overlapping zone.
return lowerBound;
}
if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
return 1;
} else if (minSideLength == -1) {
return lowerBound;
} else {
return upperBound;
}
}
// ************************
public static void getHomeBitmap(final String urlStr, final int index,
final int width, final int height,
final HomeBitmapCallBack bitmapCallBack) {
final Handler handler = new Handler() {
public void handleMessage(Message message) {
bitmapCallBack.load((Bitmap) message.obj, index);
}
};
if (urlStr != null && !urlStr.equals("")) {
new Thread(new Runnable() {
@Override
public void run() {
Bitmap bitmap;
String name = urlStr.substring(urlStr.lastIndexOf("/") + 1);
String savePaht = mkdirs() + name;
// String localPath = mkdirs()
// + name.substring(0,name.lastIndexOf(".")) + ".png";
bitmap = getLocalImage(savePaht, null, 658, 246);
if (bitmap == null) {
bitmap = createHttpBitmap(urlStr, width, height);
/**
* 保存文件
*/
if (bitmap != null) {
saveFile(bitmap, savePaht);
}
}
if (null != bitmap) {
addBitmapToMemoryCache(urlStr, bitmap);
Message message = handler.obtainMessage(0, bitmap);
message.sendToTarget();
}
}
}).start();
}
}
public static void getBitmap(final String urlStr, final int width,
final int height, final BitmapCallBack bitmapCallBack) {
final Handler handler = new Handler() {
public void handleMessage(Message message) {
bitmapCallBack.load((Bitmap) message.obj);
}
};
// new Thread(new Runnable() {
// @Override
// public void run() {
// Bitmap bitmap = createHttpBitmap(urlStr, width, height);
// if (null != bitmap) {
// addBitmapToMemoryCache(urlStr, bitmap);
// Message message = handler.obtainMessage(0, bitmap);
// message.sendToTarget();
//
// }
// }
// }).start();
if (pool != null && !pool.isShutdown()) {
pool.execute(new Thread(new Runnable() {
@Override
public void run() {
Bitmap bitmap = createHttpBitmap(urlStr, width, height);
if (null != bitmap) {
addBitmapToMemoryCache(urlStr, bitmap);
Message message = handler.obtainMessage(0, bitmap);
message.sendToTarget();
}
}
}));
}
}
@SuppressLint("NewApi")
private static void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemoryCache(key) == null) {
BitmapUtils.mLruCache.put(key, bitmap);
}
}
// 调用Lrucache的get 方法从内存缓存中去图片
@SuppressLint("NewApi")
public static Bitmap getBitmapFromMemoryCache(String key) {
return BitmapUtils.mLruCache.get(key);
}
/**
* Bitmap大小转换
*
* @param options
* @param w
* @param h
* @return
*/
public static BitmapFactory.Options sampleSize(
BitmapFactory.Options options, int w, int h) {
options.inJustDecodeBounds = false;
if (w <= 0 || h <= 0) {
options.inSampleSize = 1;
return options;
}
int initialSize = (int) Math.ceil(Math.sqrt(options.outWidth
* options.outHeight / (w * h)));
initialSize = Math.max(initialSize,
Math.max(options.outWidth / w, options.outHeight / h));
if (initialSize < 1) {
options.inSampleSize = 1;
} else {
options.inSampleSize = initialSize;
}
if (initialSize < 1) {
options.inSampleSize = 1;
} else {
options.inSampleSize = initialSize;
}
return options;
}
public static Bitmap createHttpBitmap(String path, int target_w,
int target_h) {
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap dump = null;
InputStream is = null;
ByteArrayOutputStream baos = null;
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect();
is = conn.getInputStream();
baos = new ByteArrayOutputStream();
byte[] buffer = new byte[512];
int length = -1;
while ((length = is.read(buffer)) != -1) {
if (options.mCancel) {
return dump;
}
baos.write(buffer, 0, length);
}
baos.flush();
byte[] data = baos.toByteArray();
options.inJustDecodeBounds = true;
options.inSampleSize = 1;
dump = BitmapFactory.decodeByteArray(data, 0, data.length, options);
if (options.mCancel || options.outWidth == -1
|| options.outHeight == -1) {
return null;
}
sampleSize(options, target_w, target_h);
dump = BitmapFactory.decodeByteArray(data, 0, data.length, options);
} catch (OutOfMemoryError oor) {
oor.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
closeIO(is);
closeIO(baos);
}
return dump;
}
/**
* 获取本地图片
*
* @param path
* @param options
* @param target_w
* @param target_h
* @return
*/
public static Bitmap getLocalImage(String path,
BitmapFactory.Options options, int target_w, int target_h) {
Bitmap dump = null;
try {
if (options == null) {
options = new BitmapFactory.Options();
}
options.inJustDecodeBounds = true;
options.inSampleSize = 1;
dump = BitmapFactory.decodeFile(path, options);
if (options.mCancel || options.outWidth == -1
|| options.outHeight == -1) {
return null;
}
sampleSize(options, target_w, target_h);
dump = BitmapFactory.decodeFile(path, options);
} catch (OutOfMemoryError oom) {
oom.printStackTrace();
}
return dump;
}
// 保存文件
public static void saveFile(Bitmap bm, String path) {
if (bm == null || TextUtils.isEmpty(path)) {
return;
}
File file = new File(path);
file.deleteOnExit();
FileOutputStream fos = null;
try {
if (file.createNewFile()) {
fos = new FileOutputStream(file);
bm.compress(CompressFormat.PNG, 75, fos);
fos.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
closeIO(fos);
}
}
public static String getAppDir() {
return android.os.Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/yuevod/img";
}
public static String mkdirs() {
String path = getAppDir() + "/";
File cache = new File(path);
if (!cache.exists()) {
cache.mkdirs();
}
return path;
}
public static void closeIO(Closeable io) {
if (io != null) {
try {
io.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//图片倒影
public static Bitmap createReflectedImages(Bitmap bm) {
Matrix sMatrix = new Matrix();
Bitmap miniBitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
bm.getHeight(), sMatrix, true);
int mwidth = miniBitmap.getWidth();
int mheight = miniBitmap.getHeight();
Matrix matrix = new Matrix();
matrix.preScale(1, -1); // 图片矩阵变换(从低部向顶部的倒影)
Bitmap reflectionImage = Bitmap.createBitmap(miniBitmap, 0,
mheight / 2, mwidth, mheight / 2, matrix, false);// 截取原图下半部分
Bitmap bitmapWithReflection = Bitmap.createBitmap(mwidth,
(int) (mheight * 1.2f), Config.ARGB_8888);// 创建倒影图片(高度为原图3/2)
Canvas canvas = new Canvas(bitmapWithReflection); // 绘制倒影图(原图 + 间距 + 倒影)
canvas.drawBitmap(miniBitmap, 0, 0, null); // 绘制原图
Paint paint = new Paint();
canvas.drawRect(0, mheight, mwidth, mheight, paint); // 绘制原图与倒影的间距
canvas.drawBitmap(reflectionImage, 0, mheight, null); // 绘制倒影图
paint = new Paint();
LinearGradient shader = new LinearGradient(0, miniBitmap.getHeight(),
0, bitmapWithReflection.getHeight(), 0x70ffffff, 0x00ffffff,
TileMode.CLAMP);
paint.setShader(shader); // 线性渐变效果
paint.setAntiAlias(true); // 抗锯齿
paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); // 倒影遮罩效果
canvas.drawRect(0, mheight, mwidth, bitmapWithReflection.getHeight(),
paint); // 绘制倒影的阴影效果
return bitmapWithReflection;
}
//图片3d旋转
public static void rotate3dAnimation(ImageView iv){
VodDeaitlPic rotation = new VodDeaitlPic(iv);
rotation.setDuration(1000);
rotation.setRepeatCount(1);
rotation.setFillAfter(true);
iv.startAnimation(rotation);
}
}
5. 使用
position 对应的显示下标,如果只用一个,传入0
BitmapCache.getBitmap("网络图片地址", position, new BitmapCallBack() {
@Override
public void load(Bitmap bm) {
//得到Bitmap
}
});
使用例子:
public class MainActivity extends Activity {
private ImageView img;
private BitmapCache bitmapCache;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img = (ImageView) findViewById(R.id.img);
init();
}
public void init(){
bitmapCache = new BitmapCache();
bitmapCache.getBitmap("http://50.18.192.183:8778/yuanltech/resource/images/www1/20141106/1415295768626.jpg", 0, new BitmapCallBack() {
@Override
public void load(Bitmap bm) {
// TODO Auto-generated method stub
img.setImageBitmap(bm);
}
});
}
}
布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
访问网络权限:
<uses-permission android:name="android.permission.INTERNET"/>
效果图: