ContentResolver 内容解析者(解析器) 一、Content Provider (内容 提供者 )简介:   (一)、引入:           数据库在Android当中是私有的 ,不能将数据库设为WORLD_READABLE, 每个数据库都只能创建它的包访问 。这意味着 只有创建这个数据库的应用程序才可访问它 。也就是说不能跨越进程和包,直接访问别的应用程序的数据库。那么如何在应用程序间交换数据呢?可以使用ContentProvider(内容提供者)来实现。这样就更加安全可靠(想从我家借东西,你不能直接进来拿,要我拿给你). 为什么要暴露数据呢?系统中的电话簿,短信,媒体库等数据,其他app希望访问.   (二)、ContentProvider的功能和意义:         为了在应用程序之间交换数据,Android提供了 ContentProvider ,它是不同应用程序之间进行数据交换的标准API。 当一个应用程序需要把自己的数据暴露给其他应用程序使用时,该应用程序可以通过提供ContentProvider来实现;         而其他应用程序需要使用这些数据时,不管提供数据的应用程序是否启动,可以通过 ContentResolver 来操作ContentProvider暴露的数据。包括增加数据insert()、删除数据delete()、修改数据update()、查询数据query()等。         虽然大部分使用ContentProvider操作的数据都来自于数据库,但是也可以来自于文件、SharedPreferences、XML或网络等其他存储方式。   (三)、核心类: 1、 ContentProvider 内容提供者 :(需要暴露数据的A应用程序--类似于服务器端) 可以通过继承一个 ContentProvider 抽象类 将自己的数据暴露出去; A应用通过Uri向外暴露数据。只要将A应用安装到手机上。无论是否运行,其他应用都可以从A应用获取数据。 外界不知道,也无需知道A应用暴露的数据在A应用当中是如何存储的,(是用数据库存储还是用文件存储,还是通过网上获得),外界可以通过一套标准的接口 读取或修改A应用里的数据.     2、 ContentResolver  内容解析者 :(访问操作A应用所暴露的数据--类似于客户端) 外界的程序通过 ContentResolver 可以访问 ContentProvider 提供的数据;   3、 Uri统一资源标识符: Uri是ContentResolver和ContentProvider进行数据交换的标识。 例如一个Uri是  content://com.qf.day16_contentprovider_t/user/5 Uri  的标准前缀 (协议protocal) :以“ content:// ”作为前缀,表示该数据由   ContentProvider  管理。 Uri  的 authority 部分(授权,权限):" com.qf.day16_contentprovider_t "该部分是暴露数据的app的包名。(要求小写)。 Uri  的 path 部分(路径):  " user " 用于判断请求的路径(哪些数据被请求)。 被请求的特定记录的 id 值[可选的]: "5" 如果请求不仅限于某个单条数据,该部分及其前面的斜线应该删除。 将一个字符串转换成Uri的方式:   Uri uri = Uri.parse("..............") 【备注:】URI、URL的区别: 首先,URI,是 uniform resource identifier ,统一资源标识符,用来唯一的标识一个资源。 URL是 uniform resource locator ,统一资源定位器, 它是一种具体的URI ,即URL可以用来标识一个资源,而且还指明了如何 定位 这个资源。         也就是说,URI是以一种抽象的,高层次概念定义统一资源标识,而URL则是具体的资源标识的方式。可以认为 URL是一种具体的URI ,它不仅唯一标识资源,而且还提供了定位该资源的信息。URI是一种语义上的抽象概念,可以是绝对的,也可以是相对的, 而URL则必须提供足够的信息来定位,所以,是绝对的。


二、使用 ContentResolver  管理通话记录: 查询手机通话记录,可以利用上下文菜单删除通话记录
整个通话记录列表lv 上下文菜单中的删除项:action_delete 通话记录编号tv_id 对方电话号码tv_number 通话开始时间tv_date 通话类型(呼出/呼入/未接)tv_type 注意需要申请权限,否则运行会出现异常:WRITE_CALL_LOG,READ_CALL_LOG
/**  * ContentProvider内容提供者 1.主要用于不同的应用程序之间,共享数据的。 A:ContentProvider:向外提供数据的  * 用于通过Uri向外暴露数据。只要将应用安装到手机上。无论是否运行,都可以获取数据。 B:ContentResolver:获取并解析数据  * 用于解析通过ContentProvider暴露 出来的数据。 A应用暴露出的是Uri,B应用使用该Uri就可以访问A应用暴露出来的数据了。  * =====================================================  * 本例用于实现通过ContentResovler来获取手机中通话记录  * 通话记录存储在内部存储的系统应用目录中:data/data/com.android.providers.contacts/contacts2.db  * 对外暴露的Uri:"content://call_log/calls"  * step1:通过 getContentResolver ()获取ContentResovler对象  * step2:获取通话记录的Uri:"content://call_log/calls"  * step3:执行查询:ContentResovler对象.query(uri,查询的字段, 条件,条件的参数,排序依据);  * step4:添加权限: READ_CALL_LOG  读取通话记录, WRITE_CALL_LOG  写通话记录 通话记录表的核心字段" _id ",  * " number "电话号码, " date "时间(毫秒值), " type ": 1:呼入 2:呼出 3:未接  */
public class Main3Activity extends AppCompatActivity {    // step2:提供要解析数据对应的Uri,就是电话记录的uri    private Uri uri_callLog = CallLog.Calls.CONTENT_URI;// 系统提供的常量,表示通话记录对外暴露的Uri    // 上面常量的值就是 Uri.parse("content://call_log/calls")得到的结果.    private ContentResolver contentResolver;    private ListView lv_listview;    private MyCursorAdapter adapter;// 自定义的适配器类对象    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main3);        lv_listview = (ListView) findViewById(R.id.lv_listview);        // step1:获取ContentResolver        contentResolver = getContentResolver();        queryCallLog();// 调用自定义的方法,用于查询并显示通话记录        // 注册 上下文菜单:可以删除某个通话记录        registerForContextMenu(lv_listview);    }    @Override    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {        super.onCreateContextMenu(menu, v, menuInfo);        getMenuInflater().inflate(R.menu.call_menu, menu);// 上下文菜单,只有一个"删除"选项    }    // 上下文菜单点击时间处理    @Override    public boolean onContextItemSelected(MenuItem item) {        AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();        int position = menuInfo.position;// 获得弹出上下文菜单时所选中的条目的位置        Cursor cursor = adapter.getCursor();// 调用CursorAdapter的获取cursor对象的方法        cursor.moveToPosition(position);// 把cursor作为数据源,移动到指定位置        int id = cursor.getInt(cursor.getColumnIndex("_id"));// 通话记录表calls中的字段        switch (item.getItemId()) {            case R.id.action_delete:                // 删除一条记录                int count = deleteCallLog(id);// 调用自定义的删除通话记录的方法                if (count > 0) {                    Toast.makeText(Main3Activity.this, "删除成功", Toast.LENGTH_SHORT).show();                } else {                    Toast.makeText(Main3Activity.this, "删除失败", Toast.LENGTH_SHORT).show();                }                break;            default:                break;        }        queryCallLog();// 调用自定义的重新查询的方法        return super.onContextItemSelected(item);    }    /**     * 删除一条指定的通话记录     *     * @param id     * @return     */    public int deleteCallLog(int id) {        int count = contentResolver.delete(uri_callLog, "_id=?", new String[]{id + ""});// 也可以第二个参数传"_id="+id,第三参数传null        return count;    }    /**     * 通过contentResolver,查询uri所指向的通话记录数据     * 第一个参数:要操作的应用暴露出的uri。指向通话记录的数据     * 第二个参数:要查询的字段     * 第三个参数:查询的条件     * 第四个参数:条件的参数值     * 第五个参数:排序     */    // 查询数据    public void queryCallLog() {        // step3:通过contentResolver获取数据        //Uri uri,String[] projection列名数组,String selection查询条件,String[] selectionArgs替换占位符的数组,String sortOrder                Cursor cursor = contentResolver.query(uri_callLog, new String[]{"_id", "number", "date", "type"}, null, null, "date desc");        // SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,        // R.layout.item_listview, cursor, new String[] { "_id", "number",        // "date", "type" }, new int[] { R.id.tv_id,        // R.id.tv_number, R.id.tv_date, R.id.tv_type },        // CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);//这样填进去日期就只能显示成毫秒数了,不美观        // 因此可以使用继承CursorAdapter的自定义适配器来适配Cursor数据        // 父类CursorAdapter没有无参的构造方法,必须如此传参:        adapter = new MyCursorAdapter(this, cursor, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); // 最后一个参数表示,如果数据源发生变化则在后面学习的Loader中可以动态更新.        lv_listview.setAdapter(adapter);    }    // 自定义的继承抽象类CursorAdapter的适配器    class MyCursorAdapter extends CursorAdapter {        // 继承抽象类,重写两个抽象方法        public MyCursorAdapter(Context context, Cursor c, int flags) {            super(context, c, flags);// 父类没有无参的构造方法,必须如此传参        }        @Override        public View newView(Context context, Cursor cursor, ViewGroup parent) {            // 指定布局文件,生成一个条目的View对象,注意,在内部类中,上下文是MainActivity.this            return LayoutInflater.from(Main3Activity.this).inflate(R.layout.item_listview, null);        }        @Override        public void bindView(View view, Context context, Cursor cursor) {            // 填充数据到每个条目的内部组件上,类似于继承BaseAdapter中重写getView()方法            TextView tv_id = (TextView) view.findViewById(R.id.tv_id);            TextView tv_number = (TextView) view.findViewById(R.id.tv_number);            TextView tv_date = (TextView) view.findViewById(R.id.tv_date);            TextView tv_type = (TextView) view.findViewById(R.id.tv_type);            // 从cursor获取数据,显示到textview上            tv_id.setText("" + cursor.getInt(cursor.getColumnIndex("_id")));            tv_number.setText(cursor.getString(cursor.getColumnIndex("number")));            long dateNum = cursor.getLong(cursor.getColumnIndex("date"));// 获取以毫秒表示的date数据            Date date = new Date(dateNum);// 利用毫秒数构建Date对象            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");            tv_date.setText(sdf.format(date));            int typeNum = cursor.getInt(cursor.getColumnIndex("type"));            if (typeNum == 1) {                tv_type.setText("呼入");            } else if (typeNum == 2) {                tv_type.setText("呼出");            } else {                tv_type.setText("未接");            }        }    }}

/**  * 短信息的程序的数据库文件:/data/data/com.android.providers.telephony/mmssms.db  * Uri:content://sms  * step1:获取contentResolver对象  * step2:获取短信息的Uri  * step3:查询,插入  * step4:添加权限: READ_SMS , WRITE_SMS  * @author  Administrator  * 核心字段: _id , address 电话号码, body 信息文本, type 类型(1.接收;2.发送), date 时间(毫秒)  */ 四、使用 ContentResolver  查询 联系人 (一)、 [总结]使用ContentResolver 操作数据的步骤: 1、调用Context的 getContentResolver ()方法获得ContentResolver 对象; 2、调用ContentResolver 的 query() 方法查询数据。 · Cursor  query (Uri  uri , String[]  projection , String where, String[] whereArgs, String sortOrder) 参数解释: String[]    projection :表示select语句中需要查询的所有的字段组成的字符串数组。 String   where:表示带有 占位符 的where子句组成的字符串; String[]   whereArgs:表示 替换 where参数中 占位符 的数据组成的字符串数组; String   sortOrder:表示select语句中的order by子句组成的字符串;   (二)、  联系人中 管理ContentProvider的几个Uri:  1、联系人的Uri==>      content://com.android.contacts/ raw_contacts   2、电话/邮件地址等数据的Uri==>  content://com.android.contacts/ data   数据库位置 :/data/data/com.android.providers.contacts/databases/contacts2.db 用可视化工具打开(例如SQLite Expert) 核心表: 1.raw_contacts原始联系人表 "_id":联系人的id "display_name":联系人的姓名  2.data数据表 "raw_contact_id":作为外键参照raw_contacts表的_id字段 "data1":具体数据,例如手机号,email,姓名等 "mimetype_id":数据的大类型,例如 1:email; 5:电话; 7:姓名; 在mimetypes表中对应于_id字段 3.mimetypes表 "_id":类型id "mimetype":具体类型,例如_id为7的mimetype是 vnd.android.cursor.item/name 1 电子邮件 2 即时通讯 3 昵称 4 组织,单位 5 电话号码 6 邮编 7 名字 8 地址 9 身份证识别号 10 头像 11 组群 /**  * 操作手机的联系人: 应用程序数据所在的位置:/data/data/com.android.providers/contacts/contacts2.db  * step1:获取ContentResolver对象  * step2:提供Uri 1、联系人的Uri==>  * content://com.android.contacts/raw_contacts  * 2、电话/邮件地址等数据的Uri==> content://com.android.contacts/data  * step3:执行查询  * step4: 添加权限 : READ_CONTACTS  *  * @author  Administrator  */
public class MainActivity extends Activity implements OnClickListener {private Uri uri_raw_contact = Uri.parse("content://com.android.contacts/raw_contacts");// raw_contacts表private Uri uri_data = Uri.parse("content://com.android.contacts/data");private ContentResolver contentResolver;private ListView lv_listview;private Button btn_queryData; @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);contentResolver = getContentResolver();initView();// 自定义的获取组件引用和注册监听器的方法queryContacts();// 自定义的查询联系人的方法} public void initView() {lv_listview = (ListView) findViewById(R.id.lv_listview);btn_queryData = (Button) findViewById(R.id.btn_queryData);btn_queryData.setOnClickListener(this);} /** * 获取联系人的信息,并且显示到listview上。 用SimpleAdapter进行适配 */public void queryContacts() {List> list = getDataContacts();// 自定义的方法,获取联系人的信息List// 仅用于展示信息,可以直接使用SimpleAdapterSimpleAdapter adapter = new SimpleAdapter(this, list, R.layout.item_listview,new String[] { "_id", "display_name", "phone", "email" },new int[] { R.id.tv_id, R.id.tv_display_name, R.id.tv_phone, R.id.tv_email });lv_listview.setAdapter(adapter);} // 自定义的用于查询联系人的方法public List> getDataContacts() {List> list = new ArrayList>();//初始化结果集// A:查询raw_contact表,为了得到_id,display_name.Cursor cursor = contentResolver.query(uri_raw_contact, new String[] { "_id", "display_name" }, null, null,null);while (cursor.moveToNext()) {Map map = new HashMap();String _id = cursor.getString(cursor.getColumnIndex("_id"));String display_name = cursor.getString(cursor.getColumnIndex("display_name"));map.put("_id", _id);map.put("display_name", display_name);// B:根据查询到_id,查询data表,获取到data1, mimetype字段:// select data1,mimetype from data where raw_contact_id = _id:Cursor cursor2 = contentResolver.query(uri_data, new String[] { "data1", "mimetype" }, "raw_contact_id=?",new String[] { _id }, null);// 存储的是_id对应的联系人的信息:String email = "";String phone = "";String address = ""; while (cursor2.moveToNext()) {String data = cursor2.getString(cursor2.getColumnIndex("data1"));String mimetype = cursor2.getString(cursor2.getColumnIndex("mimetype"));// 虽然data表没有这个字段,只有mimetype_id字段,但此处必须这样获取,且获取回来的是一个类似于"vnd.android.cursor.item/email_v2"的字符串if ("vnd.android.cursor.item/email_v2".equals(mimetype)) {email = email + "|" + data;// 如果mimetype的值为email,表示此处的data中的数据是电子邮箱} else if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) {// 电话(有可能有手机的,座机的,家庭的,单位的...)phone = phone + "|" + data;} else if ("vnd.android.cursor.item/postal-address_v2".equals(mimetype)) {// 地址address = address + "|" + data;}}map.put("phone", phone);map.put("email", email);map.put("address", address); list.add(map);//把一个联系人的所有信息存入map后,再将map存入list}return list;}// 点击按钮,实现查询功能@Overridepublic void onClick(View v) {queryContacts();//调用自定义的方法}}
一、自定义ContentProvider:   (一)、操作步骤: 1、自己编写一个类,必须继承自 ContentProvider 类; 2、实现ContentProvider类中所有的抽象方法;     需要实现: onCreate () 、 getType()  、 query () 、 insert () 、 update ()、 delete () 等方法。 【备注:】 ContentProvider暴露出来的数据和方法是给其他应用程序来调用。 其他应用程序通过ContentResolver对象调用 query () 、 insert () 、 update ()、 delete () 等。 3、定义ContentProvider的Uri。这个Uri是ContentResolver对象执行CRUD操作时重要的参数; 4、使用UriMatcher对象映射Uri返回代码 ;【超纲】 5、在AndroidMainfest.xml文件中使用标签注册ContentProvider。   (二)、ContentProvider类中的六个抽象方法: 1、boolean  onCreate ()  初始化provider   注意没有ContentResolver试图访问你的Provider之前,它不会创建出来. 2、Uri  insert (Uri uri, ContentValues values)  插入新数据到ContentProvider 3、int  delete (Uri uri, String selection, String[] selectionArgs) 从ContentProvider中删除数据 4、int  update (Uri uri, ContentValues values, String selection, String[] selectionArgs) 更新ContentProvider已经存在的数据 5、Cursor  query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)  返回数据给调用者 6、String  getType (Uri uri)  返回ContentProvider数据的MIME类型 (三)、在清单文件中声明注册ContentProvider: android:authorities ="com.qf.wordscontentprovider"   android:exported ="true"    />   // android:name 属性的值:ContentProvider类的子类的完整路径; // android:authorities 属性的值:对应于content:URI中的authority部分。 // android:exported 属性是否允许其他应用调用。如果是false,则该ContentProvider不允许其他应用调用。   【备注:】         ContentProvider是 单例模式 的,当多个应用程序通过使用ContentResolver 来操作使用ContentProvider 提供的数据时,ContentResolver 调用的数据操作会委托给同一个ContentProvider 来处理。这样就能保证数据的一致性。 数据库工具类DBHelper.java import  android.content.Context; import  android.database.sqlite.SQLiteDatabase; import  android.database.sqlite.SQLiteOpenHelper; public   class  DBHelper extends   SQLiteOpenHelper {   public  DBHelper(Context context , int   versionCode ){ super ( context , "users.db" , null , versionCode ); } @Override public   void  onCreate(SQLiteDatabase db ) { // TODO  初始化创建表 db . execSQL ( "create table t_user(_id integer primary key ,uname,upass,money)" ); db . execSQL ( "create table t_order(_id integer primary key ,product_name,price,user_id)" ); //对于 sqlite 来说,只要是integer的主键,则是自动增长的,无需用 autoincrement 指定 db . execSQL ( "insert into t_user(uname,upass,money) values('disen','123',1000)" ); db . execSQL ( "insert into t_user(uname,upass,money) values('jack','234',10000)" ); }   @Override public   void  onUpgrade(SQLiteDatabase db , int   oldVersion , int   newVersion ) { // TODO   升级数据库(删除旧表,创建新表) if ( newVersion > oldVersion ){ db .execSQL( "drop table if exists t_user" ); db .execSQL( "drop table if exists t_order" ); onCreate( db ); } }   } 在AndroidManifest.xml中的标签中:    < provider   android:name = "com.user.contentprovider.UserContentProvider"     android:authorities = "com.user.contentprovider.users"     android:exported = "true" />   UserContentProvider.java   public   class   UserContentProvider   extends  ContentProvider {   // 声明当前ContentProvider组件的唯一标识(Authority),注:必须使用小写字母 private   static   final  String AUTHORITY  = "com. user .contentprovider.users" ;   // 声明访问当前应用下的数据库中哪些资源,给这些访问资源声明code标识 private   static   final   int   CODE_USER  = 0; private   static   final   int   CODE_ORDER  = 6;   // 声明完整的资源访问 Uri 的匹配器--UriMatcher,实例化它并增加资源访问的 Uri private   static  UriMatcher uriMatcher ; static  { uriMatcher  = new  UriMatcher(UriMatcher. NO_MATCH ); // 值是-1 //UriMatcher. addURI (String authority, String path, int code) // 用Resolver访问时的 Uri // content://com.qf.contentprovider.users/users uriMatcher .addURI( AUTHORITY , "users" , CODE_USER );   // content://com.qf.contentprovider.users/orders uriMatcher .addURI( AUTHORITY , "orders" , CODE_ORDER ); //假设是订单表 }   /**  * 自定义的数据库工具类  */ private  DBHelper dbHelper ;   @Override public   boolean  onCreate() { // TODO  初始化ConentProvider组件,实例化数据库操作工具类 dbHelper  = new  DBHelper( getContext (), 1);//第二个参数是版本号 return   true ; // 成功返回true }   @Override public  Cursor query(Uri uri , String[] projection , String selection , String[] selectionArgs , String sortOrder ) { // TODO  查询数据表 SQLiteDatabase db  = dbHelper .getReadableDatabase(); // 先以读写方式打开数据库,一旦磁盘空间满了, // 会继续尝试以只读方式打开数据库。 Cursor cursor  = null ; // 查询的结果 // 通过 Uri 匹配器,判断当前请求的 Uri 是访问哪一资源的code switch  ( uriMatcher .match( uri )) { case   CODE_USER : // 查询t_users用户表的数据: cursor  = db .query( "t_user" , projection , selection , selectionArgs , null , null , sortOrder ); break ; //case CODE_ORDER:..... } return   cursor ; }   @Override public  Uri insert(Uri uri , ContentValues values ) { // TODO  向数据表中插入数据 SQLiteDatabase db  = dbHelper .getReadableDatabase(); // 先以读写方式打开数据库,一旦磁盘空间满了, // 会继续尝试以只读方式打开数据库。 if  ( uriMatcher .match( uri ) == CODE_USER ) {//如果是插入t_user表 long   id  = db .insert( "t_user" , null , values ); db .close(); return   ContentUris. withAppendedId ( uri , id ); // 将给定的id追加到路径末尾返回 } //else if().... return   null ; }   @Override public   int  delete(Uri uri , String selection , String[] selectionArgs ) { // TODO  删除数据表中数据 SQLiteDatabase db  = dbHelper .getReadableDatabase(); if  ( uriMatcher .match( uri ) == CODE_USER ) { int   cnt  = db .delete( "t_user" , selection , selectionArgs ); db .close(); return   cnt ;//返回收到影响的行数 } return  0; }   @Override public   int  update(Uri uri , ContentValues values , String selection , String[] selectionArgs ) { // TODO  更新数据表中的数据 SQLiteDatabase db  = dbHelper .getReadableDatabase(); if  ( uriMatcher .match( uri ) == CODE_USER ) { int   cnt  = db .update( "t_user" , values , selection , selectionArgs ); db .close(); return   cnt ;//返回收到影响的行数 } return  0; } @Override public  String getType(Uri uri ) { // TODO  Auto-generated method stub return   null ; } } 在另外一个app中利用ContentResolver来使用自定义的ContentProvider暴露出来的数据:
public class MainActivity extends Activity{         private TextView tv_info;         private ContentResolver resolver;         private Uri uri = Uri.parse("content://com.user.contentprovider.users/users");      @Override      protected void onCreate(Bundle savedInstanceState) {          // TODO Auto-generated method stub           super.onCreate(savedInstanceState);           setContentView(R.layout.layout_main);            tv_info = (TextView)findViewById(R.id.tv_info);           resolver = getContentResolver();      }        public void click(View v){             switch (v.getId()) {             case R.id.bt_query:              //建表时的语句:create table t_user(_id integer primary key,uname,upass,money)              query();//调用自定义的查询所有数据的方法              break;            case R.id.bt_insert:              insert();//调用自定义的插入数据的方法              break;            case R.id.bt_update:            //请自行实现             break;          default:            break;        }     }     private void insert() {       //调用自定义的插入数据的方法(硬编码)        ContentValues values = new ContentValues();          values.put("uname", "zhang");        values.put("upass", "321");          values.put("money", "99");        Uri nUri = resolver.insert(uri, values);//sqlite会自动指定主键id       long newId = ContentUris.parseId(nUri);//获取新插入的id      Toast.makeText(this, ""+newId, 0).show();   }   private void query() {    //自定义的查询所有数据的方法     Cursor c = resolver.query(uri , new String[]{"_id","uname","upass","money"}, null, null,null);    String text = "";    while(c.moveToNext()){          text +=c.getString(0)+","+c.getString(1)+","+c.getString(2)+","+c.getString(3)+"\n";    }     tv_info.setText(text);   }}





更多相关文章

  1. 2020版本Android 开发者学习路线(热门技术+学习方法+书籍+必须知
  2. Android中有几种数据存储方式,每种方式有哪些特点?
  3. Ubuntu Linux下android源码下载方法
  4. ANDROID STRINGS.XML的特殊字符_安卓STRING.XML添加空格或字符的

随机推荐

  1. CentOS下MySQL主从复制,读写分离
  2. 关于mysql无法添加中文数据的问题以及解
  3. MySQL学习笔记_时间,多表更新,数据库元数据
  4. 如何在MYSQL中选择下面的项目和上面的项
  5. web项目异常A web application registere
  6. centos设置mysql root密码
  7. MySQLWorkbench 创建E-R图步骤
  8. 按多列排序行选择
  9. mysql中插入中文时显示乱码
  10. org.hibernate.hql.internal.ast.QuerySy