Android提供Content Provider来实现应用程序之间的数据共享,provider提供了标准的接口用于存储和检索多种类型的数据。图像 、音频和视频的标准content provider就是MediaStore。

1)获取图像的URI

要获得标准的图像存储路径,我们需要获得MediaStore的引用,而这是通过content resolver来实现的(因为使用Content resolver可以获取content provider,而MediaStore就是一个content provider)。

传递指定的URI给content resolver,可以得到对应的content provider,由于是新增一张图像,所以使用insert方法,相应的URI是android.provider.MediaStore.Images.Media类定义的常量EXTERNAL_CONTENT_URI。这个常量说明我们要将图像存储到主外部存储器中,通常就是SD卡;如果要将图像存储到设备内存中,则使用INTERNAL_CONTENT_URI。当然对于媒体文件的存储而言,由于尺寸一般都比较大,因此会优先考虑使用EXTERNAL_CONTENT_URI。

Content resolver类的insert函数返回值是URI类型:

Uri imageFileUri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, new ContentValues());// Start the Camera AppIntent it = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);it.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageFileUri);startActivityForResult(it, CAMERA_RESULT);

上面代码中的ContentValues对象是捕获的图像在创建时要关联的元数据,当然,上面的元数据是空的。我们可以使用put函数将元数据信息写入ContentValues中,ContentValues是以键值对的形式存储数据的,键名是定义在android.provider.MediaStore.Images.Media类中的常量:

// Save the name and description of an image in a ContentValues mapContentValues contentValues = new ContentValues(3);contentValues.put(Media.DISPLAY_NAME, "ASCE1885_TITLE");contentValues.put(Media.DESCRIPTION, "ASCE1885_DESCRIPTION");contentValues.put(Media.MIME_TYPE, "image/jpeg");// Add a new recode without the bitmap, but with some values set.// insert() returns the URI of the new recordUri imageFileUri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, contentValues);


上面获取的Uri可能类似于:

content://media/external/images/media/16

这里说明一点,以content开头的Uri一般都是被content provider使用的,例如上面的Uri是被MediaStore使用的一样。

反过来根据Uri,我们可以用来检索这个Uri对应路径中的图像数据,代码如下:

Bitmap bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageFileUri),null,bmpFactory);

在我们捕获图像并存放在MediaStore中后,如果还想再增加元数据信息,那么可以使用ContentResolver的update函数来实现:

// Update the MediaStore record with Title and DescriptionContentValues contentValues = new ContentValues(3);contentValues.put(Media.DISPLAY_NAME, "WEN1885_TITLE");contentValues.put(Media.DESCRIPTION, "WEN1885_DESCRIPTION");getContentResolver().update(imageFileUri, contentValues, null, null);

完整的代码例子如下,先看layout/main.xml文件:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    ><ImageViewandroid:id="@+id/ReturnedImageView"      android:layout_width="wrap_content"     android:layout_height="wrap_content"/><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Title:"android:id="@+id/TitleTextView" /><EditText android:layout_width="fill_parent"android:layout_height="wrap_content"android:id="@+id/TitleEditText"/><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Description"android:id="@+id/DescriptionTextView"/><EditText android:layout_width="fill_parent"android:layout_height="wrap_content"android:id="@+id/DescriptionEditText"/><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/TakePictureButton"android:text="Take Picture"/><Button android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/SaveDataButton"android:text="Save Data"/></LinearLayout>


完整的Java代码如下:

package hust.iprai.asce1885.promedia;import java.io.FileNotFoundException;import android.app.Activity;import android.content.ContentValues;import android.content.Intent;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.net.Uri;import android.os.Bundle;import android.provider.MediaStore.Images.Media;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.EditText;import android.widget.ImageView;import android.widget.TextView;import android.widget.Toast;public class MediaStoreCameraActivity extends Activity {final static int CAMERA_RESULT = 0;Uri imageFileUri = null;// User interface elements, specified in res/layout/main.xmlImageView returnedImageView;Button takePictureButton;Button saveDataButton;TextView titleTextView;TextView descriptionTextView;EditText titleEditText;EditText descriptionEditText;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// Set the content view to be what is defined in the res/layout/main.xml filesetContentView(R.layout.main);// Get references to UI elementsreturnedImageView = (ImageView) findViewById(R.id.ReturnedImageView);takePictureButton = (Button) findViewById(R.id.TakePictureButton);saveDataButton = (Button) findViewById(R.id.SaveDataButton);titleTextView = (TextView) findViewById(R.id.TitleTextView);descriptionTextView = (TextView) findViewById(R.id.DescriptionTextView);titleEditText = (EditText) findViewById(R.id.TitleEditText);descriptionEditText = (EditText) findViewById(R.id.DescriptionEditText);// Set all except takePictureButton to not be visible initially// View.GONE is invisible and doesn't take up space in the layoutreturnedImageView.setVisibility(View.GONE);saveDataButton.setVisibility(View.GONE);titleTextView.setVisibility(View.GONE);descriptionTextView.setVisibility(View.GONE);titleEditText.setVisibility(View.GONE);descriptionEditText.setVisibility(View.GONE);// When the Take Picture Button is clickedtakePictureButton.setOnClickListener(new OnClickListener() {public void onClick(View v) {// Add a new record without the bitmap// return the URI of the new recordimageFileUri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, new ContentValues());// Start the Camera AppIntent it = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);it.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageFileUri);startActivityForResult(it, CAMERA_RESULT);}});saveDataButton.setOnClickListener(new OnClickListener() {public void onClick(View v) {// Update the MediaStore record with Title and DescriptionContentValues contentValues = new ContentValues(3);contentValues.put(Media.DISPLAY_NAME, titleEditText.getText().toString());contentValues.put(Media.DESCRIPTION, descriptionEditText.getText().toString());getContentResolver().update(imageFileUri, contentValues, null, null);// Tell the userToast bread = Toast.makeText(MediaStoreCameraActivity.this, "Record Updated", Toast.LENGTH_LONG);bread.show();// Go back to the initial state, set Take Picture Button Visible// hide other UI elementstakePictureButton.setVisibility(View.VISIBLE);returnedImageView.setVisibility(View.GONE);titleTextView.setVisibility(View.GONE);descriptionTextView.setVisibility(View.GONE);titleEditText.setVisibility(View.GONE);descriptionEditText.setVisibility(View.GONE);}});}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {super.onActivityResult(requestCode, resultCode, data);if (RESULT_OK == resultCode) {// The Camera App has returned// Hide the Take Picture ButtontakePictureButton.setVisibility(View.GONE);// Show the other UI elementssaveDataButton.setVisibility(View.VISIBLE);returnedImageView.setVisibility(View.VISIBLE);titleTextView.setVisibility(View.VISIBLE);descriptionTextView.setVisibility(View.VISIBLE);titleEditText.setVisibility(View.VISIBLE);descriptionEditText.setVisibility(View.VISIBLE);// Scale the imageint dw = 200; // Make it at most 200 pixels wideint dh = 200; // Make it at most 200 pixels tallBitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();bmpFactoryOptions.inJustDecodeBounds = true;Bitmap bmp = null;try {bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageFileUri), null, bmpFactoryOptions);} catch (FileNotFoundException e) {e.printStackTrace();}int heightRatio = (int) Math.ceil(bmpFactoryOptions.outHeight/(float)dh);int widthRatio = (int) Math.ceil(bmpFactoryOptions.outWidth/(float)dw);Log.v("HEIGHTRATIO", "" + heightRatio);Log.v("WIDTHRATIO", "" + widthRatio);// If both of the ratios are greater than 1// one of the sides of the image is greater than the screenif ((heightRatio > 1) && (widthRatio > 1)) {if (heightRatio > widthRatio) {// Height ratio is larger, scale according to itbmpFactoryOptions.inSampleSize = heightRatio;} else {// Width ratio is larger, scale according to itbmpFactoryOptions.inSampleSize = widthRatio;}}// Decode it for realbmpFactoryOptions.inJustDecodeBounds = false;try {bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageFileUri), null, bmpFactoryOptions);} catch (FileNotFoundException e) {e.printStackTrace();Log.v("ERROR", e.toString());}// Display itreturnedImageView.setImageBitmap(bmp);}}}


2)使用MediaStore来检索图像数据

MediaStore,跟所有的content provider一样使用类似于数据库操作的方式来检索数据。从指定的Uri中选择数据记录,之后通过Cursor对象来对结果进行迭代处理。

首先需要创建一个字符串数组来表示希望返回的列类型,MediaStore中图像数据的标准列类型在MediaStore.Images.Media类中:

String[] columns =     {Media.DATA, Media._ID, Media.TITLE, Media.DISPLAY_NAME};


执行实际的查询操作使用Activity的managedQuery函数,第一个参数是URI,第二个参数是列名组成的字符串数组,第三个参数是WHERE语句,后面跟的参数是WHERE包含的参数,最后一个参数是ORDER BY语句:

long oneHourAgo = System.currentTimeMillis()/1000 - (60*60);String[] whereValues = {"" + oneHourAgo};// 指定返回结果的列String[] columns = {Media.DATA, Media._ID, Media.TITLE, Media.DISPLAY_NAME, Media.DATE_ADDED};// 获得游标Cursor cursor = managedQuery(Media.EXTERNAL_CONTENT_URI, columns, Media.DATE_ADDED + " > ?",whereValues, Media.DATE_ADDED + " ASC");// 返回指定列的索引int displayColumnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);// 移到游标的开始处if (cursor.moveToFirst()) {String displayName = cursor.getString(displayColumnIndex);}


完整的例子如下所示,先是layout/main.xml文件:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    ><ImageButton android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/ImageButton"/><TextView android:layout_width="fill_parent"android:layout_height="wrap_content"android:id="@+id/TitleTextView"android:text="Image Title"/></LinearLayout>


Java代码如下:

package hust.iprai.asce1885.promedia;import android.app.Activity;import android.database.Cursor;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.os.Bundle;import android.provider.MediaStore;import android.provider.MediaStore.Images.Media;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.ImageButton;import android.widget.TextView;public class MediaStoreGallery extends Activity {public final static int DISPLAYWIDTH = 200;public final static int DISPLAYHEIGHT = 200;TextView titleTextView;ImageButton imageButton;Cursor cursor;Bitmap bmp;String imageFilePath;int fileColumn;int titleColumn;int displayColumn;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);titleTextView = (TextView) findViewById(R.id.TitleTextView);imageButton = (ImageButton) findViewById(R.id.ImageButton);String[] columns = {Media.DATA, Media._ID, Media.TITLE, Media.DISPLAY_NAME};cursor = managedQuery(Media.EXTERNAL_CONTENT_URI, columns, null, null, null);// 注意:Media.DATA是MediaStore.Images.Media.DATA的缩写fileColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);titleColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.TITLE);displayColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME);if (cursor.moveToFirst()) {titleTextView.setText(cursor.getString(titleColumn));imageFilePath = cursor.getString(fileColumn);bmp = getBitmap(imageFilePath);// Display itimageButton.setImageBitmap(bmp);}imageButton.setOnClickListener(new OnClickListener() {public void onClick(View v) {if (cursor.moveToNext()) {titleTextView.setText(cursor.getString(displayColumn));imageFilePath = cursor.getString(fileColumn);bmp = getBitmap(imageFilePath);imageButton.setImageBitmap(bmp);}}});}private Bitmap getBitmap(String imageFilePath) {// Load up the image's dimensions not the image itselfBitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();bmpFactoryOptions.inJustDecodeBounds = true;Bitmap bmp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);int heightRatio = (int) Math.ceil(bmpFactoryOptions.outHeight/(float)DISPLAYHEIGHT);int widthRatio = (int) Math.ceil(bmpFactoryOptions.outWidth/(float)DISPLAYWIDTH);Log.v("HEIGHTRATIO", "" + heightRatio);Log.v("WIDTHRATIO", "" + widthRatio);// If both of the ratios are greater than 1, one of the sides of // the image is greater than the screenif ((heightRatio > 1) && (widthRatio > 1)) {if (heightRatio > widthRatio) {bmpFactoryOptions.inSampleSize = heightRatio;} else {bmpFactoryOptions.inSampleSize = widthRatio;}}// Decode it for realbmpFactoryOptions.inJustDecodeBounds = false;bmp = BitmapFactory.decodeFile(imageFilePath, bmpFactoryOptions);return bmp;}}


2)内部元数据

EXIF,可交换图像文件格式(Exchangeable Image File Format),是将元数据保存到图像文件里的标准格式。它的数据存储与JPEG格式是完全相同的,它就是在JPEG格式头部插入了数码照片的拍摄信息。

EXIF数据中包含很多与图像拍摄紧密相关的技术参数,例如曝光时间ExposureTime和快门速度ShutterSpeedValue等。还有一些参数是我们可以在后续进行填充或修改的,例如:

UserComment: 用户评论

ImageDescription:图像的描述

Artist:图像的创建者或者拍摄者

Copyright:版权

Software:创建图像使用的软件

Android提供了方便的接口ExifInterface来读写EXIF数据:

ExifInterface ei = new ExifInterface(imageFilePath);String imageDescription = ei.getAttribute("ImageDescription");if (null != imageDescription) {Log.v("EXIF", imageDescription);}


保存EXIF数据到图像文件中的代码片段如下:

ExifInterface ei = new ExifInterface(imageFilePath);ei.setAttribute("ImageDescription", "ASCE1885");



更多相关文章

  1. java反射机制 调用android得隐藏api
  2. 谷歌官方Android应用架构库——ViewModel
  3. Android中使用SQLiteOpenHelper管理SD卡中的数据库
  4. 如何在Android(安卓)Quick Search Box中添加自己的app,按照我的意
  5. 保持长宽比 对背景图像进行修改android:scaleType="fitXY"
  6. Android(安卓)SQLite数据库操作
  7. Android(安卓)Databinding数据绑定框架
  8. Android(安卓)Transition 页面过度动画
  9. android学习日记13--数据存储之ContentProvide

随机推荐

  1. Android(安卓)Develop Challenge
  2. Android开发EditText属性
  3. [转]android 基础知识
  4. Unity Android打包持续集成一次出多个APK
  5. cocos2d-x&android返回键&菜单键
  6. Android(安卓)Activity的各种重载方法
  7. 坑爹的Android新ADT
  8. androidの实现分享功能
  9. Android常见问题(一点一点总结未完成)
  10. android中MotionEvent.ACTION_CANCEL事件