学习笔记(五)SQLite与ContentProvider

前端之家收集整理的这篇文章主要介绍了学习笔记(五)SQLite与ContentProvider前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

sqlite

sqlite是Android系统内置的轻量级关系数据库,它具有运算速度快,占用资源少等优点,通常只需要几百K的内存就足够了,因此特别适合在移动设备上使用。sqlite不仅支持标准的sql语法,还遵循数据库的ACID事务,所以用过关系型数据库的同学很容易上手sqlite;

创建数据库

android为方便我们管理数据库,专门提供了sqliteOpenHelper类,借助这个类可以非常简单的对数据库进行创建和升级;但是这个类是抽象类,我们需要自己创建一个新的类去继承它,我们需要重写onCreate()和onUpdate()方法;其次,还有两个非常重要的实例方法
- getWritableDatabase();
- getReadableDatabase();
这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则创建一个新的数据库),并返回一个可以数据库进行读写的操作对象。不同的是,当数据库不可写入的时候(如磁盘空间已满)getReadableDatabase()返回的对象将以只读的方式打开数据库
sqliteOpenHelper有两个构造方法可供重写,一般使用参数较少的构造方法

public sqliteOpenHelper(Context context,String name,CursorFactory factory,int version)
@H_301_21@
  • context:就是上下文的意思,有它才能对数据库进行操作。
  • name:创建数据库使用的名称
  • factory:允许我们在查询数据的时候返回一个自定义的Cursor,一般传入null。
  • version:当前数据库的版本号,可对数据库进行升级操作。
  • eg:我们新建一个项目创建一个名为test_database.db数据库
    DataBasehelper类继承sqliteOpenHelper;

    public class DataBasehelper extends sqliteOpenHelper {
        private static final String CREATE_DB_ONR="create table users ("
                +"id integer primary key autoincrement,"
                +"username text,"
                +"password text"
                +")";
        private Context mcontext;
        public DataBasehelper(Context context,int version,String database_name) {
            super(context,database_name,null,version);
            mcontext=context;
        }
        @Override
        public void onCreate(sqliteDatabase db) {
            db.execsql(CREATE_DB_ONR);
            Toast.makeText(mcontext,"User_DB Succeed",Toast.LENGTH_SHORT).show();
        }
       @Override
        public void onUpgrade(sqliteDatabase db,int oldVersion,int newVersion) {//当新的versio大于oldversion时候,会执行该方法
        }
    }

    Mainactivity.class

    public class MainActivity extends AppCompatActivity implements View.OnClickListener{
        public static final String TEST_DATABASE_DB = "test_database.db";
        private sqliteDatabase sqliteDatabase;
        private ContentValues contentValues;
        private int result;
        private static final String username_column="username";
        private static final String password_column= "password";
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Button btn_create= (Button) findViewById(R.id.btn_add_database);
            btn_create.setOnClickListener(this);
             @Override
        public void onClick(View v) {
            switch (v.getId()){
                case R.id.btn_add_database://创建数据库
                    DataBasehelper dataBasehelper=new DataBasehelper(this,1,TEST_DATABASE_DB);
                    sqliteDatabase = dataBasehelper.getWritableDatabase();
                    break;
                    }
                 }
           }

    我们把建表语句定义成了一个字符串常量,然后再onCreate()方法调用了exesql()方法去执行这条语句。这样数据库就建立成功了!

    升级数据库

    升级数据库需要执行onUpdate()方法,只要传入一个比原来version大的数,就会执行该方法

    DataBasehelper dataBasehelper2= new DataBasehelper(this,2,TEST_DATABASE_DB);
                    sqliteDatabase = dataBasehelper2.getWritableDatabase();

    我们version传入2,比原来的version=1要大,这时就会自动执行onUpdate()方法中的相关操作。

    添加数据

    数据库的表中添加数据,需要sqliteDatabase的insert()方法;
    对应的源码:

    public long insert(String table,String nullColumnHack,ContentValues values) {
            try {
                return insertWithOnConflict(table,nullColumnHack,values,CONFLICT_NONE);
            } catch (sqlException e) {
                Log.e(TAG,"Error inserting " + values,e);
                return -1;
            }
        }

    table:是表名,向哪张表添加数据;
    nullColumnHack:在未指定添加数据的情况下给某些可为空的列自动赋值NULL,一般不用这个功能,直接传入null即可;
    values:一个ContentValues对象,提供了put()方法重载,用于向ContentValues中添加数据;
    eg:添加数据代码示例:

    contentValues.put(username_column,"two");
                    contentValues.put(password_column,"12345678");
                    contentValues.put(age_column,20);
                    long result01=sqliteDatabase.insert("users",null,contentValues);
    
                    if(result01!=-1)
                    Toast.makeText(this,"添加成功",Toast.LENGTH_SHORT).show();
                    break;

    由于insert()方法返回一个long型值,如果加入出错,会返回-1;否则返回新加入行的id值;

    更新数据

    sqliteDatabase提供了update()方法对数据进行更新;
    对应源码:

    public int update(String table,ContentValues values,String whereClause,String[] whereArgs) { return updateWithOnConflict(table,values,whereClause,whereArgs,CONFLICT_NONE);
        }

    第一和第二个参数上面已经提到了,第三和第四参数用于去约束更新某一行或某几行的数据,不指定的话就默认更新所有行。
    eg:更新数据代码示例:

    contentValues.put(password_column,"112233");
                    result=sqliteDatabase.update("users",contentValues,"username=?",new String[]{"two"});
                    if(result!=0)
                    Toast.makeText(this,"修改成功",Toast.LENGTH_SHORT).show();

    update()返回受影响的行数,以此来判断更新是否成功。

    删除数据

    删除数据就是要调用sqliteDatabase的delete()方法了,其实和上面很相似:
    对应源码:

    public int delete(String table,String whereClause,String[] whereArgs) {}

    和update()方法参数相同;
    eg:删除数据代码示例:

    result = sqliteDatabase.delete("users",new String[]{"two"});
                    if(result==1)
                    Toast.makeText(this,"删除成功",Toast.LENGTH_SHORT).show();

    以上是删除username=“two”的用户

    查询数据

    sqliteDatabase的query()方法用于对数据进行查询,这个方法的参数非常复杂:
    相应的源码:

    public Cursor query(String table,String[] columns,String selection,String[] selectionArgs,String groupBy,String having,String orderBy,String limit) {}


    eg:代码示例

    Cursor cursor=sqliteDatabase.query("users",null,null);//返回一个查询数据的集合
                    if(cursor.moveToFirst()){
                        do{ //遍历cursor对象,取出相关数据
                            String username=cursor.getString(cursor.getColumnIndex(username_column));
                            String password=cursor.getString(cursor.getColumnIndex(password_column));
                            Log.i("TAG",username);
                            Log.i("TAG",password);
                        }while (cursor.moveToNext());
                    }
                    cursor.close();

    以上就是查询users表中的所有数据;

    使用事务

    事务就是说某个操作结果只有成功和失败,不存在完成一半;现实中比如说银行转款,收款方和借款方银行卡金额的改变是一起完成的,中间一方有问题都不可能完成这个过程。
    调用sqliteDatabase.beginTran
    saction()方法来开启一个事务,setTransaction()表示事务执行成功,最后在finally中调用endTransaction()来结束事务。

    eg:代码示例:

    sqliteDatabase.beginTransaction();//开启事务
                    try{
                        sqliteDatabase.delete("users",null,null);
                        if(true){
                            //在这里抛出异常,检查事务的特性,即没有完成就不会删除原来的数据库
    // throw new NullPointerException("检查事务的特性");
                        }
                        contentValues = new ContentValues();
                        contentValues.put(username_column,"one");
                        contentValues.put(password_column,"11111");
                        sqliteDatabase.insert("users",contentValues);
    
                        contentValues.clear();//将上一个里的数据移除
    
                        contentValues.put(username_column,"two");
                        contentValues.put(password_column,"11111");
                        result01=sqliteDatabase.insert("users",contentValues);
                        sqliteDatabase.setTransactionSuccessful();//事务执行成功
    
                        if(result01!=-1)
                            Toast.makeText(this,"事务成功",Toast.LENGTH_SHORT).show();
                    }
                    catch (Exception e){
                        e.printStackTrace();
                    }
                    finally {
                        {
                            sqliteDatabase.endTransaction();//结束事务
                        }
                    }

    我们可以用抛出异常来检验事务的特性,抛出异常就不会这个过程就不会成功,不抛出就会成功执行。

    ContentProvider

    ContentProvider主要用于不同应用程序之间实现数据共享功能,它提供了一套完整的机制,允许一个程序访问另一个应用程序中的数据,可以保证被访数据的安全性。
    适用场景:
    - ContentProvider为存储和读取数据提供了统一的接口;
    - 使用ContentProvider,应用程序可以实现数据共享;
    - Android内置的许多数据都是使用ContentProvider形式,供开发者调用的(如视频,音频,图片,通讯录等)

    若要访问ContentProvider中的共享数据,要借助ContentResolve类,可以通过Context中的getContentResolver()方法获得该类的实例;
    同样用ContentResolve类提供的insert(),update(),delete(),query()方法来实现对数据的增删改查,但是ContentResolve对应的方法不接收表名作为参数,而是使用Uri参数代替;

    URI由3个部分组成, scheme为:content://
    权限(Authority):用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
    路径(path):可以用来表示我们要操作的数据。

    UriMatcher类:匹配并解析Uri,并从Uri中获取数据

    //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
    UriMatcher  sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    //如果match()方法匹配content://com.pc.provider/users路径,返回匹配码为1
    sMatcher.addURI("com.pc.provider","users",1);//添加需要匹配uri,如果匹配就会返回匹配码
    //如果match()方法匹配content://com.pc.provider/users/230路径,返回匹配码为2
    sMatcher.addURI("com.pc.provider","users/#",2);//#号为通配
    switch (sMatcher.match(Uri.parse("content://com.pc.provider/users/10"))) { 
       case 1
         break;
       case 2
         break;
       default://不匹配
         break;
    }

    ContentProvider共享数据

    继承时需要被重写的方法
    - public boolean onCreate():该方法在ContentProvider创建后就会被调用,Android开机后,ContentProvider在其它应用第一次访问它时才会被创建。
    - public Uri insert(Uri uri,ContentValues values):该方法用于供外部应用往ContentProvider添加数据。
    - public int delete(Uri uri,String selection,String[] selectionArgs):该方法用于供外部应用从ContentProvider删除数据。
    - public int update(Uri uri,ContentValues values,String[] selectionArgs):该方法用于供外部应用更新ContentProvider中的数据。
    - public Cursor query(Uri uri,String[] projection,String[] selectionArgs,String sortOrder):该方法用于供外部应用从ContentProvider中获取数据。
    - public String getType(Uri uri):该方法用于返回当前Url所代表数据的MIME类型。

    操作ContentProvider中的数据

    当外部应用需要对ContentProvider中的数据进行添加删除修改查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法
    - public Uri insert(Uri uri,ContentValues values):该方法用于往ContentProvider添加数据。
    - public int delete(Uri uri,String[] selectionArgs):该方法用于从ContentProvider删除数据。
    - public int update(Uri uri,String[] selectionArgs):该方法用于更新ContentProvider中的数据。
    - public Cursor query(Uri uri,String sortOrder):该方法用于从ContentProvider中获取数据。

    eg:下面就用ContentProvider来读取联系人中的信息
    ReadContext.class

    public class Read_Context extends Activity{
    
        private ListView listView;
        private List<String> list;
        private ArrayAdapter<String> adapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.layout_read_context);
    
            listView = (ListView) findViewById(R.id.context_list);
            list = new ArrayList<String>();
            adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,list);
            listView.setAdapter(adapter);
    
            readContacts();
        }
    
        private void readContacts() {
            Cursor cursor=null;
            try{
                cursor=getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null);
                while (cursor.moveToNext()){
                    //获取联系人名称
                    String name=cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                    //获取联系人电话号码
                    String number=cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                    list.add(name+"\n"+number);
                }
            }
            catch (Exception e){
                e.printStackTrace();
            }
            finally {
                if(cursor!=null)
                    cursor.close();
            }
        }
    }

    layout_read_context.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent">
    
        <ListView  android:id="@+id/context_list" android:layout_width="match_parent" android:layout_height="match_parent"></ListView>
    </LinearLayout>

    在AndroidManifest.xml中添加读取联系人权限:

    <uses-permission android:name="android.permission.READ_CONTACTS"/>

    在运行之前,在首先确保联系人中有相应的数据,没有的话要新建两个联系人;
    运行结果:

    当然我们还可以创建自己的内容提供器,只需要获取应用程序内容的Uri,然后借助ContentResolver进行相关操作即可,和上面的操作大同小异。

    猜你在找的Sqlite相关文章