介绍
这篇文章主要讲了如何通过选择图片或者拍照的方式获取图片并上传到服务器上,上传图片用到了nohttp
框架,其他网络框架下略有不同,不再赘述。以下代码基于Android Studio。
获取图片
要想上传图片,首先要获取图片的路径,获取的方法主要分为选择已经存在的图片和通过各种照相机应用保存一张图片。
通过选取图片的方式
选择图片比较简单,请参考以下代码,首先是创建Intent
Intent getIntent = new Intent(Intent.ACTION_GET_CONTENT);
getIntent.setType("image/*");
Intent chooserIntent = Intent.createChooser(getIntent, getString(R.string.pickImage));
startActivityForResult(chooserIntent, RequestCode.PICK_PHOTO.getValue());
也可以使用以下代码直接打开图库应用
Intent pickIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(pickIntent, RequestCode.PICK_PHOTO.getValue());
获取选区的图片
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (RequestCode.valueOf(requestCode)) {
case PICK_PHOTO:
if (resultCode == Activity.RESULT_OK && data != null && data.getData() != null) {
fullSizeImageUri = data.getData();
File imageFile = new File(fullSizeImageUri.getPath());
uploadFile(imageFile);
}
break;
}
}
通过照相的方式
通过照相机应用获取图片稍微麻烦一点,首先需要创建Provider
并声明读取外部存储的权限,在AndroidManifest.xml
中写入以下代码
<manifest>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.domain.appname.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
...
</application>
</manifest>
注意将com.domain.appname
替换为对应的包名。
在res
目录下创建xml文件夹,然后在xml目录下创建file_paths.xml文件,并写入以下内容
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="images"
path="Android/data/com.domain.appname/files/Pictures"/>
</paths>
接下来就是创建Intent
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = createImageFile("photo");
//保存这个图片的绝对地址,在onActivityResult中使用
mCurrentImagePath = photoFile.getAbsolutePath();
} catch (IOException ex) {
// Error occurred while creating the File
Log.e(TAG,"Fail to create image file,error is "+ex.getMessage());
}
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(getContext(),
"com.domain.appname.fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
//如果不加入以下代码,4.X的机器会崩溃(未严格测试)
List<ResolveInfo> resolveInfoList = getContext().getPackageManager().queryIntentActivities(takePictureIntent, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : resolveInfoList) {
String packageName = resolveInfo.activityInfo.packageName;
getContext().grantUriPermission(packageName, photoURI, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
startActivityForResult(takePictureIntent, RequestCode.TAKE_PHOTO.getValue());
}
}
else{
Toast.makeText(getContext(),R.string.deviceNotSupportCamera,Toast.LENGTH_SHORT).show();
}
以下为createImageFile
函数的代码,创建一个文件供相机应用写入
private File createImageFile(String prefix) throws IOException {
File storageDir = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
return File.createTempFile(
prefix,
".jpg",
storageDir
);
}
获取图片
相机应用会把图片存到指定的位置,然后在onActivityResult
中使用mCurrentImagePath
获取图片文件
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (RequestCode.valueOf(requestCode)) {
case PICK_PHOTO:
//因为相机应用不会返回数据,所以data=null
if (resultCode == Activity.RESULT_OK) {
File imageFile = new File(mCurrentImagePath);
uploadFile(imageFile);
}
break;
}
}
上传图片
以下为uploadFile
函数的代码,使用nohttp框架上传图片文件
private void uploadFile(File imageFile) {
Request<String> request = new StringRequest(Constant.API_USER_PROFILE_UPLOAD,RequestMethod.POST);
BasicBinary binary = new FileBinary(imageFile);
binary.setUploadListener(UPLOAD_IMAGE, mUploadListener);
request.add("load_img", binary);
addRequest(request);
}
private OnUploadListener mUploadListener = new OnUploadListener() {
@Override
public void onStart(int what) {
mProgressDialog.setMessage(getString(R.string.uploadStart));
mProgressDialog.show();
}
@Override
public void onCancel(int what) {
mProgressDialog.setMessage(getString(R.string.uploadCanceled));
mProgressDialog.hide();
}
@Override
public void onProgress(int what, int progress) {// 这个文件的上传进度发生边耍
mProgressDialog.setProgress(progress);
}
@Override
public void onFinish(int what) {
mProgressDialog.setMessage(getString(R.string.uploadFinish));
mProgressDialog.hide();
}
@Override
public void onError(int what, Exception exception) {
mProgressDialog.setMessage(String.format(getString(R.string.uploadError),exception.getMessage()));
mProgressDialog.hide();
}
};
剪切图片
通过Android-Image-Cropper剪切图片,具体使用方法请参考该项目的github主页
private void cropImage(Uri imageUri, Uri outputUri) {
CropImage.activity(imageUri)
.setOutputUri(outputUri)
.setFixAspectRatio(true)
.setAspectRatio(1, 1)
.setMaxCropResultSize(1000, 1000)
.setGuidelines(CropImageView.Guidelines.ON)
.start(getActivity(), this);
}
获取指定大小的Bitmap
如果直接使用完整尺寸的照片显示在屏幕上,图片稍微多一点就会发生内存泄漏事件,最好的办法是根据ImageView的大小获取缩小版Bitmap,代码如下
private void setImage(ImageView imageView, String imagePath) {
// Get the dimensions of the View
int targetW = imageView.getWidth();
int targetH = imageView.getHeight();
// Get the dimensions of the bitmap
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imagePath, bmOptions);
int photoW = bmOptions.outWidth;
int photoH = bmOptions.outHeight;
// Determine how much to scale down the image
int scaleFactor = Math.min(photoW / targetW, photoH / targetH);
// Decode the image file into a Bitmap sized to fill the View
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = scaleFactor;
bmOptions.inPurgeable = true;
Bitmap bitmap = BitmapFactory.decodeFile(imagePath, bmOptions);
imageView.setImageBitmap(bitmap);
}
将照片加入图库
通过你的应用拍摄的照片是不会自动加入到图库中的,需要使用以下代码调用系统媒体扫描器,将图片加入到媒体提供数据库(Media Provider’s database)
private void galleryAddImage(String imagePath) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File imageFile = new File(imagePath);
Uri contentUri = Uri.fromFile(imageFile);
mediaScanIntent.setData(contentUri);
getActivity().sendBroadcast(mediaScanIntent);
}