我正在为我的应用开发自定义内容提供商。这是我使用Android应用程序的课程的一部分,所以请不要期望做到这一切的理由太过分了;-)这里的重点是让我了解CP。< / p>
我有一个previous post which goes on and on with this,但我想我已经设法简化了我的问题。所以,我正在使用#34; gallery应用程序&#34;。由于我不知道手机上存储 thumbnail 图像的方式和位置,我决定只使用MediaStore.Images.Thumbnails来访问拇指,并在我的手机中显示它们网格视图。
然而,为了满足所述课程的要求,我将写一个&#34; PhotoProvider&#34;在DetailActivity中加载单张照片,全屏。此外,为了使这一点有意义,而不仅仅是MediaStore.Media.Images的包装器,我使用JPEG文件中的一些EXIF标签扩展该数据。
找到了great post here on StackOverflow,并继续纠缠课堂上提供的源代码,我提出了以下课程。也许你想看看,帮助我(指出我正确的方向)?
我支持的URI context://AUTH/photo/#
,用于从缩略图中获取特定图片(给定IMAGE_ID
)。此外,为了使它更有趣,我还希望能够将数据写入EXIF标记UserComment
:context://AUTH/photo/#/comment/*
(注释String是那里的最后一个参数)。那看起来合情合理吗?
有些问题:(已更新)
getType()
令人困惑。同样,这是从应用课程借出的。返回图片时,我想类型应始终为image/jpeg
(或者PNG)?编辑:了解更多内容,我现在明白从
insert()
方法返回的URI是可选的,但是返回&#34;链接通常很有用#34; (即URI)到新的(插入的)数据!对于我的情况,在更新EXIF标记后,我可以向已修改的照片返回null
或URI:context://AUTH/photo/7271
(其中7271模仿PHOTO_ID
)。
以下是我的(未完成的!)代码。请查看,尤其是query()
和insert()
函数: - )
package com.example.android.galleri.app.data;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.net.Uri;
import android.provider.BaseColumns;
import android.provider.MediaStore;
public class PhotoContract {
public static final String CONTENT_AUTHORITY = "no.myapp.android.galleri.app";
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
public static final String PATH_PHOTO = "photo";
public static final String PATH_COMMENT = "comment";
public static final class PhotoEntry {
public static final Uri CONTENT_URI =
BASE_CONTENT_URI.buildUpon().appendPath(PATH_PHOTO).build();
public static final String COLUMN_DISPLAY_NAME = MediaStore.Images.Media.DISPLAY_NAME;
public static final String COLUMN_DATA = MediaStore.Images.Media.DATA;
public static final String COLUMN_DESC = MediaStore.Images.Media.DESCRIPTION;
public static final String COLUMN_DATE_TAKEN = MediaStore.Images.Media.DATE_TAKEN;
public static final String COLUMN_DATE_ADDED = MediaStore.Images.Media.DATE_ADDED;
public static final String COLUMN_TITLE = MediaStore.Images.Media.TITLE;
public static final String COLUMN_SIZE = MediaStore.Images.Media.SIZE;
public static final String COLUMN_ORIENTATION = MediaStore.Images.Media.ORIENTATION;
public static final String COLUMN_EXIF_COMMENT = "UserComment";
public static final String COLUMN_EXIF_AUTHOR = "Author";
// should these simply be image/png??
public static final String CONTENT_TYPE =
ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_PHOTO;
public static final String CONTENT_ITEM_TYPE =
ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_PHOTO;
// makes an URI to a specific image_id
public static final Uri buildPhotoWithId(Long photo_id) {
return CONTENT_URI.buildUpon().appendPath(Long.toString(photo_id)).build();
}
// since we will "redirect" the URI towards MediaStore, we need to be able to extract IMAGE_ID
public static Long getImageIdFromUri(Uri uri) {
return Long.parseLong(uri.getPathSegments().get(1)); // TODO: is it position 1??
}
// get comment to set in EXIF tag
public static String getCommentFromUri(Uri uri) {
return uri.getPathSegments().get(2); // TODO: is it position 2??
}
}
}
package com.example.android.galleri.app.data;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.ExifInterface;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.v4.content.CursorLoader;
import android.util.Log;
import java.io.IOException;
public class PhotoProvider extends ContentProvider {
// The URI Matcher used by this content provider.
private static final UriMatcher sUriMatcher = buildUriMatcher();
static final int PHOTO = 100;
static final int PHOTO_SET_COMMENT = 200;
static UriMatcher buildUriMatcher() {
// 1) The code passed into the constructor represents the code to return for the root
// URI. It's common to use NO_MATCH as the code for this case. Add the constructor below.
final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
final String authority = PhotoContract.CONTENT_AUTHORITY;
// 2) Use the addURI function to match each of the types. Use the constants from
// WeatherContract to help define the types to the UriMatcher.
// matches photo/<any number> meaning any photo ID
matcher.addURI(authority, PhotoContract.PATH_PHOTO + "/#", PHOTO);
// matches photo/<photo id>/comment/<any comment>
matcher.addURI(authority, PhotoContract.PATH_PHOTO + "/#/" + PhotoContract.PATH_COMMENT + "/*", PHOTO_SET_COMMENT);
// 3) Return the new matcher!
return matcher;
}
@Override
public String getType(Uri uri) {
// Use the Uri Matcher to determine what kind of URI this is.
final int match = sUriMatcher.match(uri);
switch (match) {
case PHOTO_SET_COMMENT:
return PhotoContract.PhotoEntry.CONTENT_TYPE;
case PHOTO:
return PhotoContract.PhotoEntry.CONTENT_TYPE;
default:
throw new UnsupportedOperationException("Unknown uri: " + uri);
}
}
@Override
public boolean onCreate() {
return true; // enough?
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
MatrixCursor retCursor = new MatrixCursor(projection);
// open the specified image through the MediaStore to get base columns
// then open image file through ExifInterface to get detail columns
Long IMAGE_ID = PhotoContract.PhotoEntry.getImageIdFromUri(uri);
//Uri baseUri = Uri.parse("content://media/external/images/media");
Uri baseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
baseUri = Uri.withAppendedPath(baseUri, ""+ IMAGE_ID);
String[] MS_projection = {
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATA,
MediaStore.Images.Media.DESCRIPTION,
MediaStore.Images.Media.DATE_TAKEN,
MediaStore.Images.Media.DATE_ADDED,
MediaStore.Images.Media.TITLE,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.ORIENTATION};
// http://androidsnippets.com/get-file-path-of-gallery-image
Cursor c = getContext().getContentResolver().query(baseUri, MS_projection, null, null, null);
// dump fields (the ones we want -- assuming for now we want ALL fields, in SAME ORDER) into MatrixCursor
Object[] row = new Object[projection.length];
row[0] = c.getString(0); // DISPLAY_NAME
row[1] = c.getBlob(1); // etc
row[2] = c.getString(2);
row[3] = c.getLong(3);
row[4] = c.getLong(4);
row[5] = c.getString(5);
row[6] = c.getInt(6);
row[7] = c.getInt(7);
// NB! Extra +2 fields, for EXIF data.
try {
ExifInterface exif = new ExifInterface((String)row[1]);
row[8] = exif.getAttribute("UserComment");
row[9] = exif.getAttribute("Author");
} catch (IOException e) {
e.printStackTrace();
}
retCursor.addRow(row);
return retCursor;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
String comment_to_set = PhotoContract.PhotoEntry.getCommentFromUri(uri);
Long IMAGE_ID = PhotoContract.PhotoEntry.getImageIdFromUri(uri);
Uri baseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
baseUri = Uri.withAppendedPath(baseUri, ""+ IMAGE_ID);
// get DATA (path/filename) from MediaStore -- only need that specific piece of information
String[] MS_projection = {MediaStore.Images.Media.DATA};
// http://androidsnippets.com/get-file-path-of-gallery-image
Cursor c = getContext().getContentResolver().query(baseUri, MS_projection, null, null, null);
String thumbData = c.getString(0);
try {
ExifInterface exif = new ExifInterface(thumbData);
exif.setAttribute("UserComment", comment_to_set);
exif.saveAttributes();
} catch (IOException e) {
e.printStackTrace();
}
return PhotoContract.PhotoEntry.buildPhotoWithId(IMAGE_ID); // return URI to this specific image
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
}
答案 0 :(得分:0)
我相信我设法解决了这个问题,毕竟它并不是那么神秘。编写自定义内容,在这种情况下,提供程序真正归结为实现我自己的query
和update
方法。我不需要任何insert
或delete
,因为我只是正在阅读 MediaStore。
首先,我设计了两个URI;一个用于查询,一个用于更新。查询URI遵循模式content://AUTH/photo/#
,其中#是MediaStore.Images.Thumbnails中的IMAGE_ID。该方法基本上针对MediaStore.Images.Media运行另一个查询,以获得&#34;标准&#34;关于特定图像的数据,然后通过ExifInterface
在图像上获得一些额外的元数据。所有这些都以MatrixCursor
返回。
更新URI与模式content://AUTH/photo/#/comment
匹配,然后设置(写入)具有该ID的文件中的UserComment
EXIF标记 - 再次通过{{ 1}}。
要回答我的问题,我将从我的PhotoContract和PhotoProvider课程发布更新的代码。基本上,如果您正在编写一个内容提供程序,它不接口SQLite数据库 - 而是设备上的其他内容 - 您需要做的就是在适当的方法中实现这些操作你的提供者类。
ExifInterface
import android.content.ContentResolver;
import android.content.ContentUris;
import android.net.Uri;
import android.provider.BaseColumns;
import android.provider.MediaStore;
public class PhotoContract {
public static final String CONTENT_AUTHORITY = "com.example.android.myFunkyApp.app";
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
public static final String PATH_PHOTO = "photo";
public static final String PATH_COMMENT = "comment";
//public static final String PATH_AUTHOR = "author";
public static final class ThumbEntry {
public static final String COLUMN_THUMB_ID = MediaStore.Images.Thumbnails._ID;
public static final String COLUMN_DATA = MediaStore.Images.Thumbnails.DATA;
public static final String COLUMN_IMAGE_ID = MediaStore.Images.Thumbnails.IMAGE_ID;
}
public static final class PhotoEntry {
public static final Uri CONTENT_URI =
BASE_CONTENT_URI.buildUpon().appendPath(PATH_PHOTO).build();
public static final String COLUMN_IMAGE_ID = MediaStore.Images.Media._ID;
public static final String COLUMN_DISPLAY_NAME = MediaStore.Images.Media.DISPLAY_NAME;
public static final String COLUMN_DATA = MediaStore.Images.Media.DATA;
public static final String COLUMN_DESC = MediaStore.Images.Media.DESCRIPTION;
public static final String COLUMN_DATE_TAKEN = MediaStore.Images.Media.DATE_TAKEN;
public static final String COLUMN_DATE_ADDED = MediaStore.Images.Media.DATE_ADDED;
public static final String COLUMN_TITLE = MediaStore.Images.Media.TITLE;
public static final String COLUMN_SIZE = MediaStore.Images.Media.SIZE;
public static final String COLUMN_ORIENTATION = MediaStore.Images.Media.ORIENTATION;
public static final String COLUMN_EXIF_COMMENT = "UserComment";
//public static final String COLUMN_EXIF_AUTHOR = "Author";
public static final String CONTENT_TYPE =
ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_PHOTO;
public static final String CONTENT_ITEM_TYPE =
ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_PHOTO;
// makes an URI to a specific image_id
public static final Uri buildPhotoUriWithId(Long photo_id) {
return CONTENT_URI.buildUpon().appendPath(Long.toString(photo_id)).build();
}
// since we will "redirect" the URI towards MediaStore, we need to be able to extract IMAGE_ID
public static Long getImageIdFromUri(Uri uri) {
return Long.parseLong(uri.getPathSegments().get(1)); // always in position 1
}
}
}