我们最常常遇到的也就是保存图片到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(); }
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以下使用这个方法 * @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(); }
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;//复位计数 } } }
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; } } }