前几天接到了这个任务,看起来似乎并不复杂,但实际情况却让我大为头疼,先来简单介绍一下整体流程:
最基础的一步,莫过于调用相机拍摄了,
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
startActivityForResult(cIntent, PIC_REQUEST_CODE_SELECT_CAMERA);
当然也可以不加输出,直接调用,那么会返回一个压缩过的图片
在onActivityResult中填写相应处理,添加调用gallery剪辑图片 和 剪辑后处理的两个分支:
调用galler:
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(Uri.fromFile(mCurrentPhotoFile), "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 80);
intent.putExtra("outputY", 80);
intent.putExtra("return-data", true);
startActivityForResult(intent, PIC_REQUEST_CODE_WITH_DATA);
调用后处理:
略。
看似很简单,模拟器运行也没问题,但真机运行起来总是出错,究其原因,是sdk版本问题
(总是说android 版本向下兼容,今天就碰到问题了)
模拟器用的是2.0,而手机是2.1,查了资料后发现
“2.1系统对 gallery 这个调用进行了修改,uri不让传file:///了,只能传图库中的图片,
比如此类uri:content://media/external/images/media/3
所以需要把FIle的Uri 转化成图库的Uri” (这段是看别人帖子知道的,记不清在哪了)
找到问题就改吧,把Uri.fromFile(mCurrentPhotoFile)改掉,用ContentResolver查一下媒体库总可以了吧
Cursor cursor = cr.query(imgUri, null,MediaStore.Images.Media.DISPLAY_NAME + "='"+mCurrentPhotoFile.getName()+"'", null, null);
if(cursor!=null&& cursor.getCount()>0){
cursor.moveToLast();
id=cursor.getLong(0);
Uri uri = ContentUris.withAppendedId(imgUri,id);//Uri.fromFile(mCurrentPhotoFile);
}
这下总可以了吧,结果还是让我很头疼,
始终查不到新拍的相片,文件已经存了啊,一开始还以为查询写错了
不停的找啊找,改呀改,没有任何进展
纠结了半天后才发现,压根就不是查询的问题,是因为有些手机,
拍照后,相片并不能即时进入媒体库,包括视频和音频
需要刷新才可以,折磨了我两天的问题终于找到根了
那就在查询之前刷新吧
刷新有两种方法:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, dirUri)); //刷新sd卡
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,fileUri)); //刷新单个文件
刷新后再查询,还是有问题,刷新也是要时间的,需要有个异步处理
对于刷新sd卡来说, 我们可以定义一个接收器来处理,单个文件的接收却始终找不到合适的方法
只能写个线程,来扫描数据库,有新增的图片了,再调用gallery
到此,功能是实现了,对于我这个初学者来说,
真是煞费苦心啊,不过也是收获不少,代码也一并奉上,希望与有相同经历的同志共勉:
package lv.test;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
public class Main extends Activity implements OnClickListener {
String TAG = "lvtest";
private Button btn;
private ImageView img;
private Button btn2;
private ImageView img2;
private ImageView img3;
private static final File PHOTO_DIR = new File(Environment.getExternalStorageDirectory()+ "/DCIM/Camera");
private File mCurrentPhotoFile;//
private static MediaActionReceiver actionReceiver;
private static final int SCAN_MEDIA_START = 1;
private static final int SCAN_MEDIA_FINISH = 2;
private static final int SCAN_MEDIA_FILE = 3;
private static final int SCAN_MEDIA_FILE_FINISH_INT = 4;
private static final int SCAN_MEDIA_FILE_FAIL_INT = 5;
ProgressDialog delLoadingDialog = null;
HeadImageGetter imageGet;
private String tag = "lvtest";
private static final String SCAN_MEDIA_FILE_FINISH = "ACTION_MEDIA_SCANNER_SCAN_FILE_FINISH";
private static final String SCAN_MEDIA_FILE_FAIL = "ACTION_MEDIA_SCANNER_SCAN_FILE_FAIL";
private static final int PIC_REQUEST_CODE_WITH_DATA = 1; // 标识获取图片数据
private static final int PIC_REQUEST_CODE_SELECT_CAMERA = 2; // 标识请求照相功能的activity
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn = (Button)this.findViewById(R.id.Button01);
btn.setOnClickListener(this);
img = (ImageView)this.findViewById(R.id.ImageView01);
img.setImageResource(R.drawable.i_happy);
btn2 = (Button)this.findViewById(R.id.Button02);
btn2.setOnClickListener(this);
img2 = (ImageView)this.findViewById(R.id.ImageView02);
img2.setImageResource(R.drawable.i_cry);
img3 = (ImageView)this.findViewById(R.id.ImageView03);
img3.setImageResource(R.drawable.i_cry);
actionReceiver = new MediaActionReceiver();
}
/* (non-Javadoc)
* @see android.app.Activity#onDestroy()
*/
@Override
protected void onDestroy() {
try {
unregisterReceiver(actionReceiver);
} catch (Exception e) {
Log.e(TAG, "actionReceiver not registed");
}
super.onDestroy();
}
/**
* 定义receiver接收其他线程的广播
*
*/
public class MediaActionReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_MEDIA_SCANNER_STARTED.equals(action)) {
mHandler.sendEmptyMessage(SCAN_MEDIA_START);
}
if (Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)) {
mHandler.sendEmptyMessage(SCAN_MEDIA_FINISH);
}
if (Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)) {
mHandler.sendEmptyMessage(SCAN_MEDIA_FILE);
}
}
}
public Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case SCAN_MEDIA_START:
Log.i(TAG, "sccan media started");
delLoadingDialog = onCreateDialogByResId(R.string.loading);
delLoadingDialog.show();
break;
case SCAN_MEDIA_FINISH:
Log.i(TAG, "sccan media finish");
galleryPhoto();
break;
case SCAN_MEDIA_FILE:
Log.i(TAG, "sccan file");
delLoadingDialog = onCreateDialogByResId(R.string.loading);
delLoadingDialog.show();
ScanMediaThread sthread = new ScanMediaThread(Main.this,40,300);
sthread.run();
break;
case SCAN_MEDIA_FILE_FINISH_INT:
Log.i(TAG, "sccan file finish");
galleryPhoto();
break;
case SCAN_MEDIA_FILE_FAIL_INT:
Log.i(TAG, "sccan file fail");
if (delLoadingDialog!=null && delLoadingDialog.isShowing()) {
delLoadingDialog.dismiss();
}
try {
unregisterReceiver(actionReceiver);
} catch (Exception e) {
Log.e(TAG, "actionReceiver not registed");
}
Toast.makeText(Main.this, "no take photo",
Toast.LENGTH_LONG).show();
break;
}
}
};
private void galleryPhoto(){
try {
long id = 0;
Uri imgUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver cr = Main.this.getContentResolver();
Cursor cursor = cr.query(imgUri, null,MediaStore.Images.Media.DISPLAY_NAME + "='"+mCurrentPhotoFile.getName()+"'", null, null);
if(cursor!=null&& cursor.getCount()>0){
cursor.moveToLast();
id=cursor.getLong(0);
/*
* update by lvxuejun on 20110322
* 2.1系统对 gallery 这个调用进行了修改,uri不让传file:///了,只能传图库中的图片,
* 比如此类uri:content://media/external/images/media/3
* 所以需要把FIle的Uri 转化成图库的Uri
*/
Uri uri = ContentUris.withAppendedId(imgUri,id);//Uri.fromFile(mCurrentPhotoFile);
// 启动gallery去剪辑这个照片
final Intent intent = getCropImageIntent(uri);
if (intent!=null) {
startActivityForResult(intent, PIC_REQUEST_CODE_WITH_DATA);
}
}
if (delLoadingDialog!=null && delLoadingDialog.isShowing()) {
delLoadingDialog.dismiss();
}
try {
unregisterReceiver(actionReceiver);
} catch (Exception e) {
Log.e(TAG, "actionReceiver not registed");
}
} catch (Exception ee) {
// TODO Auto-generated catch block
Log.e(TAG, "",ee);
}
}
/**
* 根据资源ID获得ProgressDialog对象
*
* @param resId
* @return
*/
protected ProgressDialog onCreateDialogByResId(int resId) {
ProgressDialog dialog = new ProgressDialog(this);
dialog.setMessage(getResources().getText(resId));
dialog.setIndeterminate(true);
dialog.setCancelable(true);
return dialog;
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.Button01:
try {
PHOTO_DIR.mkdirs();// 创建照片的存储目录
mCurrentPhotoFile = new File(PHOTO_DIR, getPhotoFileName());// 给新照的照片文件命名
final Intent cIntent = getTakePickIntent(mCurrentPhotoFile);
//final Intent cIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null);
startActivityForResult(cIntent, PIC_REQUEST_CODE_SELECT_CAMERA);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, "",
Toast.LENGTH_LONG).show();
}
break;
default:
break;
}
// TODO Auto-generated method stub
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK)
{
switch (requestCode) {
// 调用Gallery返回的
case PIC_REQUEST_CODE_WITH_DATA: {
final Bitmap photo = data.getParcelableExtra("data");
//缓存用户选择的图片
img.setImageBitmap(photo);
break;
}
// 照相机程序返回的,再次调用图片剪辑程序去修剪图片
case PIC_REQUEST_CODE_SELECT_CAMERA: {
try {
Uri fileUri = Uri.fromFile(mCurrentPhotoFile);
Uri dirUri = Uri.parse("file://" + Environment.getExternalStorageDirectory()+ "/DCIM/Camera");
try {
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_STARTED);
intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
intentFilter.addDataScheme("file");
intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
registerReceiver(actionReceiver,intentFilter);
} catch (RuntimeException e) {
}
//sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, dirUri));
sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, fileUri));
} catch (Exception e) {
Log.e(TAG, "Cannot crop image:", e);
}
break;
}
}
}
}
public static Intent getTakePickIntent(File f) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
return intent;
}
/**
* Constructs an intent for image cropping. 调用图片剪辑程序
*/
public static Intent getCropImageIntent(Uri photoUri) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setClassName("com.android.camera", "com.android.camera.CropImage");
//intent.setDataAndType(photoUri, "image/*");
intent.setData(photoUri);
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 80);
intent.putExtra("outputY", 80);
intent.putExtra("return-data", true);
return intent;
}
// 用当前时间给取得的图片命名
private String getPhotoFileName() {
Date date = new Date(System.currentTimeMillis());
SimpleDateFormat dateFormat = new SimpleDateFormat(
"'IMG'_yyyyMMdd_HHmmss");
return dateFormat.format(date) + ".jpg";
}
public class ScanMediaThread extends Thread{
private int scanCount=5;
private int interval=50;
private Context cx = null;
public ScanMediaThread(Context context,int count,int i){
scanCount = count;
interval = i;
cx = context;
this.setName(System.currentTimeMillis() + "_ScanMediaThread");
}
@Override
public void run() {
Log.i(TAG,"scan thread start");
if (this.cx == null)
return;
try {
int j = 0;
long id = 0;
Uri imgUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver cr = Main.this.getContentResolver();
Cursor cursor;
for (j = 0; j < this.scanCount; j++) {
Thread.sleep(this.interval);
cursor = cr.query(imgUri, null,MediaStore.Images.Media.DISPLAY_NAME + "='"+mCurrentPhotoFile.getName()+"'", null, null);
Log.i(TAG,"scan thread "+ j);
if(cursor!=null&& cursor.getCount()>0){
Log.i(TAG,"send finish " + SCAN_MEDIA_FILE_FINISH);
//cx.sendBroadcast(new Intent(SCAN_MEDIA_FILE_FINISH));
mHandler.sendEmptyMessage(SCAN_MEDIA_FILE_FINISH_INT);
break;
}
}
if (j==this.scanCount) {
Log.i(TAG,"send fail ");
//cx.sendBroadcast(new Intent(SCAN_MEDIA_FILE_FAIL));
mHandler.sendEmptyMessage(SCAN_MEDIA_FILE_FAIL_INT);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}