`
decentway
  • 浏览: 157333 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

数据集的MIME类型字符串

阅读更多

 初始MIME类型,是在学习ContentProvider的时候。
       当在创建自己的ContentProvider的时,需要从抽象类ContentProvider中派生出自己的子类,并实现其中5个抽象方法:

query(Uri, String[], String, String[], String) which returns data to the caller

insert(Uri, ContentValues) which inserts new data into the content provider

update(Uri, ContentValues, String, String[]) which updates existing data in the content provider

delete(Uri, String, String[]) which deletes data from the content provider

getType(Uri) which returns the MIME type of data in the content provider


       至于前四个方法,不是本文想要讨论的重点,就不做冗余的阐述了;有意思的是这个方法getType(Uri),根据帮助文档的解释,它返回一个MIME类型。
       首先,先百度了一下MIME类型,根据百度百科的解释:MIME:全称Multipurpose Internet Mail Extensions,多功能Internet 邮件扩充服务。它是一种多用途网际邮件扩充协议,在1992年最早应用于电子邮件系统,但后来也应用到浏览器MIME类型就是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
    看完百度百科的解释,相信大家和我一样,仍然不解。结合一个例子和跟老师的交流,我的理解是这样的:
       在ContentProvidergetType(Uri)方法中,可以显示的返回一个MIME类型,该方法返回一个字符串,可以是任意的字符串,当我们显示的返回一个MIME类型的时候,相当于通过该方法的验证,Provider可以识别Provider中其他方法返回的Cursor的内容,不需要在进行更多的验证;如果返回其他的字符串(android能够识别的MIME类型,例如直接返回当前的包名),则Provider在执行其他方法后,返回Cursor类型的时候,需要进行验证。
    还是云里雾里的?下面来看一个使用了MIME类型的自定义ContentProvider的例子:
import android.net.Uri;
public class Shopping {
// 定义数据库的名字
public static final String DATABASE_NAME = "shopping_db";
// 定义数据库的版本
public static final int DATABASE_VERSION = 1;
// 表的名字
public static final String TABLE_NAME = "t_shopping";
// 定义数据库的字段
public static final String FIELD_ID = "_id";
public static final String FIELE_NAME = "product_name";
// 定义访问的类型
public static final int ITEM = 1;
public static final int ITEM_ID = 2;
// 定义MIME类型,访问单个记录
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.com.stone.shopping";
// 访问数据集
public static final String CONTENT_ITEM = "vnd.android.cursor.dir/vnd.stone.shopping";
// 定义访问ContentProvider权限
public static final String AUTHORITY = "com.stone.shopping";
// 定义URI
public static final Uri URI = Uri.parse("content://" + AUTHORITY + "/item");
}

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase.CursorFactory;

public class MyDbHelper extends SQLiteOpenHelper {
public MyDbHelper(Context context, String name, CursorFactory factory,
    int version) {
   super(context, name, factory, version);
}

@Override
public void onCreate(SQLiteDatabase db) {
   String sql = "CREATE TABLE " + Shopping.TABLE_NAME + " ( "
     + Shopping.FIELD_ID + " INTEGER primary key autoincrement, "
     + " " + Shopping.FIELE_NAME + " TEXT)";
   db.execSQL(sql);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
   String sql = "DROP TABLE IF EXISTS " + Shopping.TABLE_NAME;
   db.execSQL(sql);
   onCreate(db);
}
}


import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.text.TextUtils;

public class MyProvider extends ContentProvider {
private MyDbHelper myDbHelper;
private static final UriMatcher mUriMatcher; // 进行匹配的Uri的设定
static {
   mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
   mUriMatcher.addURI(Shopping.AUTHORITY, "item", Shopping.ITEM);
   mUriMatcher.addURI(Shopping.AUTHORITY, "item/#", Shopping.ITEM_ID);
}

@Override
public boolean onCreate() {
   System.out.println("onCreate");

   // 创建数据库
   myDbHelper = new MyDbHelper(getContext(), Shopping.DATABASE_NAME, null,
     Shopping.DATABASE_VERSION);
   return true;
}

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
   SQLiteDatabase db = myDbHelper.getWritableDatabase();
   int count = 0;
   System.out.println("delete");

   switch (mUriMatcher.match(uri)) {
   case Shopping.ITEM:
    count = db.delete(Shopping.TABLE_NAME, selection, selectionArgs);
    break;
   case Shopping.ITEM_ID:

    // 通过Uri获取Id,根据主键进行删除
    String id = uri.getPathSegments().get(1);
    System.out.println(String.valueOf(uri.getPathSegments().size()));

    count = db.delete(Shopping.TABLE_NAME,
      Shopping.FIELD_ID + "=" + id, selectionArgs);
    break;
   default:
    throw new IllegalArgumentException();
   }

   // 通知数据发生改变
   getContext().getContentResolver().notifyChange(uri, null);
   return count;
}

@Override
public Uri insert(Uri uri, ContentValues values) {
   SQLiteDatabase db = myDbHelper.getWritableDatabase();
   long row = 0;
   System.out.println("insert");

   if (mUriMatcher.match(uri) != Shopping.ITEM) {
    throw new IllegalArgumentException();
   }

   row = db.insert(Shopping.TABLE_NAME, Shopping.FIELD_ID, values);
   if (row > 0) {
    Uri noteUri = ContentUris.withAppendedId(Shopping.URI, row);
    getContext().getContentResolver().notifyChange(uri, null);
    return noteUri;
   }
   return null;
}

@Override
public Cursor query(Uri uri, String[] projection, String selection,
    String[] selectionArgs, String sortOrder) {
   SQLiteDatabase db = myDbHelper.getReadableDatabase();
   Cursor cursor = null;
   System.out.println("query");

   switch (mUriMatcher.match(uri)) {
   case Shopping.ITEM:
    cursor = db.query(Shopping.TABLE_NAME, projection, selection,
      selectionArgs, null, null, sortOrder);
    break;
   case Shopping.ITEM_ID:
    String id = uri.getPathSegments().get(1);
    cursor = db.query(Shopping.TABLE_NAME, projection,
      Shopping.FIELD_ID
        + "="
        + id
        + (!TextUtils.isEmpty(selection) ? " AND ("
          + selection + ')' : ""), selectionArgs,
      null, null, sortOrder);
    break;
   default:
    throw new IllegalArgumentException();
   }
  
   cursor.setNotificationUri(getContext().getContentResolver(), uri);
   return cursor;
}

@Override
public int update(Uri uri, ContentValues values, String selection,
    String[] selectionArgs) {
   SQLiteDatabase db = myDbHelper.getWritableDatabase();
   int count = 0;
   System.out.println("update");
  
   switch (mUriMatcher.match(uri)) {
   case Shopping.ITEM:
    count = db.update(Shopping.TABLE_NAME, values, selection,
      selectionArgs);
    break;
   case Shopping.ITEM_ID:
    String id = uri.getPathSegments().get(1);
    count = db.update(Shopping.TABLE_NAME, values, Shopping.FIELD_ID
      + "="
      + id
      + (!TextUtils.isEmpty(selection) ? " AND (" + selection
        + ')' : ""), selectionArgs);
    break;
   default:
    throw new IllegalArgumentException();
   }
   getContext().getContentResolver().notifyChange(uri, null);
   return count;
}

@Override
public String getType(Uri uri) {

   // 进行Uri匹配完成不同的处理工作
   switch (mUriMatcher.match(uri)) {
   case Shopping.ITEM:
   return Shopping.CONTENT_ITEM;
   case Shopping.ITEM_ID:
    return Shopping.CONTENT_ITEM_TYPE;
   default:
    throw new IllegalArgumentException();
   }
}

}

     在上面的例子中,首先有一个Shopping类,定义了一系列的常量。包括访问的数据库的相关信息和URI的定义,其中最重要的就是下面的两句,MIME类型的定义:

public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.stone.shopping";
public static final String CONTENT_ITEM = "vnd.android.cursor.dir/vnd.stone.shopping";

    其次是一个MyDbHelper类,继承自SQLiteOpenHelper类,用于一些数据库相关操作,这里就不赘述了。
    最后的MyProvider类使我们的重头戏,首先我们来看这一段代码:
private static final UriMatcher mUriMatcher; // 进行匹配的Uri的设定
static {
   mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
   mUriMatcher.addURI(Shopping.AUTHORITY, "item", Shopping.ITEM);
   mUriMatcher.addURI(Shopping.AUTHORITY, "item/#", Shopping.ITEM_ID);
}

    UriMatcher表示一个Uri的匹配器,它会对我们请求的Uri进行匹配,而匹配的格式就是这里我们通过addURI()方法添加格式。
    接下来,首先执行的就是getType(Uri)方法,下面来看该方法体中的代码:
switch (mUriMatcher.match(uri)) {
   case Shopping.ITEM:
    return Shopping.CONTENT_ITEM;
   case Shopping.ITEM_ID:
    return Shopping.CONTENT_ITEM_TYPE;
   default:
    throw new IllegalArgumentException();
   }

    当请求过来的Uri通过mUriMatcher.match(uri)方法进行匹配,根据不同的匹配值(Shopping.CONTENT_ITEM 或者 Shopping.CONTENT_ITEM_TYPE)来返回不同的MIME类型。
    下面我们来结合query(Uri, String[], String, String[], String) 这个方法来解释一下:
        在这个方法中,返回的是一个Cursor游标对象。而Cursor中是单条的记录还是一个集合,需要和在getType()方法中返回的类型保持一致。当返回的MIME类型是Shopping.CONTENT_ITEM时,Cursor应该是一个集合;当返回的MIME类型是Shopping.CONTENT_ITEM_TYPE时,Cursor应该是单条记录。
    由于在getType()方法里面,我们显示的返回了android平台可以识别的MIME类型,所以在执行query方法返回Cursor对象的时候,系统将不需要再进行验证,从而可以说是节省了系统开销。
       话已至此,那么何谓android平台可以识别的MIME类型呢?下面来分析一下MIME类型的结构:
       其实,MIME类型其实就是一个字符串,中间有一个 “/” 来隔开,“/”前面的部分是系统识别的部分,就相当于我们定义一个变量时的变量数据类型,通过这个“数据类型”,系统能够知道我们所要表示的是个什么东西。至于 “/” 后面的部分就是我们自已来随便定义的“变量名”了。
       那么,既然MIME类型就是一个字符串,那么我们的getType( )自然也可以随便返回一个系统不能识别的字符串啦?没错,有些时候我们确实也这样处理,比如说可以这样写:
     public String getType(Uri uri) {
      return getContext().getPackageName(); 
    }

    这里,我们把当前上下文的包名返回了。这样处理的结果是怎样的呢?
    简单的说,系统不能够识别它了,也就不会做任何处理。仍然以query方法来说,当执行完方法体(这里需要注意一下:在这种情况下,即使我们没有通过返回MIME类型字符串来进行验证处理,但是在query方法中再次对Uri进行了匹配并根据不同的Uri类型进行了不同的操作)返回Cursor对象的时候,这时候系统不能肯定返回的Cursor对象是否合法,因此需要对其进行验证,这样对系统资源算是一个浪费了吧。所以,我们最好还是显示的返回一个MIME类型吧,当然要写正确了,让我们android平台可以识别。

分享到:
评论

相关推荐

    Python Cookbook

    1.3 测试一个对象是否是类字符串 8 1.4 字符串对齐 10 1.5 去除字符串两端的空格 11 1.6 合并字符串 11 1.7 将字符串逐字符或逐词反转 14 1.8 检查字符串中是否包含某字符集合中的字符 15 1.9 简化字符串的...

    用Delphi2010 实现邮件附件收发功能

    ContentType:指定MIME媒体数据类型,描述正文中包含的数据,使用户代理决定如何显示数据,常用的有text/html,text/xml。 TIdSMTP组件简介 TIdSMTP是TIdMessageClient派生出的一个简单邮件传输协议和SMTP客户端...

    C#基类库大全下载--苏飞版

    这里面实现了很多的帮助方法,比如正则验证,加密,解密,MD5加密,字符串的处理等操作。 2.最新的 PageValidate 类 主要是实现了验证,是否为空,是否为数字等。 3.JavascriptHelp 帮助输出简单的JS代码 4.最新...

    C#基类库(苏飞版)

    6.从字符串里随机得到,规定个数的字符串. 复制代码 22.条形码 BarCodeToHTML 本类是个条码生成类,大家可根据需要自己设置,非常好用 23.图片 ImageClass 主要功能有:缩略图片,图片水印,文字水印,调整光暗...

    精通javascript

    • 2.11.htm 字符串型转换为逻辑型数据 • 2.12.htm toLowerCase()方法 • 2.13.htm 通过字符串调用toLowerCase()方法 • 2.14.htm 使用值的数据操作 • 2.15.htm 对数据的...

    java-servlet-api.doc

    RFC2046多用途Internet邮件扩展(多用途网际邮件扩充协议(MIME))第二部分:媒体类型 RFC2047多用途网际邮件扩充协议(MIME)(多用途Internet邮件扩展)第三部分:信息标题扩展用于非ASCII文本 RFC2048多用途Internet邮件...

    HTML开发王

    3.5.5 文本字符串 3.5.6 使用uri 3.5.7 使用颜色 3.5.8 使用长度 3.5.9 内容类型(mime类型) 3.5.10 语言代码 3.5.11 字符编码 3.5.12 单字符 3.5.13 日期和时间 3.5.14 链接类型 3.5.15 介质描述符 3.5.16 脚本数据 ...

    精通JavaScript

    • 2.11.htm 字符串型转换为逻辑型数据 • 2.12.htm toLowerCase()方法 • 2.13.htm 通过字符串调用toLowerCase()方法 • 2.14.htm 使用值的数据操作 • 2.15.htm 对数据的...

    rfc中文文档目录,包含部分翻译

    RFC1558_LDAP研究过滤器的字符串表达 RFC1571_Telnet环境选项互用性问题 RFC1590_媒体类型注册过程 RFC1591_域名系统的结构和授权 RFC1597_私有Internet的地址分配 RFC1605_SONET to Sonnet翻译 RFC1606_用IP版本9的...

    中文版RFC,共456

    RFC1558 LDAP研究过滤器的字符串表达 RFC1571 Telnet环境选项互用性问题 RFC1590 媒体类型注册过程 RFC1591 域名系统的结构和授权 RFC1597 私有Internet的地址分配 RFC1605 SONET to Sonnet翻译 RFC1606 用IP版本9的...

    RFC中文文档-txt

    RFC1558 LDAP研究过滤器的字符串表达 RFC1571 Telnet环境选项互用性问题 RFC1590 媒体类型注册过程 RFC1591 域名系统的结构和授权 RFC1597 私有Internet的地址分配 RFC1605 SONET to Sonnet翻译 RFC1606 用IP版本9的...

    ZendFramework中文文档

    2.3.1. 保存 ACL 数据确保持久性 2.3.2. 使用声明(Assert)来编写条件性的 ACL 规则 3. Zend_Auth 3.1. 简介 3.1.1. 适配器 3.1.2. 结果 3.1.3. 身份的持久(Persistence) 3.1.3.1. 在PHP Session 中的缺省...

    asp.net知识库

    .NET 2.0中的字符串比较 小试ASP.NET 2.0的兼容性 为 asp.net 2.0 的菜单控件增加 target 属性 ASP.NET 2.0 的内部变化 常见的 ASP.NET 2.0 转换问题和解决方案 Asp.Net2.0无刷新客户端回调 体验.net 2.0 的优雅(1...

Global site tag (gtag.js) - Google Analytics