Android保存图片到图库,Android扫描文件到媒体库,Android保存图片到SD卡

我们最常常遇到的也就是保存图片到SD卡,然后打开系统的图库可以看得到,可是为什么微信QQ之类的应用可以,我们保存到SD卡就看不到呢?原因就是保存到SD卡后我们还要让系统扫描图片到多媒体库,因为系统的图库读的其实是一个多媒体库的数据库,所以我们保存之后如果没有通知系统扫描的画是看不到的

这里要声明一点,后边的扫描要用到获取文件的Mimetype,不知道怎么获取的人看这里:http://blog.csdn.net/yanzhenjie1003/article/details/44936643

Demo源码连接在文章尾部给出。

首先,保存图片到SD卡,当然方法不止一种,我这里例举一种:

	/**
	 * 保存图片
	 * @author YOLANDA
	 * @param bitmap 图片
	 * @return
	 */
	private String saveImg(Bitmap bitmap){
		File myappDir = new File(Environment.getExternalStorageDirectory(), "yolanda");
		if(myappDir.exists() && myappDir.isFile()) {
			myappDir.delete();
		}
		if (!myappDir.exists()) {
			myappDir.mkdir();
		}
		String fileName = System.currentTimeMillis() + ".png";
		File file = new File(myappDir, fileName);
		if(file.exists()) {
			file.delete();
		}
		try {
			FileOutputStream fos = new FileOutputStream(file);
			bitmap.compress(CompressFormat.PNG, 100, fos);
			fos.flush();
			fos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return file.getAbsolutePath();
	}

那么还有一个问题是,我们怎么保存图片到系统图库呢?为什么要单独说这个问题呢,因为有的手机保存的路径在DCIM/100ANDRo下,有的手机在DCIM/Camera下,所以很难做到兼容,所以我们用到系统的一个方法:
	MediaStore.Images.Media.insertImage(getContentResolver(), file.getAbsolutePath(), fileName, null);
这里做个参数说明,第一个参数不用说了,第二个参数是文件在SD卡的路径,第三个是文件保存的名字,第四个是文件描述,可有可无;

那么现在完成的代码就是:

	/**
	 * 保存图片到SD卡
	 * @author YOLANDA
	 * @param isInsertGallery 是否保存到图库
	 * @return
	 */
	private String saveImg(Bitmap bitmap, boolean isInsertGallery){
		File myappDir = new File(Environment.getExternalStorageDirectory(), "yolanda");
		if(myappDir.exists() && myappDir.isFile()) {
			myappDir.delete();
		}
		if (!myappDir.exists()) {
			myappDir.mkdir();
		}
		String fileName = System.currentTimeMillis() + ".png";
		File file = new File(myappDir, fileName);
		if(file.exists()) {
			file.delete();
		}
		try {
			FileOutputStream fos = new FileOutputStream(file);
			bitmap.compress(CompressFormat.PNG, 100, fos);
			fos.flush();
			fos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		if(isInsertGallery) {
			try {
				MediaStore.Images.Media.insertImage(getContentResolver(), file.getAbsolutePath(), fileName, null);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}
		return file.getAbsolutePath();
	}

这样就可以做到既保存到我们自定义的目录中,又保存在系统图库中了。现在打开图库就直接可以看到图片了。

看似好像解决了我们刚开始说的保存图片到SD打开图库可以看到的问题了,那么有人就问了,QQ和微信人家也不是直接存到图库的啊,人家咋可以保存到自己的目录打开图库就可以看到呢?好,下面我们就来解决这个问题

其实,我们保存图片到SD卡时,要通知系统来扫描,这里分为两种情况:

1、在Androd4.4出来之前,我们都可以发送一个系统广播出去,这个广播既可以扫描一个文件夹:

	
	sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));

又可以扫描一个文件:

		sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + filePath)));

所以在Android4.4之前的的系统中最终的代码是:

	/**
	 * 保存后用广播扫描,Android4.4以下使用这个方法
	 * @author YOLANDA
	 */
	private void saveBroadcast(){
		String filePath = saveImg(true);
		sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + filePath)));
		Toast.makeText(this, "保存成功:" + filePath, Toast.LENGTH_LONG).show();
	}

	/**
	 * 保存图片到SD卡
	 * @author YOLANDA
	 * @param isInsertGallery 是否保存到图库
	 * @return
	 */
	private String saveImg(boolean isInsertGallery){
		File myappDir = new File(Environment.getExternalStorageDirectory(), "yolanda");
		if(myappDir.exists() && myappDir.isFile()) {
			myappDir.delete();
		}
		if (!myappDir.exists()) {
			myappDir.mkdir();
		}
		String fileName = System.currentTimeMillis() + ".png";
		File file = new File(myappDir, fileName);
		if(file.exists()) {
			file.delete();
		}
		try {
			FileOutputStream fos = new FileOutputStream(file);
			bitmap.compress(CompressFormat.PNG, 100, fos);
			fos.flush();
			fos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		if(isInsertGallery) {
			try {
				MediaStore.Images.Media.insertImage(getContentResolver(), file.getAbsolutePath(), fileName, null);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}
		return file.getAbsolutePath();
	}

为什么说是Android4.4之前呢?因为Android4.4开始,Android把系统广播的权限回收了,只有系统应用才可以发送系统广播,那么这还怎么活啊???不要着急,车道山前必有路,还有一个MediaScannerConnection,这个玩意儿可强大了,不仅仅可以搞定图片,只要是媒体文件都可以用他来扫描,不过要知道文件的MimeType,不知道怎么获取文件MimeType的看这里: http://blog.csdn.net/yanzhenjie1003/article/details/44936643

2、在Android4.4和之后用MediaScannerConnection来扫描。

这里讲解一下怎么用MediaScannerConnection来扫描文件,我封装好了一个类出来:

/**
 * 实现MediaScannerConnection.MediaScannerConnectionClient
 * @author YOLANDA
 * @Time 2015年4月8日 上午9:03:54
 */
public class MediaScanner implements MediaScannerConnection.MediaScannerConnectionClient {

	/**
	 * 扫描对象
	 */
	private MediaScannerConnection mediaScanConn = null;

	public MediaScanner(Context context) {
		//实例化
		mediaScanConn = new MediaScannerConnection(context, this);
	}

	/**文件路径集合**/
	private String[] filePaths;
	/**文件MimeType集合**/
	private String[] mimeTypes;

	/**
	 * 扫描文件
	 * @author YOLANDA
	 * @param filepaths
	 * @param mimeTypes
	 */
	public void scanFiles(String[] filePaths, String[] mimeTypes) {
		this.filePaths = filePaths;
		this.mimeTypes = mimeTypes;
		mediaScanConn.connect();//连接扫描服务
	}

	/**
	 * @author YOLANDA
	 */
	@Override
	public void onMediaScannerConnected() {
		for (int i = 0; i < filePaths.length; i++) {
			mediaScanConn.scanFile(filePaths[i], mimeTypes[i]);//服务回调执行扫描
		}
		filePaths = null;
		mimeTypes = null;
	}

	private int scanTimes = 0;

	/**
	 * 扫描一个文件完成
	 * @author YOLANDA
	 * @param path
	 * @param uri
	 */
	@Override
	public void onScanCompleted(String path, Uri uri) {
		scanTimes ++;
		if(scanTimes == filePaths.length) {//如果扫描完了全部文件
			mediaScanConn.disconnect();//断开扫描服务
			scanTimes = 0;//复位计数
		}
	}
}


这个类可以单个文件,也可以扫描多个文件,用法就是直接new一个MediaScannerConnection对象,这个对象需要一个实现了MediaScannerConnection.MediaScannerConnectionClient接口的对象,我们调用的时候步骤是:

1、new一个MediaScannerConnection对象

2、传要扫描的文件路径和文件MimeType进来

3、调用MediaScannerConnection对象的connect()方法,会触发MediaScannerConnection.MediaScannerConnectionClient接口的onMediaScannerConnected方法

4、在MediaScannerConnection.MediaScannerConnectionClient接口的onMediaScannerConnected()方法内调用用MediaScannerConnection.scanFile(String path, String mimeType)来扫描文件

5、扫描结束后会触发MediaScannerConnection.MediaScannerConnectionClient接口的onScanCompleted方法,在这个方法里调用MediaScannerConnection.disconnect()断开连接

所以我们完成的代码是:

public class MainActivity extends Activity implements View.OnClickListener {

	private Bitmap bitmap = null;
	private ImageView imgUserHead;//假如这是用户头像
	private Button btnSaveBoradcase;//保存并广播扫描
	private Button btnSaveScan;//保存并扫描到媒体库

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		imgUserHead = (ImageView) findViewById(R.id.img_userhead);
		btnSaveBoradcase = (Button) findViewById(R.id.btn_broadcast);
		btnSaveScan = (Button) findViewById(R.id.btn_scan);

		bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.scan);
		imgUserHead.setImageBitmap(bitmap);

		btnSaveBoradcase.setOnClickListener(this);
		btnSaveScan.setOnClickListener(this);
	}

	/**
	 * @author YOLANDA
	 * @param v
	 */
	@Override
	public void onClick(View v) {
		if(v == btnSaveBoradcase) {
			saveBroadcast();
		}
		if(v == btnSaveScan) {
			saveScan();
		}
	}

	/**
	 * 保存后用广播扫描,Android4.4以下使用这个方法
	 * @author YOLANDA
	 */
	private void saveBroadcast(){
		String filePath = saveImg(true);
		sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://" + filePath)));
		Toast.makeText(this, "保存成功:" + filePath, Toast.LENGTH_LONG).show();
	}

	/**
	 * 保存后用MediaScanner扫描,通用的方法
	 * @author YOLANDA
	 */
	private void saveScan(){
		String filePath = saveImg(false);
		MediaScanner mediaScanner = new MediaScanner(this);
		String[] filePaths = new String[]{filePath};
		String[] mimeTypes = new String[]{MimeTypeMap.getSingleton().getMimeTypeFromExtension("png")};
		mediaScanner.scanFiles(filePaths, mimeTypes);
		Toast.makeText(this, "保存成功:" + filePath, Toast.LENGTH_LONG).show();
	}


	/**
	 * 保存图片到SD卡
	 * @author YOLANDA
	 * @param isInsertGallery 是否保存到图库
	 * @return
	 */
	private String saveImg(boolean isInsertGallery){
		File myappDir = new File(Environment.getExternalStorageDirectory(), "yolanda");
		if(myappDir.exists() && myappDir.isFile()) {
			myappDir.delete();
		}
		if (!myappDir.exists()) {
			myappDir.mkdir();
		}
		String fileName = System.currentTimeMillis() + ".png";
		File file = new File(myappDir, fileName);
		if(file.exists()) {
			file.delete();
		}
		try {
			FileOutputStream fos = new FileOutputStream(file);
			bitmap.compress(CompressFormat.PNG, 100, fos);
			fos.flush();
			fos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		if(isInsertGallery) {
			try {
				MediaStore.Images.Media.insertImage(getContentResolver(), file.getAbsolutePath(), fileName, null);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
		}
		return file.getAbsolutePath();
	}
	/**
	 * @author YOLANDA
	 */
	@Override
	protected void onDestroy() {
		super.onDestroy();
		if(bitmap != null) {
			bitmap.recycle();
			bitmap = null;
		}
	}
}

Demo源码在: http://download.csdn.net/detail/yanzhenjie1003/8573229

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:C马雯娟 返回首页