Android之自定义ContentProvider详解

第一个版本  对android中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类型就是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。

      看完百度百科的解释,相信大家和我一样,仍然不解。结合一个例子,与老师交流之后,我的理解是这样的:

       在ContentProvider的getType(Uri)方法中,可以显示的返回一个MIME类型,该方法返回一个字符串,可以是任意的字符串,当我们显示的返回该MIME类型的时候,相当于通过该方法的验证,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() {

// 创建数据库
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;

switch (mUriMatcher.match(uri)) {

case Shopping.ITEM:

ount = 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;

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;

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;

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)方法进行匹配,根据不同的匹配值来返回不同的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平台可以识别。

sourceurl:http://blog.csdn.net/h3g2010/article/details/6093366


第二个版本

在Android中,每个程序都在自己的进程中运行,互不干扰.这样的好处不说了,但是带来的问题就是想要在程序之间实现数据共享,在没有其它工具的帮助下,就难以实现了.为了解决这个问题,ContentProvider就派上用场了.

一,说说ContentProvider怎么用.


   1,把你想要共享出去的数据用一个URl表示出来.如:content://contacts/people/5(联系人信息中Id位5的联系人记录).或者这样也行:Uri person =ContentUris.withAppendedId(People.CONTENT_URI,5);来封装.

   2,所有的Content Providers都会实现一些共同的接口,可以通过唯一的ContentResolveer来向外提供数据,冰进行一系列的增删改查;ContentResolver cr = getContentResplver();

   3,cr利用定义好的uri(作为参数送给cr封装好的方法里面进行一系列的操作);

至于ContentProvider的实例化,这些不需要我们去做,系统会做这件事.对于ContentProvider,正常情况下,只需一个,但是ContentResolver可以存在多个,在不同进程中的

ContentResolver可以使用同一个ContentProvider.


二,定义自己的ContentProvider

    根据我个人的理解,这作用就有点像J2EE里面的DAO的作用.
    
    1,实现一个定义节本字段的类.示例如下:
          
          
  public class NotePad
{
    //ContentProvider的uri
    public static final String    AUTHORITY    = "com.google.provider.NotePad";

    private NotePad(){}

    // 定义基本字段
    public static final class Notes implements BaseColumns
    {
        private Notes(){}

        public static final Uri        CONTENT_URI            = Uri.parse("content://" + AUTHORITY + "/notes");

        // 新的MIME类型-多个
        public static final String    CONTENT_TYPE        = "vnd.android.cursor.dir/vnd.google.note";

        // 新的MIME类型-单个
        public static final String    CONTENT_ITEM_TYPE    = "vnd.android.cursor.item/vnd.google.note";

        public static final String    DEFAULT_SORT_ORDER    = "modified DESC";

        //字段
        public static final String    TITLE                = "title";
        public static final String    NOTE                = "note";
        public static final String    CREATEDDATE        = "created";
        public static final String    MODIFIEDDATE        = "modified";
    }
}

          
 解释一下MIME类型,假如你要处理的数据类型是新的类型,就得定义一个新的MIME类型,一边ContentProvider.getType(url)来调用;
 粉单个与多个;

 
 2,创建自己的ContentProvider
      
    如果要共享的是数据库,我们在这里可以封装一个SqlLiteOpenHelper,以便建库建表 ,对于 SqlLiteOpenHelper 用过数据库的人应该都懂,在这里就不赘述了;
    
    然后在ContentProvider里面实现增删改查,另外如果有自定义类型的话,还的在ContentProvider刘main实现一个方法    
        
    public String getType(Uri uri)
    {
        switch (sUriMatcher.match(uri))
        {
            case NOTES:
                return Notes.CONTENT_TYPE;

            case NOTE_ID:
                return Notes.CONTENT_ITEM_TYPE;

            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }
 
 实例如下:
 
     public class NotePadProvider extends ContentProvider
{
    private static final String                TAG                    = "NotePadProvider";
    // 数据库名
    private static final String                DATABASE_NAME        = "note_pad.db";
    private static final int                DATABASE_VERSION    = 2;
    // 表名
    private static final String                NOTES_TABLE_NAME    = "notes";
    private static HashMap<String, String>    sNotesProjectionMap;
    private static final int                NOTES                = 1;
    private static final int                NOTE_ID                = 2;
    private static final UriMatcher            sUriMatcher;
    private DatabaseHelper    mOpenHelper;
    //创建表SQL语句
    private static final String                CREATE_TABLE="CREATE TABLE " 
                                                        + NOTES_TABLE_NAME 
                                                        + " (" + Notes._ID 
                                                        + " INTEGER PRIMARY KEY," 
                                                        + Notes.TITLE 
                                                        + " TEXT," 
                                                        + Notes.NOTE 
                                                        + " TEXT,"
                                                        + Notes.CREATEDDATE 
                                                        + " INTEGER," 
                                                        + Notes.MODIFIEDDATE 
                                                        + " INTEGER" + ");";
    
    static
    {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
        sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);

        sNotesProjectionMap = new HashMap<String, String>();
        sNotesProjectionMap.put(Notes._ID, Notes._ID);
        sNotesProjectionMap.put(Notes.TITLE, Notes.TITLE);
        sNotesProjectionMap.put(Notes.NOTE, Notes.NOTE);
        sNotesProjectionMap.put(Notes.CREATEDDATE, Notes.CREATEDDATE);
        sNotesProjectionMap.put(Notes.MODIFIEDDATE, Notes.MODIFIEDDATE);
    }
    private static class DatabaseHelper extends SQLiteOpenHelper
    {
        //构造函数-创建数据库
        DatabaseHelper(Context context)
        {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }
        //创建表
        @Override
        public void onCreate(SQLiteDatabase db)
        {
            db.execSQL(CREATE_TABLE);
        }
        //更新数据库
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
        {
            db.execSQL("DROP TABLE IF EXISTS notes");
            onCreate(db);
        }
    }
    @Override
    public boolean onCreate()
    {
        mOpenHelper = new DatabaseHelper(getContext());
        return true;
    }
    @Override
    //查询操作
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
    {
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        switch (sUriMatcher.match(uri))
        {
            case NOTES:
                qb.setTables(NOTES_TABLE_NAME);
                qb.setProjectionMap(sNotesProjectionMap);
                break;

            case NOTE_ID:
                qb.setTables(NOTES_TABLE_NAME);
                qb.setProjectionMap(sNotesProjectionMap);
                qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1));
                break;

            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
        String orderBy;
        if (TextUtils.isEmpty(sortOrder))
        {
            orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;
        }
        else
        {
            orderBy = sortOrder;
        }
        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
        c.setNotificationUri(getContext().getContentResolver(), uri);
        return c;
    }
    @Override
    // 如果有自定义类型,必须实现该方法
    public String getType(Uri uri)
    {
        switch (sUriMatcher.match(uri))
        {
            case NOTES:
                return Notes.CONTENT_TYPE;

            case NOTE_ID:
                return Notes.CONTENT_ITEM_TYPE;

            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
    }
    @Override
    //插入数据库
    public Uri insert(Uri uri, ContentValues initialValues)
    {
        if (sUriMatcher.match(uri) != NOTES)
        {
            throw new IllegalArgumentException("Unknown URI " + uri);
        }
        ContentValues values;
        if (initialValues != null)
        {
            values = new ContentValues(initialValues);
        }
        else
        {
            values = new ContentValues();
        }
        Long now = Long.valueOf(System.currentTimeMillis());

        if (values.containsKey(NotePad.Notes.CREATEDDATE) == false)
        {
            values.put(NotePad.Notes.CREATEDDATE, now);
        }
        if (values.containsKey(NotePad.Notes.MODIFIEDDATE) == false)
        {
            values.put(NotePad.Notes.MODIFIEDDATE, now);
        }
        if (values.containsKey(NotePad.Notes.TITLE) == false)
        {
            Resources r = Resources.getSystem();
            values.put(NotePad.Notes.TITLE, r.getString(android.R.string.untitled));
        }
        if (values.containsKey(NotePad.Notes.NOTE) == false)
        {
            values.put(NotePad.Notes.NOTE, "");
        }
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values);
        if (rowId > 0)
        {
            Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId);
            getContext().getContentResolver().notifyChange(noteUri, null);
            return noteUri;
        }
        throw new SQLException("Failed to insert row into " + uri);
    }
    @Override
    //删除数据
    public int delete(Uri uri, String where, String[] whereArgs)
    {
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        int count;
        switch (sUriMatcher.match(uri))
        {
            case NOTES:
                count = db.delete(NOTES_TABLE_NAME, where, whereArgs);
                break;

            case NOTE_ID:
                String noteId = uri.getPathSegments().get(1);
                count = db.delete(NOTES_TABLE_NAME, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
                break;

            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }
    @Override
    //更新数据
    public int update(Uri uri, ContentValues values, String where, String[] whereArgs)
    {
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        int count;
        switch (sUriMatcher.match(uri))
        {
            case NOTES:
                count = db.update(NOTES_TABLE_NAME, values, where, whereArgs);
                break;

            case NOTE_ID:
                String noteId = uri.getPathSegments().get(1);
                count = db.update(NOTES_TABLE_NAME, values, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
                break;

            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
        }
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    }
}



这样我们就实现了一个自定义的ContentProvider,档然最后不要忘记一件事情了,在AndroidMinifest.xml中声明我们定义好的ContentProvider

    <provider android:name="NotePadProvider" 
    android:authorities="com.google.provider.NotePad"/>
    
好了,一切OK!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/295919.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

dwr 写的小程序,配置

第一、在web.xml里面有如下配置&#xff1a; <?xml version"1.0" encoding"UTF-8"?><web-app xmlns"http://java.sun.com/xml/ns/j2ee" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"h…

PHP开发学习-Apache+PHP+MySQL环境搭建

我现在开始php的学习之旅啦&#xff01; 入门&#xff1a;开发环境搭建 组件版本&#xff1a; apache2.2.22 下载地址&#xff1a;http://httpd.apache.org/ php5.4.11 下载地址&#xff1a;http://windows.php.net/download/ mysql5.5.29 下载地址&#xff1a;http://www.mys…

如何不露声色地知道别人是不是单身?

1 世界上竟然会有这么香的东西&#xff01;&#xff01;&#xff01;2 全网吧的电脑都死机了&#xff0c;唯独写论文的电脑没死机&#xff01;3 哈哈哈哈哈哈哈哈哈哈哈好拉风啊&#xff01;&#xff01;4 中国好邻居5 《秋游》&#xff0c;五年级男生写的诗图自我们1班王悦微6…

Android 防火墙 知乎,知乎回应:防火墙太“坑爹” 正检查用户隐私是否有泄露...

9月7日消息&#xff0c;知乎今日下午系统瘫痪无法登陆&#xff0c;各个页面变为一片空白&#xff0c;并且还出现了知乎账号“串号”现象&#xff0c;当时有消息称是服务器原因。其后知乎发布公告&#xff0c;声称由第三方防火墙故障引起客户端临时下线&#xff0c;并引起数据展…

再谈C#中的委托和事件

写在最前我相信全网关于委托和事件的文章和概述&#xff0c;大家应该已经读过很多篇。但是就我的观察来看&#xff0c;大多数文在讲述这方面概念时&#xff0c;都会用烧开水和狗叫主人的例子来讲述事件怎么工作&#xff0c;这样比喻固然与生活联系紧密&#xff0c;但看多了难免…

MIT Scheme 使用 Edwin

MIT Scheme 的基本使用&#xff1a;http://www.math.pku.edu.cn/teachers/qiuzy/progtech/scheme/mit_scheme.htm 安装过程 安装brew XQuartz 转载于:https://www.cnblogs.com/IDRI/p/4989171.html

js.domReady

2019独角兽企业重金招聘Python工程师标准>>> var dom [], dom_isReady false, domReady function (a) { if (dom_isReady) a(); else dom.push(a) }, dom_fireReady function () { if (!dom_isReady) { if (!document.body) return setTimeout(dom_fireReady, 1…

mongo-rename操作

重命名集合 > show collectionstianyc_test9> db.runCommand({renameCollection:Gps.tianyc_test9, to:Gps.tianyc_test99}){ "ok" : 1 }> show collectionstianyc_test99 另&#xff1a;通过db.listCommands()&#xff0c;可以查看到所有mongo的命令。转载…

Android之监测database的改变--notifyChange

我们在ContentProvider的insert,update,delete等改变之后调用getContext().getContentResolver().notifyChange(uri, null);这样就通知那些监测databases变化的observer了&#xff0c;而你的observer可以在一个service里面注册。 以Downloadmanger为例子&#xff1a; 定义Cont…

双一流高校出新规:研究生未经导师同意发论文,不得用于毕业、评奖!

全世界只有3.14 % 的人关注了爆炸吧知识本文转自&#xff1a;募格学术近日&#xff0c;吉林大学研究生院发布文件《吉林大学关于加强对研究生在学期间公开发表论文等学术成果管理的通知》&#xff0c;因内容涉及校内研究生论文发表要求&#xff0c;引起很多研究生的注意。其中包…

android http 三次 握手,面试解析:3次握手与4次挥手

在面试中&#xff0c;三次握手和四次挥手可以说是问的最频繁的一个知识点了&#xff0c;我相信大家也都看过很多关于三次握手与四次挥手的文章。今天的这篇文章&#xff0c;重点是围绕着面试&#xff0c;我们应该掌握哪些比较重要的点&#xff0c;哪些是比较多被面试官给问到的…

微服务组件记事本:Skywalking执行效果 · 多图篇

立冬时节知多少今天立冬&#xff0c;周末两天在家继续研究了下Skywalking&#xff0c;感觉这个组件还是很不错的&#xff0c;无论是设计思想还是架构设计&#xff0c;都能从中受到启发和帮助&#xff0c;建议感兴趣的小伙伴可以看看&#xff0c;当然&#xff0c;如果不感兴趣还…

《Starting with Starling》 Ep 1~11

starling 1.3&#xff0c;Hi-ReS-Stats FlashDevelop设置 Project->Properties ->Output->Platform->Flash Player->11.5 ->Classpaths->Add Classpath->(starling和Stats的src文件夹) 程序入口 [SWF(frameRate"60", width"800", …

Android之TextUtils类介绍

对于字符串处理Android为我们提供了一个简单实用的TextUtils类&#xff0c;如果处理比较简单的内容不用去思考正则表达式不妨试试这个在android.text.TextUtils的类&#xff0c;主要的功能如下: 是否为空字符 boolean android.text.TextUtils.isEmpty(CharSequence str) 拼接…

堆和栈的区别 (转贴)

从其他博客复制过来的&#xff0c;因为这个够详细&#xff0c;转过来学习一下&#xff01; 堆和栈的区别一、预备知识—程序的内存分配一个由c/C编译的程序占用的内存分为以下几个部分1、栈区&#xff08;stack&#xff09;— 由编译器自动分配释放 &#xff0c;存放函数的参数…

ios和android交互差异,Android 和 iOS 主要交互区别整理

我简单整理了一下Android 和 iOS 主要的交互区别&#xff0c;如果有遗漏欢迎批评补充。我总结有下面五类区别&#xff1a;一、界面布局形式的差异1 iOS 的 Tab Bar在iOS应用内最多用Tab Bar来切换不同的模块&#xff0c;Tab Bar 也是最受欢迎最容易被用户认知的方式。2 Android…

要比惨吗?看看这个女人

全世界只有3.14 % 的人关注了爆炸吧知识她从不知道辞职是什么滋味&#xff0c;因为被炒的总是她&#xff1b;连续被三家公司炒掉之后&#xff0c;她不得不自己做SOHO。生了双胞胎&#xff0c;本是喜事&#xff1b;但还在月子里&#xff0c;却发现老公出轨。小三还没打走&#x…

【Blog.Core开源】完成升级.NET 6.0

(千呼万唤始出来&#xff0c;_ _ _ _ _ _ _)是不是每个人都已经尝试一遍vs2022和.NET6.0了&#x1f601;&#xff0c;从各个微信群和盆友圈就可见一斑。今天一大早&#xff0c;一位粉丝就发私信&#xff0c;让升级6.0&#xff0c;这么简单的需求&#xff0c;必须满足&#xff0…

Mac 修改用户名

系统偏好设置 > 用户与群组 > 解锁 > 用户 > 右键 > 高级选项 > 全名转载于:https://www.cnblogs.com/SimonGao/p/4989662.html

Android之学习笔记 Contacts (一)ContentResolver query 参数详解

1.获取联系人姓名 一个简单的例子&#xff0c;这个函数获取设备上所有的联系人ID和联系人NAME。 [java] view plaincopy public void fetchAllContacts() { ContentResolver contentResolver this.getContentResolver(); Cursor cursor contentResolver.query(an…