多线程下载图片(使用ExecutorService)

从网络下载图片时,使用多线程同时下载,可以提高下载速度,带来更好的用户体验.

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"/>

效果图:



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个多线程下载图片的 Java 实例代码: ```java import java.io.FileOutputStream; import java.io.InputStream; import java.net.URL; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MultiThreadImageDownloader { public static void main(String[] args) throws Exception { String[] imageUrls = { "https://example.com/image1.jpg", "https://example.com/image2.jpg", "https://example.com/image3.jpg" }; ExecutorService executor = Executors.newFixedThreadPool(imageUrls.length); for (String imageUrl : imageUrls) { executor.execute(new ImageDownloader(imageUrl)); } executor.shutdown(); } private static class ImageDownloader implements Runnable { private String imageUrl; public ImageDownloader(String imageUrl) { this.imageUrl = imageUrl; } @Override public void run() { try { URL url = new URL(imageUrl); InputStream in = url.openStream(); FileOutputStream out = new FileOutputStream(getFileName(imageUrl)); byte[] buffer = new byte[1024]; int length = 0; while ((length = in.read(buffer)) != -1) { out.write(buffer, 0, length); } in.close(); out.close(); System.out.println("Downloaded " + imageUrl); } catch (Exception e) { System.out.println("Error downloading " + imageUrl); } } private String getFileName(String url) { int index = url.lastIndexOf("/"); return "image" + url.substring(index); } } } ``` 该程序会并发下载多张图片,并将每张图片保存到本地文件系统中。该程序使用了 Java 的线程池 ExecutorService 来管理多线程。每个任务都是一个 ImageDownloader 对象,它实现了 Runnable 接口并重写了 run() 方法。在 run() 方法中,程序会从指定的 URL 中读取图片数据,并将数据写入到本地文件中。最后,程序会输出成功下载图片的 URL。 该程序的运行结果如下: ``` Downloaded https://example.com/image1.jpg Downloaded https://example.com/image3.jpg Downloaded https://example.com/image2.jpg ``` 可以看到,三张图片都被成功下载并保存到本地文件系统中。该程序可以根据实际需要进行修改和优化,例如增加异常处理机制、设置超时时间、使用线程池等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值