精华内容
下载资源
问答
  • 安卓5种数据存储方式主要有 SharedPreferences -

    安卓的5种数据存储方式主要有

    • SharedPreferences
    • Internal Stroage
    • External Stroage
    • SQLite Database
    • Network Connection

    SharedPreferences

    我们可以使用SharedPreferences保存任何原始的数据,比如说booleans, floats, ints, longs, and strings。即使你的应用被杀死,这些数据也是可持续的。

    为了得到SharedPreferences对象,以下有两种方法

    • getSharedPreferences()。需要指定名字
    • getPreferences。Activity独有的,你不需要指定名字。

    向里面写入数据需要经历下面几步

    1. 调用call()方法获得Editor对象
    2. 调用Editor的putBoolean()等方法
    3. 调用commit方法

    为了读取数据,调用SharedPreferences的getBoolean()等方法

    下面是一个实例

    public class Calc extends Activity {
        public static final String PREFS_NAME = "MyPrefsFile";
    
        @Override
        protected void onCreate(Bundle state){
           super.onCreate(state);
           . . .
    
           // Restore preferences
           SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
           boolean silent = settings.getBoolean("silentMode", false);
           setSilent(silent);
        }
    
        @Override
        protected void onStop(){
           super.onStop();
    
          // We need an Editor object to make preference changes.
          // All objects are from android.context.Context
          SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
          SharedPreferences.Editor editor = settings.edit();
          editor.putBoolean("silentMode", mSilentMode);
    
          // Commit the edits!
          editor.commit();
        }
    }

    Internal Stroage

    你可以直接在设备上直接进行存储,默认的情况下,存储在Internal Stroage的数据是私有,其他应用是不能读取的,如果应用被卸载,那么这些file也会跟着被删除。
    为了创建和写入数据需要经历以下几个步骤

    1. 调用opeanOutputStream(),public abstract FileOutputStream openFileOutput (String name, int mode),是Context里面的方法,返回一个FileOutputStream对象。
    2. 调用write()方法
    3. 调用close()方法

    下面是一个实例

    String FILENAME = "hello_file";
    String string = "hello world!";
    
    FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
    fos.write(string.getBytes());
    fos.close();

    MODE_PRIVATE的意思是对应用来说是私有的,而且如果有相同的文件名字,没有则会创建,有,则会覆盖原有文件。

    为了读取文件我们需要经历以下几个步骤

    1.openFileInput(),传入我们需要读取的文件的名字,返回一个FileInputStream对象。
    2.调用read()方法
    3.调用colse()方法

    如果你想在编译期保存一个static file文件,把文件放在res/raw/ 目录下,如果你想打开它,调用 openRawResource()方法,向方法传入 R.raw.参数,这个方法会返回一个InputStream对象,你可以进行读取,但是不能够写入

    保存缓存文件
    调用getCacheDir方法,会返回一个缓存目录,我们可以把缓存文件存在里面,如果安卓设备的存储量不够,安卓系统可能自动的删除里面的文件,但是我们也可以做相同的事情。应用程序删除会删除上面的文件

    下面是一些有用的方法
    getFilesDir()
    Gets the absolute path to the filesystem directory where your internal files are saved.
    getDir()
    Creates (or opens an existing) directory within your internal storage space.
    deleteFile()
    Deletes a file saved on the internal storage.
    fileList()
    Returns an array of files currently saved by your application.

    External Stroage

    存储在external stroage上的数据是公开的当启用USB大容量存储的时候。
    如果你想向里面存储数据和读取数据只需要 WRITE_EXTERNAL_STORAGE权限
    如果你只是想读取数据,需要READ_EXTERNAL_STORAGE权限

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

    从安卓4.4开始,如果你读取或者写入对你应用来说是私有的文件的话,这些权限是不需要的。

    因为外部存储并不是一定是可用的,所以在存储之前检查他的可用性,例如下面代码

    /* Checks if external storage is available for read and write */
    public boolean isExternalStorageWritable() {
        String state = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(state)) {
            return true;
        }
        return false;
    }
    
    /* Checks if external storage is available to at least read */
    public boolean isExternalStorageReadable() {
        String state = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(state) ||
            Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
            return true;
        }
        return false;
    }

    保存和其他app共享的文件

    getExternalStoragePublicDirectory (String type),向里面传入DIRECTORY_MUSIC, DIRECTORY_PICTURES, DIRECTORY_RINGTONES
    下面是一个示例

    public File getAlbumStorageDir(String albumName) {
        // Get the directory for the user's public pictures directory.
        File file = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_PICTURES), albumName);
        if (!file.mkdirs()) {
            Log.e(LOG_TAG, "Directory not created");
        }
        return file;
    }

    保存app私有的文件

    getExternalFilesDir()
    其中传入一个type参数用来指定子文件夹的类型,如果不需要则传入一个null值。从安卓4.4开始,读或者写app私有的文件是不需要权限的。所以我们可以指定一个 maxSdkVersion属性。如下所示

    <manifest ...>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
                         android:maxSdkVersion="18" />
        ...
    </manifest>

    当应用程序卸载的时候,保存在上述文件夹里的文件也会被删除。同时私有性的原因,不会被媒体扫描器扫到。但即使是这样,其他应用具有READ_EXTERNAL_STORAGE权限的也会有读的权限,所以如果真的是私有的话,应该把它保存到内部存储当中。

    保存缓存文件
    getExternalCacheDir()

    SQLite Database

    这个我之前讲过。。。

    Network Connection

    和服务器进行交互,所用的类在以下两个包中,这里就不做讨论了

    java.net.*
    android.net.*
    
    展开全文
  • 本文介绍Android平台进行数据存储的五大方式,分别如下: 1使用SharedPreferences存储数据 2文件存储数据 3SQLite数据库存储数据 4使用ContentProvider存储数据 5网络存储数据 下面详细讲解这五种方式的...

    本文介绍Android平台进行数据存储的五大方式,分别如下:   

        1 使用SharedPreferences存储数据

        2 文件存储数据      

        3 SQLite数据库存储数据

        4 使用ContentProvider存储数据

        5 网络存储数据

    下面详细讲解这五种方式的特点

    第一种: 使用SharedPreferences存储数据

        适用范围保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。比如应用程序的各种配置信息(如是否打开音效、是否使用震动效果、小游戏的玩家积分等),解锁口 令密码等

        核心原理保存基于XML文件存储的key-value键值对数据,通常用来存储一些简单的配置信息。通过DDMS的File Explorer面板,展开文件浏览树,很明显SharedPreferences数据总是存储在/data/data/<package name>/shared_prefs目录下。SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过SharedPreferences.edit()获取的内部接口Editor对象实现。 SharedPreferences本身是一 个接口,程序无法直接创建SharedPreferences实例,只能通过Context提供的getSharedPreferences(String name, int mode)方法来获取SharedPreferences实例,该方法中name表示要操作的xml文件名,第二个参数具体如下:

                     Context.MODE_PRIVATE: 指定该SharedPreferences数据只能被本应用程序读、写。

                     Context.MODE_WORLD_READABLE:  指定该SharedPreferences数据能被其他应用程序读,但不能写。

                     Context.MODE_WORLD_WRITEABLE:  指定该SharedPreferences数据能被其他应用程序读,

    Editor有如下主要重要方法:

                     SharedPreferences.Editor clear():清空SharedPreferences里所有数据

                     SharedPreferences.Editor putXxx(String key , xxx value): 向SharedPreferences存入指定key对应的数据,其中xxx 可以是boolean,float,int等各种基本类型据

                     SharedPreferences.Editor remove(): 删除SharedPreferences中指定key对应的数据项

                     boolean commit(): 当Editor编辑完成后,使用该方法提交修改

        实际案例:运行界面如下

                           

    这里只提供了两个按钮和一个输入文本框,布局简单,故在此不给出界面布局文件了,程序核心代码如下:         

    复制代码
    class ViewOcl implements View.OnClickListener{
    
            @Override
            public void onClick(View v) {
    
                switch(v.getId()){
                case R.id.btnSet:
                    //步骤1:获取输入值
                    String code = txtCode.getText().toString().trim();
                    //步骤2-1:创建一个SharedPreferences.Editor接口对象,lock表示要写入的XML文件名,MODE_WORLD_WRITEABLE写操作
                    SharedPreferences.Editor editor = getSharedPreferences("lock", MODE_WORLD_WRITEABLE).edit();
                    //步骤2-2:将获取过来的值放入文件
                    editor.putString("code", code);
                    //步骤3:提交
                    editor.commit();
                    Toast.makeText(getApplicationContext(), "口令设置成功", Toast.LENGTH_LONG).show();
                    break;
                case R.id.btnGet:
                    //步骤1:创建一个SharedPreferences接口对象
                    SharedPreferences read = getSharedPreferences("lock", MODE_WORLD_READABLE);
                    //步骤2:获取文件中的值
                    String value = read.getString("code", "");
                    Toast.makeText(getApplicationContext(), "口令为:"+value, Toast.LENGTH_LONG).show();
                    
                    break;
                    
                }
            }
            
        }
    复制代码

    读写其他应用的SharedPreferences: 步骤如下

                    1、在创建SharedPreferences时,指定MODE_WORLD_READABLE模式,表明该SharedPreferences数据可以被其他程序读取

                    2、创建其他应用程序对应的Context:

                        Context pvCount = createPackageContext("com.tony.app", Context.CONTEXT_IGNORE_SECURITY);这里的com.tony.app就是其他程序的包名

                    3、使用其他程序的Context获取对应的SharedPreferences

                        SharedPreferences read = pvCount.getSharedPreferences("lock", Context.MODE_WORLD_READABLE);

                    4、如果是写入数据,使用Editor接口即可,所有其他操作均和前面一致。

    SharedPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其职能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。

     

    第二种: 文件存储数据

     核心原理: Context提供了两个方法来打开数据文件里的文件IO流 FileInputStream openFileInput(String name); FileOutputStream(String name , int mode),这两个方法第一个参数 用于指定文件名,第二个参数指定打开文件的模式。具体有以下值可选:

                 MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可   以使用Context.MODE_APPEND

                 MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。

                 MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;

                 MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。

     除此之外,Context还提供了如下几个重要的方法:

                 getDir(String name , int mode):在应用程序的数据文件夹下获取或者创建name对应的子目录

                 File getFilesDir():获取该应用程序的数据文件夹得绝对路径

                 String[] fileList():返回该应用数据文件夹的全部文件               

    实际案例:界面沿用上图

                 核心代码如下:

    复制代码
    public String read() {
            try {
                FileInputStream inStream = this.openFileInput("message.txt");
                byte[] buffer = new byte[1024];
                int hasRead = 0;
                StringBuilder sb = new StringBuilder();
                while ((hasRead = inStream.read(buffer)) != -1) {
                    sb.append(new String(buffer, 0, hasRead));
                }
    
                inStream.close();
                return sb.toString();
            } catch (Exception e) {
                e.printStackTrace();
            } 
            return null;
        }
        
        public void write(String msg){
            // 步骤1:获取输入值
            if(msg == null) return;
            try {
                // 步骤2:创建一个FileOutputStream对象,MODE_APPEND追加模式
                FileOutputStream fos = openFileOutput("message.txt",
                        MODE_APPEND);
                // 步骤3:将获取过来的值放入文件
                fos.write(msg.getBytes());
                // 步骤4:关闭数据流
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    复制代码

    openFileOutput()方法的第一参数用于指定文件名称,不能包含路径分隔符“/” ,如果文件不存在,Android 会自动创建它。创建的文件保存在/data/data/<package name>/files目录,如: /data/data/cn.tony.app/files/message.txt

     下面讲解某些特殊文件读写需要注意的地方:

    读写sdcard上的文件

    其中读写步骤按如下进行:

    1、调用Environment的getExternalStorageState()方法判断手机上是否插了sd卡,且应用程序具有读写SD卡的权限,如下代码将返回true

    Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)

    2、调用Environment.getExternalStorageDirectory()方法来获取外部存储器,也就是SD卡的目录,或者使用"/mnt/sdcard/"目录

    3、使用IO流操作SD卡上的文件 

    注意点:手机应该已插入SD卡,对于模拟器而言,可通过mksdcard命令来创建虚拟存储卡

               必须在AndroidManifest.xml上配置读写SD卡的权限

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

    案例代码:

    复制代码
    // 文件写操作函数
        private void write(String content) {
            if (Environment.getExternalStorageState().equals(
                    Environment.MEDIA_MOUNTED)) { // 如果sdcard存在
                File file = new File(Environment.getExternalStorageDirectory()
                        .toString()
                        + File.separator
                        + DIR
                        + File.separator
                        + FILENAME); // 定义File类对象
                if (!file.getParentFile().exists()) { // 父文件夹不存在
                    file.getParentFile().mkdirs(); // 创建文件夹
                }
                PrintStream out = null; // 打印流对象用于输出
                try {
                    out = new PrintStream(new FileOutputStream(file, true)); // 追加文件
                    out.println(content);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (out != null) {
                        out.close(); // 关闭打印流
                    }
                }
            } else { // SDCard不存在,使用Toast提示用户
                Toast.makeText(this, "保存失败,SD卡不存在!", Toast.LENGTH_LONG).show();
            }
        }
    
        // 文件读操作函数
        private String read() {
    
            if (Environment.getExternalStorageState().equals(
                    Environment.MEDIA_MOUNTED)) { // 如果sdcard存在
                File file = new File(Environment.getExternalStorageDirectory()
                        .toString()
                        + File.separator
                        + DIR
                        + File.separator
                        + FILENAME); // 定义File类对象
                if (!file.getParentFile().exists()) { // 父文件夹不存在
                    file.getParentFile().mkdirs(); // 创建文件夹
                }
                Scanner scan = null; // 扫描输入
                StringBuilder sb = new StringBuilder();
                try {
                    scan = new Scanner(new FileInputStream(file)); // 实例化Scanner
                    while (scan.hasNext()) { // 循环读取
                        sb.append(scan.next() + "\n"); // 设置文本
                    }
                    return sb.toString();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (scan != null) {
                        scan.close(); // 关闭打印流
                    }
                }
            } else { // SDCard不存在,使用Toast提示用户
                Toast.makeText(this, "读取失败,SD卡不存在!", Toast.LENGTH_LONG).show();
            }
            return null;
        }
    复制代码

     第三种:SQLite存储数据

    SQLite是轻量级嵌入式数据库引擎,它支持 SQL 语言,并且只利用很少的内存就有很好的性能。现在的主流移动设备像Android、iPhone等都使用SQLite作为复杂数据的存储引擎,在我们为移动设备开发应用程序时,也许就要使用到SQLite来存储我们大量的数据,所以我们就需要掌握移动设备上的SQLite开发技巧

    SQLiteDatabase类为我们提供了很多种方法,上面的代码中基本上囊括了大部分的数据库操作;对于添加、更新和删除来说,我们都可以使用

    1 db.executeSQL(String sql);  
    2 db.executeSQL(String sql, Object[] bindArgs);//sql语句中使用占位符,然后第二个参数是实际的参数集 

    除了统一的形式之外,他们还有各自的操作方法:

    1 db.insert(String table, String nullColumnHack, ContentValues values);  
    2 db.update(String table, Contentvalues values, String whereClause, String whereArgs);  
    3 db.delete(String table, String whereClause, String whereArgs);

    以上三个方法的第一个参数都是表示要操作的表名;insert中的第二个参数表示如果插入的数据每一列都为空的话,需要指定此行中某一列的名称,系统将此列设置为NULL,不至于出现错误;insert中的第三个参数是ContentValues类型的变量,是键值对组成的Map,key代表列名,value代表该列要插入的值;update的第二个参数也很类似,只不过它是更新该字段key为最新的value值,第三个参数whereClause表示WHERE表达式,比如“age > ? and age < ?”等,最后的whereArgs参数是占位符的实际参数值;delete方法的参数也是一样

    下面给出demo

    数据的添加

    1.使用insert方法

    复制代码
    1 ContentValues cv = new ContentValues();//实例化一个ContentValues用来装载待插入的数据
    2 cv.put("title","you are beautiful");//添加title
    3 cv.put("weather","sun"); //添加weather
    4 cv.put("context","xxxx"); //添加context
    5 String publish = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    6                         .format(new Date());
    7 cv.put("publish ",publish); //添加publish
    8 db.insert("diary",null,cv);//执行插入操作
    复制代码

    2.使用execSQL方式来实现

    String sql = "insert into user(username,password) values ('Jack Johnson','iLovePopMuisc');//插入操作的SQL语句
    db.execSQL(sql);//执行SQL语句

    数据的删除

    同样有2种方式可以实现

    String whereClause = "username=?";//删除的条件
    String[] whereArgs = {"Jack Johnson"};//删除的条件参数
    db.delete("user",whereClause,whereArgs);//执行删除

    使用execSQL方式的实现

    String sql = "delete from user where username='Jack Johnson'";//删除操作的SQL语句
    db.execSQL(sql);//执行删除操作

    数据修改

    同上,仍是2种方式

    ContentValues cv = new ContentValues();//实例化ContentValues
    cv.put("password","iHatePopMusic");//添加要更改的字段及内容
    String whereClause = "username=?";//修改条件
    String[] whereArgs = {"Jack Johnson"};//修改条件的参数
    db.update("user",cv,whereClause,whereArgs);//执行修改

    使用execSQL方式的实现

    String sql = "update user set password = 'iHatePopMusic' where username='Jack Johnson'";//修改的SQL语句
    db.execSQL(sql);//执行修改

    数据查询

    下面来说说查询操作。查询操作相对于上面的几种操作要复杂些,因为我们经常要面对着各种各样的查询条件,所以系统也考虑到这种复杂性,为我们提供了较为丰富的查询形式:

    1 db.rawQuery(String sql, String[] selectionArgs);  
    2 db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy);  
    3 db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);  
    4 db.query(String distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);  

    上面几种都是常用的查询方法,第一种最为简单,将所有的SQL语句都组织到一个字符串中,使用占位符代替实际参数,selectionArgs就是占位符实际参数集;

    各参数说明:

    • table:表名称
    • colums:表示要查询的列所有名称集
    • selection:表示WHERE之后的条件语句,可以使用占位符
    • selectionArgs:条件语句的参数数组
    • groupBy:指定分组的列名
    • having:指定分组条件,配合groupBy使用
    • orderBy:y指定排序的列名
    • limit:指定分页参数
    • distinct:指定“true”或“false”表示要不要过滤重复值
    • Cursor:返回值,相当于结果集ResultSet

    最后,他们同时返回一个Cursor对象,代表数据集的游标,有点类似于JavaSE中的ResultSet。下面是Cursor对象的常用方法:

    复制代码
     1 c.move(int offset); //以当前位置为参考,移动到指定行  
     2 c.moveToFirst();    //移动到第一行  
     3 c.moveToLast();     //移动到最后一行  
     4 c.moveToPosition(int position); //移动到指定行  
     5 c.moveToPrevious(); //移动到前一行  
     6 c.moveToNext();     //移动到下一行  
     7 c.isFirst();        //是否指向第一条  
     8 c.isLast();     //是否指向最后一条  
     9 c.isBeforeFirst();  //是否指向第一条之前  
    10 c.isAfterLast();    //是否指向最后一条之后  
    11 c.isNull(int columnIndex);  //指定列是否为空(列基数为0)  
    12 c.isClosed();       //游标是否已关闭  
    13 c.getCount();       //总数据项数  
    14 c.getPosition();    //返回当前游标所指向的行数  
    15 c.getColumnIndex(String columnName);//返回某列名对应的列索引值  
    16 c.getString(int columnIndex);   //返回当前行指定列的值 
    复制代码

    实现代码

    复制代码
    String[] params =  {12345,123456};
    Cursor cursor = db.query("user",columns,"ID=?",params,null,null,null);//查询并获得游标 if(cursor.moveToFirst()){//判断游标是否为空 for(int i=0;i<cursor.getCount();i++){ cursor.move(i);//移动到指定记录 String username = cursor.getString(cursor.getColumnIndex("username"); String password = cursor.getString(cursor.getColumnIndex("password")); } }
    复制代码

    通过rawQuery实现的带参数查询

    复制代码
    Cursor result=db.rawQuery("SELECT ID, name, inventory FROM mytable");
    //Cursor c = db.rawQuery("s name, inventory FROM mytable where ID=?",new Stirng[]{"123456"});     
    result.moveToFirst(); 
    while (!result.isAfterLast()) { 
        int id=result.getInt(0); 
        String name=result.getString(1); 
        int inventory=result.getInt(2); 
        // do something useful with these 
        result.moveToNext(); 
     } 
     result.close();
    复制代码

     

    在上面的代码示例中,已经用到了这几个常用方法中的一些,关于更多的信息,大家可以参考官方文档中的说明。

    最后当我们完成了对数据库的操作后,记得调用SQLiteDatabase的close()方法释放数据库连接,否则容易出现SQLiteException。

    上面就是SQLite的基本应用,但在实际开发中,为了能够更好的管理和维护数据库,我们会封装一个继承自SQLiteOpenHelper类的数据库操作类,然后以这个类为基础,再封装我们的业务逻辑方法。

    这里直接使用案例讲解:下面是案例demo的界面

    SQLiteOpenHelper类介绍

    SQLiteOpenHelper是SQLiteDatabase的一个帮助类,用来管理数据库的创建和版本的更新。一般是建立一个类继承它,并实现它的onCreate和onUpgrade方法。

    方法名方法描述
    SQLiteOpenHelper(Context context,String name,SQLiteDatabase.CursorFactory factory,int version)

    构造方法,其中

    context 程序上下文环境 即:XXXActivity.this;

    name :数据库名字;

    factory:游标工厂,默认为null,即为使用默认工厂;

    version 数据库版本号

    onCreate(SQLiteDatabase db) 创建数据库时调用
    onUpgrade(SQLiteDatabase db,int oldVersion , int newVersion) 版本更新时调用
    getReadableDatabase() 创建或打开一个只读数据库
    getWritableDatabase() 创建或打开一个读写数据库

    首先创建数据库类

    复制代码
     1 import android.content.Context;
     2 import android.database.sqlite.SQLiteDatabase;
     3 import android.database.sqlite.SQLiteDatabase.CursorFactory;
     4 import android.database.sqlite.SQLiteOpenHelper;
     5 
     6 public class SqliteDBHelper extends SQLiteOpenHelper {
     7 
     8     // 步骤1:设置常数参量
     9     private static final String DATABASE_NAME = "diary_db";
    10     private static final int VERSION = 1;
    11     private static final String TABLE_NAME = "diary";
    12 
    13     // 步骤2:重载构造方法
    14     public SqliteDBHelper(Context context) {
    15         super(context, DATABASE_NAME, null, VERSION);
    16     }
    17 
    18     /*
    19      * 参数介绍:context 程序上下文环境 即:XXXActivity.this 
    20      * name 数据库名字 
    21      * factory 接收数据,一般情况为null
    22      * version 数据库版本号
    23      */
    24     public SqliteDBHelper(Context context, String name, CursorFactory factory,
    25             int version) {
    26         super(context, name, factory, version);
    27     }
    28     //数据库第一次被创建时,onCreate()会被调用
    29     @Override
    30     public void onCreate(SQLiteDatabase db) {
    31         // 步骤3:数据库表的创建
    32         String strSQL = "create table "
    33                 + TABLE_NAME
    34                 + "(tid integer primary key autoincrement,title varchar(20),weather varchar(10),context text,publish date)";
    35         //步骤4:使用参数db,创建对象
    36         db.execSQL(strSQL);
    37     }
    38     //数据库版本变化时,会调用onUpgrade()
    39     @Override
    40     public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
    41 
    42     }
    43 }
    复制代码

    正如上面所述,数据库第一次创建时onCreate方法会被调用,我们可以执行创建表的语句,当系统发现版本变化之后,会调用onUpgrade方法,我们可以执行修改表结构等语句。

     我们需要一个Dao,来封装我们所有的业务方法,代码如下:

    复制代码
     1 import android.content.Context;
     2 import android.database.Cursor;
     3 import android.database.sqlite.SQLiteDatabase;
     4 
     5 import com.chinasoft.dbhelper.SqliteDBHelper;
     6 
     7 public class DiaryDao {
     8 
     9     private SqliteDBHelper sqliteDBHelper;
    10     private SQLiteDatabase db;
    11 
    12     // 重写构造方法
    13     public DiaryDao(Context context) {
    14         this.sqliteDBHelper = new SqliteDBHelper(context);
    15         db = sqliteDBHelper.getWritableDatabase();
    16     }
    17 
    18     // 读操作
    19     public String execQuery(final String strSQL) {
    20         try {
    21             System.out.println("strSQL>" + strSQL);
    22             // Cursor相当于JDBC中的ResultSet
    23             Cursor cursor = db.rawQuery(strSQL, null);
    24             // 始终让cursor指向数据库表的第1行记录
    25             cursor.moveToFirst();
    26             // 定义一个StringBuffer的对象,用于动态拼接字符串
    27             StringBuffer sb = new StringBuffer();
    28             // 循环游标,如果不是最后一项记录
    29             while (!cursor.isAfterLast()) {
    30                 sb.append(cursor.getInt(0) + "/" + cursor.getString(1) + "/"
    31                         + cursor.getString(2) + "/" + cursor.getString(3) + "/"
    32                         + cursor.getString(4)+"#");
    33                 //cursor游标移动
    34                 cursor.moveToNext();
    35             }
    36             db.close();
    37             return sb.deleteCharAt(sb.length()-1).toString();
    38         } catch (RuntimeException e) {
    39             e.printStackTrace();
    40             return null;
    41         }
    42 
    43     }
    44 
    45     // 写操作
    46     public boolean execOther(final String strSQL) {
    47         db.beginTransaction();  //开始事务
    48         try {
    49             System.out.println("strSQL" + strSQL);
    50             db.execSQL(strSQL);
    51             db.setTransactionSuccessful();  //设置事务成功完成 
    52             db.close();
    53             return true;
    54         } catch (RuntimeException e) {
    55             e.printStackTrace();
    56             return false;
    57         }finally {  
    58             db.endTransaction();    //结束事务  
    59         }  
    60 
    61     }
    62 }
    复制代码

    我们在Dao构造方法中实例化sqliteDBHelper并获取一个SQLiteDatabase对象,作为整个应用的数据库实例;在增删改信息时,我们采用了事务处理,确保数据完整性;最后要注意释放数据库资源db.close(),这一个步骤在我们整个应用关闭时执行,这个环节容易被忘记,所以朋友们要注意。

    我们获取数据库实例时使用了getWritableDatabase()方法,也许朋友们会有疑问,在getWritableDatabase()和getReadableDatabase()中,你为什么选择前者作为整个应用的数据库实例呢?在这里我想和大家着重分析一下这一点。

    我们来看一下SQLiteOpenHelper中的getReadableDatabase()方法:

    复制代码
     1 public synchronized SQLiteDatabase getReadableDatabase() {  
     2     if (mDatabase != null && mDatabase.isOpen()) {  
     3         // 如果发现mDatabase不为空并且已经打开则直接返回  
     4         return mDatabase;  
     5     }  
     6   
     7     if (mIsInitializing) {  
     8         // 如果正在初始化则抛出异常  
     9         throw new IllegalStateException("getReadableDatabase called recursively");  
    10     }  
    11   
    12     // 开始实例化数据库mDatabase  
    13   
    14     try {  
    15         // 注意这里是调用了getWritableDatabase()方法  
    16         return getWritableDatabase();  
    17     } catch (SQLiteException e) {  
    18         if (mName == null)  
    19             throw e; // Can't open a temp database read-only!  
    20         Log.e(TAG, "Couldn't open " + mName + " for writing (will try read-only):", e);  
    21     }  
    22   
    23     // 如果无法以可读写模式打开数据库 则以只读方式打开  
    24   
    25     SQLiteDatabase db = null;  
    26     try {  
    27         mIsInitializing = true;  
    28         String path = mContext.getDatabasePath(mName).getPath();// 获取数据库路径  
    29         // 以只读方式打开数据库  
    30         db = SQLiteDatabase.openDatabase(path, mFactory, SQLiteDatabase.OPEN_READONLY);  
    31         if (db.getVersion() != mNewVersion) {  
    32             throw new SQLiteException("Can't upgrade read-only database from version " + db.getVersion() + " to "  
    33                     + mNewVersion + ": " + path);  
    34         }  
    35   
    36         onOpen(db);  
    37         Log.w(TAG, "Opened " + mName + " in read-only mode");  
    38         mDatabase = db;// 为mDatabase指定新打开的数据库  
    39         return mDatabase;// 返回打开的数据库  
    40     } finally {  
    41         mIsInitializing = false;  
    42         if (db != null && db != mDatabase)  
    43             db.close();  
    44     }  
    45 }
    复制代码

    在getReadableDatabase()方法中,首先判断是否已存在数据库实例并且是打开状态,如果是,则直接返回该实例,否则试图获取一个可读写模式的数据库实例,如果遇到磁盘空间已满等情况获取失败的话,再以只读模式打开数据库,获取数据库实例并返回,然后为mDatabase赋值为最新打开的数据库实例。既然有可能调用到getWritableDatabase()方法,我们就要看一下了:

    复制代码
    public synchronized SQLiteDatabase getWritableDatabase() {  
        if (mDatabase != null && mDatabase.isOpen() && !mDatabase.isReadOnly()) {  
            // 如果mDatabase不为空已打开并且不是只读模式 则返回该实例  
            return mDatabase;  
        }  
      
        if (mIsInitializing) {  
            throw new IllegalStateException("getWritableDatabase called recursively");  
        }  
      
        // If we have a read-only database open, someone could be using it  
        // (though they shouldn't), which would cause a lock to be held on  
        // the file, and our attempts to open the database read-write would  
        // fail waiting for the file lock. To prevent that, we acquire the  
        // lock on the read-only database, which shuts out other users.  
      
        boolean success = false;  
        SQLiteDatabase db = null;  
        // 如果mDatabase不为空则加锁 阻止其他的操作  
        if (mDatabase != null)  
            mDatabase.lock();  
        try {  
            mIsInitializing = true;  
            if (mName == null) {  
                db = SQLiteDatabase.create(null);  
            } else {  
                // 打开或创建数据库  
                db = mContext.openOrCreateDatabase(mName, 0, mFactory);  
            }  
            // 获取数据库版本(如果刚创建的数据库,版本为0)  
            int version = db.getVersion();  
            // 比较版本(我们代码中的版本mNewVersion为1)  
            if (version != mNewVersion) {  
                db.beginTransaction();// 开始事务  
                try {  
                    if (version == 0) {  
                        // 执行我们的onCreate方法  
                        onCreate(db);  
                    } else {  
                        // 如果我们应用升级了mNewVersion为2,而原版本为1则执行onUpgrade方法  
                        onUpgrade(db, version, mNewVersion);  
                    }  
                    db.setVersion(mNewVersion);// 设置最新版本  
                    db.setTransactionSuccessful();// 设置事务成功  
                } finally {  
                    db.endTransaction();// 结束事务  
                }  
            }  
      
            onOpen(db);  
            success = true;  
            return db;// 返回可读写模式的数据库实例  
        } finally {  
            mIsInitializing = false;  
            if (success) {  
                // 打开成功  
                if (mDatabase != null) {  
                    // 如果mDatabase有值则先关闭  
                    try {  
                        mDatabase.close();  
                    } catch (Exception e) {  
                    }  
                    mDatabase.unlock();// 解锁  
                }  
                mDatabase = db;// 赋值给mDatabase  
            } else {  
                // 打开失败的情况:解锁、关闭  
                if (mDatabase != null)  
                    mDatabase.unlock();  
                if (db != null)  
                    db.close();  
            }  
        }  
    }
    复制代码

    大家可以看到,几个关键步骤是,首先判断mDatabase如果不为空已打开并不是只读模式则直接返回,否则如果mDatabase不为空则加锁,然后开始打开或创建数据库,比较版本,根据版本号来调用相应的方法,为数据库设置新版本号,最后释放旧的不为空的mDatabase并解锁,把新打开的数据库实例赋予mDatabase,并返回最新实例。

    看完上面的过程之后,大家或许就清楚了许多,如果不是在遇到磁盘空间已满等情况,getReadableDatabase()一般都会返回和getWritableDatabase()一样的数据库实例,所以我们在DBManager构造方法中使用getWritableDatabase()获取整个应用所使用的数据库实例是可行的。当然如果你真的担心这种情况会发生,那么你可以先用getWritableDatabase()获取数据实例,如果遇到异常,再试图用getReadableDatabase()获取实例,当然这个时候你获取的实例只能读不能写了

    最后,让我们看一下如何使用这些数据操作方法来显示数据,界面核心逻辑代码:

    复制代码
    public class SQLiteActivity extends Activity {
    
        public DiaryDao diaryDao;
    
        //因为getWritableDatabase内部调用了mContext.openOrCreateDatabase(mName, 0, mFactory);  
        //所以要确保context已初始化,我们可以把实例化Dao的步骤放在Activity的onCreate里
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            diaryDao = new DiaryDao(SQLiteActivity.this);
            initDatabase();
        }
    
        class ViewOcl implements View.OnClickListener {
    
            @Override
            public void onClick(View v) {
    
                String strSQL;
                boolean flag;
                String message;
                switch (v.getId()) {
                case R.id.btnAdd:
                    String title = txtTitle.getText().toString().trim();
                    String weather = txtWeather.getText().toString().trim();;
                    String context = txtContext.getText().toString().trim();;
                    String publish = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                            .format(new Date());
                    // 动态组件SQL语句
                    strSQL = "insert into diary values(null,'" + title + "','"
                            + weather + "','" + context + "','" + publish + "')";
                    flag = diaryDao.execOther(strSQL);
                    //返回信息
                    message = flag?"添加成功":"添加失败";
                    Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
                    break;
                case R.id.btnDelete:
                    strSQL = "delete from diary where tid = 1";
                    flag = diaryDao.execOther(strSQL);
                    //返回信息
                    message = flag?"删除成功":"删除失败";
                    Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
                    break;
                case R.id.btnQuery:
                    strSQL = "select * from diary order by publish desc";
                    String data = diaryDao.execQuery(strSQL);
                    Toast.makeText(getApplicationContext(), data, Toast.LENGTH_LONG).show();
                    break;
                case R.id.btnUpdate:
                    strSQL = "update diary set title = '测试标题1-1' where tid = 1";
                    flag = diaryDao.execOther(strSQL);
                    //返回信息
                    message = flag?"更新成功":"更新失败";
                    Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
                    break;
                }
            }
        }
    
        private void initDatabase() {
            // 创建数据库对象
            SqliteDBHelper sqliteDBHelper = new SqliteDBHelper(SQLiteActivity.this);
            sqliteDBHelper.getWritableDatabase();
            System.out.println("数据库创建成功");
        }
    }
    复制代码

     

    Android sqlite3数据库管理工具

    Android SDK的tools目录下提供了一个sqlite3.exe工具,这是一个简单的sqlite数据库管理工具。开发者可以方便的使用其对sqlite数据库进行命令行的操作。

    程序运行生成的*.db文件一般位于"/data/data/项目名(包括所处包名)/databases/*.db",因此要对数据库文件进行操作需要先找到数据库文件:

    1、进入shell 命令

    adb shell

    2、找到数据库文件

    #cd data/data
    #ls                --列出所有项目
    #cd project_name   --进入所需项目名
    #cd databases    
    #ls                --列出现寸的数据库文件

    3、进入数据库

    #sqlite3 test_db   --进入所需数据库

    会出现类似如下字样:

    SQLite version 3.6.22
    Enter ".help" for instructions
    Enter SQL statements terminated with a ";"
    sqlite>

    至此,可对数据库进行sql操作。

    4、sqlite常用命令

    >.databases        --产看当前数据库
    >.tables           --查看当前数据库中的表
    >.help             --sqlite3帮助
    >.schema            --各个表的生成语句

    转载于:https://www.cnblogs.com/Dionexin/p/6013119.html

    展开全文
  • 安卓5种存储方式

    2017-04-28 17:43:50
    适用范围:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。比如应用程序的各种配置信息(如是否打开音效、是否使用震动效果、小游戏的玩家积分等),解锁口 令密码,是否为第一次登陆等 核心...

    转载于博客园 http://www.cnblogs.com/ITtangtang/p/3920916.html
    1、sharedpreferences
    适用范围:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。比如应用程序的各种配置信息(如是否打开音效、是否使用震动效果、小游戏的玩家积分等),解锁口 令密码,是否为第一次登陆等
    核心原理:保存基于XML文件存储的key-value键值对数据,通常用来存储一些简单的配置信息。通过DDMS的File Explorer面板,展开文件浏览树,很明显SharedPreferences数据总是存储在/data/data//shared_prefs目录下。SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过SharedPreferences.edit()获取的内部接口Editor对象实现。 SharedPreferences本身是一 个接口,程序无法直接创建SharedPreferences实例,只能通过Context提供的getSharedPreferences(String name, int mode)方法来获取SharedPreferences实例,该方法中name表示要操作的xml文件名,第二个参数具体如下:

                 Context.MODE_PRIVATE: 指定该SharedPreferences数据只能被本应用程序读、写。
    
                 Context.MODE_WORLD_READABLE:  指定该SharedPreferences数据能被其他应用程序读,但不能写。
    
                 Context.MODE_WORLD_WRITEABLE:  指定该SharedPreferences数据能被其他应用程序读,写
    

    Editor有如下主要重要方法:

                 SharedPreferences.Editor clear():清空SharedPreferences里所有数据
    
                 SharedPreferences.Editor putXxx(String key , xxx value): 向SharedPreferences存入指定key对应的数据,其中xxx 可以是boolean,float,int等各种基本类型据
    
                 SharedPreferences.Editor remove(): 删除SharedPreferences中指定key对应的数据项
    
                 boolean commit(): 当Editor编辑完成后,使用该方法提交修改
    

    读写其他应用的SharedPreferences: 步骤如下

                1、在创建SharedPreferences时,指定MODE_WORLD_READABLE模式,表明该SharedPreferences数据可以被其他程序读取
    
                2、创建其他应用程序对应的Context:
    
                    Context pvCount = createPackageContext("com.tony.app", Context.CONTEXT_IGNORE_SECURITY);这里的com.tony.app就是其他程序的包名
    
                3、使用其他程序的Context获取对应的SharedPreferences
    
                    SharedPreferences read = pvCount.getSharedPreferences("lock", Context.MODE_WORLD_READABLE);
    
                4、如果是写入数据,使用Editor接口即可,所有其他操作均和前面一致。
    

    SharedPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其职能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。
    2

    展开全文
  • 安卓数据存储方式

    2014-03-11 15:20:03
    本文介绍Android中的5种数据存储方式。   数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是: 1 使用SharedPreferences存储数据 2 文件存储数据 3 SQLite数据库...
    本文介绍Android中的5种数据存储方式。
    
     
    数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是:
    1 使用SharedPreferences存储数据
    2 文件存储数据
    3 SQLite数据库存储数据
    4 使用ContentProvider存储数据
    5 网络存储数据
     
    下面将为大家一一详细介绍。
     
    第一种: 使用SharedPreferences存储数据
    SharedPreferences是Android平台上一个轻量级的存储类,主要是保存一些常用的配置比如窗口状态,一般在Activity中 重载窗口状态onSaveInstanceState保存一般使用SharedPreferences完成,它提供了Android平台常规的Long长 整形、Int整形、String字符串型的保存。
     
    它是什么样的处理方式呢? SharedPreferences类似过去Windows系统上的ini配置文件,但是它分为多种权限,可以全局共享访问,android123提示最终是以xml方式来保存,整体效率来看不是特别的高,对于常规的轻量级而言比SQLite要好不少,如果真的存储量不大可以考虑自己定义文件格式。xml 处理时Dalvik会通过自带底层的本地XML Parser解析,比如XMLpull方式,这样对于内存资源占用比较好。
     
    它的本质是基于XML文件存储key-value键值对数据,通常用来存储一些简单的配置信息。
    其存储位置在/data/data/< >/shared_prefs目录下。
    SharedPreferences对象本身只能获取数据而不支持存储和修改,存储修改是通过Editor对象实现。
     
    实现SharedPreferences存储的步骤如下:
    一、根据Context获取SharedPreferences对象
    二、利用edit()方法获取Editor对象。
    三、通过Editor对象存储key-value键值对数据。
    四、通过commit()方法提交数据。
     
    下面是示例代码:
    public class MainActivity extends Activity {    
     @Override
         public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            
            //获取SharedPreferences对象
            Context ctx = MainActivity.this;       
            SharedPreferences sp = ctx.getSharedPreferences("SP", MODE_PRIVATE);
            //存入数据
            Editor editor = sp.edit();
            editor.putString("STRING_KEY", "string");
            editor.putInt("INT_KEY", 0);
            editor.putBoolean("BOOLEAN_KEY", true);
            editor.commit();
            
            //返回STRING_KEY的值
            Log.d("SP", sp.getString("STRING_KEY", "none"));
            //如果NOT_EXIST不存在,则返回值为"none"
            Log.d("SP", sp.getString("NOT_EXIST", "none"));
         }
     
    }
    这段代码执行过后,即在/data/data/com.test/shared_prefs目录下生成了一个SP.xml文件,一个应用可以创建多个这样的xml文件。
     
    SharedPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其职能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式。
     
    第二种: 文件存储数据
    关于文件存储,Activity提供了openFileOutput()方法可以用于把数据输出到文件中,具体的实现过程与在J2SE环境中保存数据到文件中是一样的。
    文件可用来存放大量数据,如文本、图片、音频等。
    默认位置:/data/data/< >/files/***.***。
     
    代码示例:
    public void save()
     {
     
            try {
                FileOutputStream outStream=this.openFileOutput("a.txt",Context.MODE_WORLD_READABLE);
                outStream.write(text.getText().toString().getBytes());
                outStream.close();
                Toast.makeText(MyActivity.this,"Saved",Toast.LENGTH_LONG).show();
            } catch (FileNotFoundException e) {
                return;
            }
            catch (IOException e){
                return ;
            }
     
     } 
    openFileOutput()方法的第一参数用于指定文件名称,不能包含路径分隔符“/” ,如果文件不存在,Android 会自动创建它。
    创建的文件保存在/data/data//files目录,如: /data/data/cn.itcast.action/files/itcast.txt ,通过点击Eclipse菜单“Window”-“Show View”-“Other”,在对话窗口中展开android文件夹,选择下面的File Explorer视图,然后在File Explorer视图中展开/data/data//files目录就可以看到该文件。
     
    openFileOutput()方法的第二参数用于指定操作模式,有四种模式,分别为:
    Context.MODE_PRIVATE = 0
    Context.MODE_APPEND = 32768
    Context.MODE_WORLD_READABLE = 1
    Context.MODE_WORLD_WRITEABLE = 2
    Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可以使用Context.MODE_APPEND
    Context.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
    Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件。
    MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;
    MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。
     
    如果希望文件被其他应用读和写,可以传入: openFileOutput("itcast.txt", Context.MODE_WORLD_READABLE + Context.MODE_WORLD_WRITEABLE); android有一套自己的安全模型,当应用程序(.apk)在安装时系统就会分配给他一个userid,当该应用要去访问其他资源比如文件的时候,就需要userid匹配。默认情况下,任何应用创建的文件,sharedpreferences,数据库都应该是私有的(位于/data/data//files),其他程序无法访问。
    除非在创建时指定了Context.MODE_WORLD_READABLE或者Context.MODE_WORLD_WRITEABLE ,只有这样其他程序才能正确访问。
     
    读取文件示例
    public void load()
    {
        try {
            FileInputStream inStream=this.openFileInput("a.txt");
            ByteArrayOutputStream stream=new ByteArrayOutputStream();
            byte[] buffer=new byte[1024];
            int length=-1;
    while((length=inStream.read(buffer))!=-1)   {
                stream.write(buffer,0,length);
            }
     
            stream.close();
            inStream.close();
            text.setText(stream.toString());
            Toast.makeText(MyActivity.this,"Loaded",Toast.LENGTH_LONG).show();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        catch (IOException e){
            return ;
        }
     
    }
    对于私有文件只能被创建该文件的应用访问,如果希望文件能被其他应用读和写,可以在创建文件时,指定Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE权限。
     
    Activity还提供了getCacheDir()和getFilesDir()方法: getCacheDir()方法用于获取/data/data//cache目录 getFilesDir()方法用于获取/data/data//files目录。
     
    把文件存入SDCard:
    使用Activity的openFileOutput()方法保存文件,文件是存放在手机空间上,一般手机的存储空间不是很大,存放些小文件还行,如果要存放像视频这样的大文件,是不可行的。对于像视频这样的大文件,我们可以把它存放在SDCard。
    SDCard是干什么的?你可以把它看作是移动硬盘或U盘。 在模拟器中使用SDCard,你需要先创建一张SDCard卡(当然不是真的SDCard,只是镜像文件)。
     
    创建SDCard可以在Eclipse创建模拟器时随同创建,也可以使用DOS命令进行创建,如下: 在Dos窗口中进入android SDK安装路径的tools目录,输入以下命令创建一张容量为2G的SDCard,文件后缀可以随便取,建议使用.img: mksdcard 2048M D:\AndroidTool\sdcard.img 在程序中访问SDCard,你需要申请访问SDCard的权限。
     
    在AndroidManifest.xml中加入访问SDCard的权限如下:
    <!-- 在SDCard中创建与删除文件权限 -->
        <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
     
        <!-- 往SDCard写入数据权限 -->
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 
    要往SDCard存放文件,程序必须先判断手机是否装有SDCard,并且可以进行读写。
    注意:访问SDCard必须在AndroidManifest.xml中加入访问SDCard的权限。
    if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ 
    File sdCardDir = Environment.getExternalStorageDirectory();//获取SDCard目录         
     
    File saveFile = new File(sdCardDir, “a.txt”);
            FileOutputStream outStream = new FileOutputStream(saveFile);
            outStream.write("test".getBytes());
            outStream.close();
     
    } 
    Environment.getExternalStorageState()方法用于获取SDCard的状态,如果手机装有SDCard,并且可以进行读写,那么方法返回的状态等于Environment.MEDIA_MOUNTED。  
    Environment.getExternalStorageDirectory()方法用于获取SDCard的目录,当然要获取SDCard的目录,你也可以这样写:
    File sdCardDir = new File("/sdcard"); //获取SDCard目录
     
    File saveFile = new File(sdCardDir, "itcast.txt");
     
    //上面两句代码可以合成一句:
     
    File saveFile = new File("/sdcard/a.txt");
     
    FileOutputStream outStream = new FileOutputStream(saveFile);
     
    outStream.write("test".getBytes());
     
    outStream.close();
    第三种: SQLite数据库存储数据
     
    SQLite是轻量级嵌入式数据库引擎,它支持 SQL 语言,并且只利用很少的内存就有很好的性能。此外它还是开源的,任何人都可以使用它。许多开源项目((Mozilla, PHP, Python)都使用了 SQLite.SQLite 由以下几个组件组成:SQL 编译器、内核、后端以及附件。SQLite 通过利用虚拟机和虚拟数据库引擎(VDBE),使调试、修改和扩展 SQLite 的内核变得更加方便。
    特点:
    面向资源有限的设备,
    没有服务器进程,
    所有数据存放在同一文件中跨平台,
    可自由复制。
    SQLite 内部结构:
     
    SQLite 基本上符合 SQL-92 标准,和其他的主要 SQL 数据库没什么区别。它的优点就是高效,Android 运行时环境包含了完整的 SQLite。  
    SQLite 和其他数据库最大的不同就是对数据类型的支持,创建一个表时,可以在 CREATE TABLE 语句中指定某列的数据类型,但是你可以把任何数据类型放入任何列中。当某个值插入数据库时,SQLite 将检查它的类型。如果该类型与关联的列不匹配,则 SQLite 会尝试将该值转换成该列的类型。如果不能转换,则该值将作为其本身具有的类型存储。比如可以把一个字符串(String)放入 INTEGER 列。SQLite 称这为“弱类型”(manifest typing.)。 此外,SQLite 不支持一些标准的 SQL 功能,特别是外键约束(FOREIGN KEY constrains),嵌套 transcaction 和 RIGHT OUTER JOIN 和 FULL OUTER JOIN, 还有一些 ALTER TABLE 功能。 除了上述功能外,SQLite 是一个完整的 SQL 系统,拥有完整的触发器,交易等等。
    Android 集成了 SQLite 数据库 Android 在运行时(run-time)集成了 SQLite,所以每个 Android 应用程序都可以使用 SQLite 数据库。 
    对于熟悉 SQL 的开发人员来时,在 Android 开发中使用 SQLite 相当简单。但是,由于 JDBC 会消耗太多的系统资源,所以 JDBC 对于手机这种内存受限设备来说并不合适。因此,Android 提供了一些新的 API 来使用 SQLite 数据库,Android 开发中,程序员需要学使用这些 API。
    数据库存储在 data/< 项目文件夹 >/databases/ 下。 Android 开发中使用 SQLite 数据库 Activites 可以通过 Content Provider 或者 Service 访问一个数据库。
    下面会详细讲解如果创建数据库,添加数据和查询数据库。 创建数据库 Android 不自动提供数据库。在 Android 应用程序中使用 SQLite,必须自己创建数据库,然后创建表、索引,填充数据。
    Android 提供了 SQLiteOpenHelper 帮助你创建一个数据库,你只要继承 SQLiteOpenHelper 类,就可以轻松的创建数据库。SQLiteOpenHelper 类根据开发应用程序的需要,封装了创建和更新数据库使用的逻辑。
    SQLiteOpenHelper 的子类,至少需要实现三个方法:
     
    1 构造函数,调用父类 SQLiteOpenHelper 的构造函数。这个方法需要四个参数:上下文环境(例如,一个 Activity),数据库名字,一个可选的游标工厂(通常是 Null),一个代表你正在使用的数据库模型版本的整数。
     
    2 onCreate()方法,它需要一个 SQLiteDatabase 对象作为参数,根据需要对这个对象填充表和初始化数据。
     
    3 onUpgrage() 方法,它需要三个参数,一个 SQLiteDatabase 对象,一个旧的版本号和一个新的版本号,这样你就可以清楚如何把一个数据库从旧的模型转变到新的模型。

    下面示例代码展示了如何继承 SQLiteOpenHelper 创建数据库:
    public class DatabaseHelper extends SQLiteOpenHelper {    
      DatabaseHelper(Context context, String name, CursorFactory cursorFactory, int version) 
      {     
        super(context, name, cursorFactory, version);     
         }     
         
         @Override    
         public void onCreate(SQLiteDatabase db) {     
             // TODO 创建数据库后,对数据库的操作     
         }     
         
         @Override    
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {     
             // TODO 更改数据库版本的操作     
         }     
         
     @Override    
     public void onOpen(SQLiteDatabase db) {     
             super.onOpen(db);       
             // TODO 每次成功打开数据库后首先被执行     
         }     
     }
    接下来讨论具体如何创建表、插入数据、删除表等等。调用 getReadableDatabase() 或 getWriteableDatabase() 方法,你可以得到 SQLiteDatabase 实例,具体调用那个方法,取决于你是否需要改变数据库的内容:
     db=(new DatabaseHelper(getContext())).getWritableDatabase();
           return (db == null) ? false : true;  
     
    上面这段代码会返回一个 SQLiteDatabase 类的实例,使用这个对象,你就可以查询或者修改数据库。 当你完成了对数据库的操作(例如你的 Activity 已经关闭),需要调用 SQLiteDatabase 的 Close() 方法来释放掉数据库连接。 创建表和索引 为了创建表和索引,需要调用 SQLiteDatabase 的 execSQL() 方法来执行 DDL 语句。如果没有异常,这个方法没有返回值。 
    例如,你可以执行如下代码:

    db.execSQL("CREATE TABLE mytable (_id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, value REAL);");  

    这条语句会创建一个名为 mytable 的表,表有一个列名为 _id,并且是主键,这列的值是会自动增长的整数(例如,当你插入一行时,SQLite 会给这列自动赋值),另外还有两列:title( 字符 ) 和 value( 浮点数 )。 SQLite 会自动为主键列创建索引。 通常情况下,第一次创建数据库时创建了表和索引。
    如果你不需要改变表的 schema,不需要删除表和索引 . 删除表和索引,需要使用 execSQL() 方法调用 DROP INDEX 和 DROP TABLE 语句。 给表添加数据 上面的代码,已经创建了数据库和表,现在需要给表添加数据。有两种方法可以给表添加数据。
    像上面创建表一样,你可以使用 execSQL() 方法执行 INSERT, UPDATE, DELETE 等语句来更新表的数据。execSQL() 方法适用于所有不返回结果的 SQL 语句。 

    例如: db.execSQL("INSERT INTO widgets (name, inventory)"+ "VALUES ('Sprocket', 5)"); 

    另一种方法是使用 SQLiteDatabase 对象的 insert(), update(), delete() 方法。这些方法把 SQL 语句的一部分作为参数。
    示例如下:
    ContentValues cv=new ContentValues();
    cv.put(Constants.TITLE, "example title");
    cv.put(Constants.VALUE, SensorManager.GRAVITY_DEATH_STAR_I);
    db.insert("mytable", getNullColumnHack(), cv);
    update()方法有四个参数,分别是表名,表示列名和值的 ContentValues 对象,可选的 WHERE 条件和可选的填充 WHERE 语句的字符串,这些字符串会替换 WHERE 条件中的“?”标记。
    update() 根据条件,更新指定列的值,所以用 execSQL() 方法可以达到同样的目的。 WHERE 条件和其参数和用过的其他 SQL APIs 类似。
    例如:
     
    String[] parms=new String[] {"this is a string"};
     
    db.update("widgets", replacements, "name=?", parms);
    delete() 方法的使用和 update() 类似,使用表名,可选的 WHERE 条件和相应的填充 WHERE 条件的字符串。 查询数据库 类似 INSERT, UPDATE, DELETE,有两种方法使用 SELECT 从 SQLite 数据库检索数据。  
     
    1 .使用 rawQuery() 直接调用 SELECT 语句; 使用 query() 方法构建一个查询。
    Raw Queries 正如 API 名字,rawQuery() 是最简单的解决方法。通过这个方法你就可以调用 SQL SELECT 语句。
    例如: Cursor c=db.rawQuery( "SELECT name FROM sqlite_master WHERE type='table' AND name='mytable'", null);
    在上面例子中,我们查询 SQLite 系统表(sqlite_master)检查 table 表是否存在。返回值是一个 cursor 对象,这个对象的方法可以迭代查询结果。 如果查询是动态的,使用这个方法就会非常复杂。
    例如,当你需要查询的列在程序编译的时候不能确定,这时候使用 query() 方法会方便很多。
    Regular Queries query() 方法用 SELECT 语句段构建查询。SELECT 语句内容作为 query() 方法的参数,比如:要查询的表名,要获取的字段名,WHERE 条件,包含可选的位置参数,去替代 WHERE 条件中位置参数的值,GROUP BY 条件,HAVING 条件。 除了表名,其他参数可以是 null。所以,以前的代码段可以可写成:
    String[] columns={"ID", "inventory"}; 
     
     String[] parms={"snicklefritz"}; 
     Cursor result=db.query("widgets", columns, "name=?",parms, null, null, null);   
     
    使用游标  
    不管你如何执行查询,都会返回一个 Cursor,这是 Android 的 SQLite 数据库游标,
    使用游标,你可以:
    通过使用 getCount() 方法得到结果集中有多少记录;
    通过 moveToFirst(), moveToNext(), 和 isAfterLast() 方法遍历所有记录;
    通过 getColumnNames() 得到字段名;
    通过 getColumnIndex() 转换成字段号;
    通过 getString(),getInt() 等方法得到给定字段当前记录的值;
    通过 requery() 方法重新执行查询得到游标;
    通过 close() 方法释放游标资源;
    例如,下面代码遍历 mytable 表
    Cursor result=db.rawQuery("SELECT ID, name, inventory FROM mytable");     
    result.moveToFirst(); 
        while (!result.isAfterLast()) { 
            int id=result.getInt(0); 
            String name=result.getString(1); 
            int inventory=result.getInt(2); 
            // do something useful with these 
            result.moveToNext(); 
          } 
     
     result.close();
    在 Android 中使用 SQLite 数据库管理工具 在其他数据库上作开发,一般都使用工具来检查和处理数据库的内容,而不是仅仅使用数据库的 API。 
    使用 Android 模拟器,有两种可供选择的方法来管理数据库。
    首先,模拟器绑定了 sqlite3 控制台程序,可以使用 adb shell 命令来调用他。只要你进入了模拟器的 shell,在数据库的路径执行 sqlite3 命令就可以了。
    数据库文件一般存放在: /data/data/your.app.package/databases/your-db-name 如果你喜欢使用更友好的工具,你可以把数据库拷贝到你的开发机上,使用 SQLite-aware 客户端来操作它。这样的话,你在一个数据库的拷贝上操作,如果你想要你的修改能反映到设备上,你需要把数据库备份回去。
    把数据库从设备上考出来,你可以使用 adb pull 命令(或者在 IDE 上做相应操作)。
    存储一个修改过的数据库到设备上,使用 adb push 命令。 一个最方便的 SQLite 客户端是 FireFox SQLite Manager 扩展,它可以跨所有平台使用。

    使用ContentProvider存储数据

    第四种: 使用ContentProvider存储数据

    Android这个系统和其他的操作系统还不太一样,我们需要记住的是,数据在Android当中是私有的,当然这些数据包括文件数据和数据库数据以及一些其他类型的数据。那这个时候有读者就会提出问题,难道两个程序之间就没有办法对于数据进行交换?Android这么优秀的系统不会让这种情况发生的。解决这个问题主要靠ContentProvider。一个Content Provider类实现了一组标准的方法接口,从而能够让其他的应用保存或读取此Content Provider的各种数据类型。也就是说,一个程序可以通过实现一个Content Provider的抽象接口将自己的数据暴露出去。外界根本看不到,也不用看到这个应用暴露的数据在应用当中是如何存储的,或者是用数据库存储还是用文件存储,还是通过网上获得,这些一切都不重要,重要的是外界可以通过这一套标准及统一的接口和程序里的数据打交道,可以读取程序的数据,也可以删除程序的数据,当然,中间也会涉及一些权限的问题。 

    一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据完全暴露出去,而且ContentProviders是以类似数据库中表的方式将数据暴露,也就是说ContentProvider就像一个“数据库”。那么外界获取其提供的数据,也就应该与从数据库中获取数据的操作基本一样,只不过是采用URI来表示外界需要访问的“数据库”。 

    Content Provider提供了一种多应用间数据共享的方式,比如:联系人信息可以被多个应用程序访问。

    Content Provider是个实现了一组用于提供其他应用程序存取数据的标准方法的类。 应用程序可以在Content Provider中执行如下操作: 查询数据 修改数据 添加数据 删除数据

    标准的Content Provider: Android提供了一些已经在系统中实现的标准Content Provider,比如联系人信息,图片库等等,你可以用这些Content Provider来访问设备上存储的联系人信息,图片等等。

     

    查询记录:  

    在Content Provider中使用的查询字符串有别于标准的SQL查询。很多诸如select, add, delete, modify等操作我们都使用一种特殊的URI来进行,这种URI由3个部分组成, “content://”, 代表数据的路径,和一个可选的标识数据的ID。

    以下是一些示例URI:

    content://media/internal/images 这个URI将返回设备上存储的所有图片

    content://contacts/people/ 这个URI将返回设备上的所有联系人信息

    content://contacts/people/45 这个URI返回单个结果(联系人信息中ID为45的联系人记录)

    尽管这种查询字符串格式很常见,但是它看起来还是有点令人迷惑。为此,Android提供一系列的帮助类(在android.provider包下),里面包含了很多以类变量形式给出的查询字符串,这种方式更容易让我们理解一点,参见下例:

    MediaStore.Images.Media.INTERNAL_CONTENT_URI Contacts.People.CONTENT_URI

    因此,如上面content://contacts/people/45这个URI就可以写成如下形式:

    Uri person = ContentUris.withAppendedId(People.CONTENT_URI, 45);

    然后执行数据查询: Cursor cur = managedQuery(person, null, null, null);

     

    这个查询返回一个包含所有数据字段的游标,我们可以通过迭代这个游标来获取所有的数据:

    package com.wissen.testApp;public class ContentProviderDemo extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
           displayRecords();
        }

        private void displayRecords() {
            //该数组中包含了所有要返回的字段
         String columns[] = new String[] { People.NAME, People.NUMBER };
           Uri mContacts = People.CONTENT_URI;
           Cursor cur = managedQuery(
               mContacts,
              columns,  // 要返回的数据字段
           null,          // WHERE子句
           null,         // WHERE 子句的参数
           null         // Order-by子句
         );
           if (cur.moveToFirst()) {
               String name = null;
               String phoneNo = null;
               do {
                  // 获取字段的值
             name = cur.getString(cur.getColumnIndex(People.NAME));
                 phoneNo = cur.getString(cur.getColumnIndex(People.NUMBER));
                 Toast.makeText(this, name + ” ” + phoneNo, Toast.LENGTH_LONG).show();
              } while (cur.moveToNext());
           }
        }

     

    上例示范了一个如何依次读取联系人信息表中的指定数据列name和number。 

     

    修改记录:  

    我们可以使用ContentResolver.update()方法来修改数据,我们来写一个修改数据的方法:

        private void updateRecord(int recNo, String name) {

        Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, recNo);
        ContentValues values = new ContentValues();
        values.put(People.NAME, name);
        getContentResolver().update(uri, values, null, null);

    }  

    现在你可以调用上面的方法来更新指定记录: updateRecord(10, ”XYZ”); //更改第10条记录的name字段值为“XYZ”  

     

    添加记录:

    要增加记录,我们可以调用ContentResolver.insert()方法,该方法接受一个要增加的记录的目标URI,以及一个包含了新记录值的Map对象,调用后的返回值是新记录的URI,包含记录号。

    上面的例子中我们都是基于联系人信息簿这个标准的Content Provider,现在我们继续来创建一个insertRecord() 方法以对联系人信息簿中进行数据的添加:

     private void insertRecords(String name, String phoneNo) {

        ContentValues values = new ContentValues();
        values.put(People.NAME, name);
        Uri uri = getContentResolver().insert(People.CONTENT_URI, values);
        Log.d(”ANDROID”, uri.toString());
        Uri numberUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY);
        values.clear();
        values.put(Contacts.Phones.TYPE, People.Phones.TYPE_MOBILE);
        values.put(People.NUMBER, phoneNo);
        getContentResolver().insert(numberUri, values);

    }  


    这样我们就可以调用insertRecords(name, phoneNo)的方式来向联系人信息簿中添加联系人姓名和电话号码。  

     

    删除记录:

    Content Provider中的getContextResolver.delete()方法可以用来删除记录。

    下面的记录用来删除设备上所有的联系人信息:

    private void deleteRecords() {

    Uri uri = People.CONTENT_URI;

    getContentResolver().delete(uri, null, null);

    }

     

    你也可以指定WHERE条件语句来删除特定的记录:

    getContentResolver().delete(uri, “NAME=” + “‘XYZ XYZ’”, null);

    这将会删除name为‘XYZ XYZ’的记录。

    创建Content Provider:  

    至此我们已经知道如何使用Content Provider了,现在让我们来看下如何自己创建一个Content Provider。

    要创建我们自己的Content Provider的话,我们需要遵循以下几步:

    1. 创建一个继承了ContentProvider父类的类

    2. 定义一个名为CONTENT_URI,并且是public static final的Uri类型的类变量,你必须为其指定一个唯一的字符串值,最好的方案是以类的全名称,

    如: public static final Uri CONTENT_URI = Uri.parse( “content://com.google.android.MyContentProvider”);

    3. 创建你的数据存储系统。大多数Content Provider使用Android文件系统或SQLite数据库来保持数据,但是你也可以以任何你想要的方式来存储。

    4. 定义你要返回给客户端的数据列名。如果你正在使用Android数据库,则数据列的使用方式就和你以往所熟悉的其他数据库一样。但是,你必须为其定义一个叫_id的列,它用来表示每条记录的唯一性。

    5. 如果你要存储字节型数据,比如位图文件等,那保存该数据的数据列其实是一个表示实际保存文件的URI字符串,客户端通过它来读取对应的文件数据,处理这种数据类型的Content Provider需要实现一个名为_data的字段,_data字段列出了该文件在Android文件系统上的精确路径。这个字段不仅是供客户端使用,而且也可以供ContentResolver使用。客户端可以调用ContentResolver.openOutputStream()方法来处理该URI指向的文件资源,如果是ContentResolver本身的话,由于其持有的权限比客户端要高,所以它能直接访问该数据文件。

    6. 声明public static String型的变量,用于指定要从游标处返回的数据列。

    7. 查询返回一个Cursor类型的对象。所有执行写操作的方法如insert(), update() 以及delete()都将被监听。我们可以通过使用ContentResover().notifyChange()方法来通知监听器关于数据更新的信息。

    8. 在AndroidMenifest.xml中使用标签来设置Content Provider。

    9. 如果你要处理的数据类型是一种比较新的类型,你就必须先定义一个新的MIME类型,以供ContentProvider.geType(url)来返回。

    MIME类型有两种形式:

    一种是为指定的单个记录的,还有一种是为多条记录的。这里给出一种常用的格式: vnd.android.cursor.item/vnd.yourcompanyname.contenttype (单个记录的MIME类型) 比如, 一个请求列车信息的URI如content://com.example.transportationprovider/trains/122 可能就会返回typevnd.android.cursor.item/vnd.example.rail这样一个MIME类型。

    vnd.android.cursor.dir/vnd.yourcompanyname.contenttype (多个记录的MIME类型) 比如, 一个请求所有列车信息的URI如content://com.example.transportationprovider/trains 可能就会返回vnd.android.cursor.dir/vnd.example.rail这样一个MIME 类型。

    下列代码将创建一个Content Provider,它仅仅是存储用户名称并显示所有的用户名称(使用 SQLLite数据库存储这些数据):

    package com.wissen.testApp;public class MyUsers {
        public static final String AUTHORITY  = “com.wissen.MyContentProvider”;

        // BaseColumn类中已经包含了 _id字段
       public static final class User implements BaseColumns {
            public static final Uri CONTENT_URI  = Uri.parse(”content://com.wissen.MyContentProvider”);
            // 表数据列
         public static final String  USER_NAME  = “USER_NAME”;
        }

    }  


    上面的类中定义了Content Provider的CONTENT_URI,以及数据列。下面我们将定义基于上面的类来定义实际的Content Provider类: 

    package com.wissen.testApp.android;public class MyContentProvider extends ContentProvider {
        private SQLiteDatabase     sqlDB;
        private DatabaseHelper    dbHelper;
        private static final String  DATABASE_NAME     = “Users.db”;
        private static final int        DATABASE_VERSION         = 1;
        private static final String TABLE_NAME   = “User”;
        private static final String TAG = “MyContentProvider”;

        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 ” + TABLE_NAME + “( _id INTEGER PRIMARY KEY AUTOINCREMENT, USER_NAME TEXT);”);
            }

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

        @Override
        public int delete(Uri uri, String s, String[] as) {
            return 0;
        }

        @Override
        public String getType(Uri uri) {
            return null;
        }

        @Override
        public Uri insert(Uri uri, ContentValues contentvalues) {
            sqlDB = dbHelper.getWritableDatabase();
            long rowId = sqlDB.insert(TABLE_NAME, “”, contentvalues);
            if (rowId > 0) {
                Uri rowUri = ContentUris.appendId(MyUsers.User.CONTENT_URI.buildUpon(), rowId).build();
                getContext().getContentResolver().notifyChange(rowUri, null);
                return rowUri;
            }
            throw new SQLException(”Failed to insert row into ” + uri);
        }

        @Override
        public boolean onCreate() {
            dbHelper = new DatabaseHelper(getContext());
            return (dbHelper == null) ? false : true;
        }

        @Override
        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
            SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
            SQLiteDatabase db = dbHelper.getReadableDatabase();
            qb.setTables(TABLE_NAME);
            Cursor c = qb.query(db, projection, selection, null, null, null, sortOrder);
            c.setNotificationUri(getContext().getContentResolver(), uri);
            return c;
        }

        @Override
        public int update(Uri uri, ContentValues contentvalues, String s, String[] as) {
            return 0;
        }

    }  

    一个名为MyContentProvider的Content Provider创建完成了,它用于从Sqlite数据库中添加和读取记录。 

    Content Provider的入口需要在AndroidManifest.xml中配置:

    之后,让我们来使用这个定义好的Content Provider: 

    package com.wissen.testApp;public class MyContentDemo extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            insertRecord(”MyUser”);
            displayRecords();
        }
       
        private void insertRecord(String userName) {
            ContentValues values = new ContentValues();
            values.put(MyUsers.User.USER_NAME, userName);
            getContentResolver().insert(MyUsers.User.CONTENT_URI, values);
        }

        private void displayRecords() {
            String columns[] = new String[] { MyUsers.User._ID, MyUsers.User.USER_NAME };
            Uri myUri = MyUsers.User.CONTENT_URI;
            Cursor cur = managedQuery(myUri, columns,null, null, null );
            if (cur.moveToFirst()) {
                String id = null;
                String userName = null;
                do {
                    id = cur.getString(cur.getColumnIndex(MyUsers.User._ID));
                    userName = cur.getString(cur.getColumnIndex(MyUsers.User.USER_NAME));
                    Toast.makeText(this, id + ” ” + userName, Toast.LENGTH_LONG).show();
               } while (cur.moveToNext());
           }
        }

     

    上面的类将先向数据库中添加一条用户数据,然后显示数据库中所有的用户数据。 

     

    第五种: 网络存储数据

    前面介绍的几种存储都是将数据存储在本地设备上,除此之外,还有一种存储(获取)数据的方式,通过网络来实现数据的存储和获取。

    我们可以调用WebService返回的数据或是解析HTTP协议实现网络数据交互。

    具体需要熟悉java.net.*,Android.net.*这两个包的内容,在这就不赘述了,请大家参阅相关文档。

    下面是一个通过地区名称查询该地区的天气预报,以POST发送的方式发送请求到webservicex.net站点,访问WebService.webservicex.net站点上提供查询天气预报的服务。

    代码如下:

    package com.android.weather; 
    import java.util.ArrayList;
    import java.util.List;

    import org.apache.http.HttpResponse;
    import org.apache.http.NameValuePair;
    import org.apache.http.client.entity.UrlEncodedFormEntity;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.apache.http.message.BasicNameValuePair;
    import org.apache.http.protocol.HTTP;
    import org.apache.http.util.EntityUtils;

    import android.app.Activity;
    import android.os.Bundle;

    public class MyAndroidWeatherActivity extends Activity {
        //定义需要获取的内容来源地址
        private static final String SERVER_URL = 
            "http://www.webservicex.net/WeatherForecast.asmx/GetWeatherByPlaceName"; 
        
        
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            
            HttpPost request = new HttpPost(SERVER_URL); //根据内容来源地址创建一个Http请求
            // 添加一个变量 
            List<NameValuePair> params = new ArrayList<NameValuePair>(); 
            // 设置一个地区名称
            params.add(new BasicNameValuePair("PlaceName", "NewYork"));  //添加必须的参数
            
            
            try { 
                //设置参数的编码
                request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8)); 
                //发送请求并获取反馈
                HttpResponse httpResponse = new DefaultHttpClient().execute(request);
                 
                // 解析返回的内容
                if(httpResponse.getStatusLine().getStatusCode() != 404){ 
                   String result = EntityUtils.toString(httpResponse.getEntity()); 
                   System.out.println(result);
                }
            } catch (Exception e) {
                e.printStackTrace();
           } 
        }
    }

     

     别忘记了在配置文件中设置访问网络权限:

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








    展开全文
  • 安卓的五种存储方式

    2020-12-04 11:02:18
    安卓存储方式5种,分别为: SharedPrefences; SQLite数据库 文件存储 网络存储 ContentProvider 1. 数据存储的类型和存放位置 应用程序一般有一下几种类型: file-普通的文件存储 database-数据库...
  • 安卓种存储方式入门

    千次阅读 2016-03-14 13:27:26
    本文介绍Android中的5种数据存储方式。数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是: 1 使用SharedPreferences存储数据 2 文件存储数据 3 SQLite数据库存储数据 ...
  • 我在网上看到很多篇关于安卓数据保存的文章,大概知道有哪几种方式,但是现在的情况令我不知道怎么选择,希望各位给点建议! 情况是: 我需要1秒内保存3~5数据,每段数据都是字符串而且没有固定长度,一共会...
  • 在android手机存储数据和文件的方式分为五:1.文件存储(sd卡中)、2.采用共享参数(sharedpreferences)的方式存储、3.SQLite数据库存储、4.使用内容提供者(Content Provider)存储5.存放在网络的服务器端。...
  • 安卓文件存储

    2021-02-17 17:35:47
    安卓中的数据存储方式5种,分别是文件存储、SharedPreferences、Sqlite数据库、ContentProvider以及网络存储 SharedPreferences是安卓平台上一个轻量级的存储类。用于存储一些应用程序的配置参数,例如用户名、...
  • 数据存储5种方式 使用API Guide学习数据存储的五大存储方式。--面试的时候会问的 Shared Preferences(共享参数): 使用键值对的形式去存储私有数据,这种数据只有当前应用可以访问,其他应用无法访问。(数据是以...
  • Android为数据存储提供了五种方式: 1、SharedPreferences 2、文件存储 3、SQLite数据库 4、ContentProvider 5、网络存储 安卓的网络存储比较简单,因为Android提供的 Uri 和 Intent 可以帮助我们完成...
  • (1)在Android的持久化技术中,文件存储是最基本的一种数据存储方式。 (2)对存储的内容部做任何处理,原样存储到文件中。 (3)Context提供了文件写入与读取的方法,openFileOutput:写入到文件;openFileInput...
  • Android 文件存储

    2021-01-24 10:51:31
    安卓中的数据存储方式5种,分别是文件存储、SharedPreferences、Sqlite数据库、ContentProvider以及网络存储 SharedPreferences是安卓平台上一个轻量级的存储类。用于存储一些应用程序的配置参数,例如用户名、...
  • 安卓笔记7

    2017-01-15 09:41:29
    1这周我们学习了数据库存储方式,在Android中一共提供了5种数据存储方式,分别为: (1)Files:通过FileInputStream和FileOutputStream对文件进行操作。 (2)SharedPreferences:常用来存储键值对形式的数据,对...
  • 如何学习安卓

    2014-06-28 22:46:12
    搭建好开发环境以后,学习安卓5种布局和常用控件的使用以及自定义一些效果,同时学习四大组件,然后学习数据存储方式,sharedprafernce,file,sqltite,网络存储,应用之间数据共享contentprovider,以及数据解析...
  • 搭建好开发环境以后,学习安卓5种布局和常用控件的使用以及自定义一些效果,同时学习四大组件,然后学习数据存储方式,sharedprafernce,file,sqltite,网络存储,应用之间数据共享contentprovider,以及数据解析...
  • 要求达到效果:使安卓上的系统能够进行...参考网址:http://blog.csdn.net/xjbclz/article/details/53046306,里面讲解了5种存储方式。 1.1 1.2 1.3 SQLite数据库的使用。这个感觉比较符合要求。可以进行使用。 ...
  • 初级安卓程序试题

    千次阅读 2016-02-23 21:32:44
    填空题 1.android中常用的四个布局是:____,____,____和____. 2.android的四大组件是:____,____,____和____. 3.java.io包中的____和____类主要用于对对象...5.android的数据存储方式是:____,____,____和____
  • 黑马安卓52期视频教程

    热门讨论 2015-06-24 22:15:48
    day02_Android应用开发-数据存储和界面展现 00_剧情回顾 01_线性布局 02_相对布局 03_帧布局 04_表格布局 05_绝对布局 06_logcat输出 07_在内部存储中写文件 08_在内部存储中读文件 09_使用路径API获取内部存储的...
  • java常见问题

    2021-02-02 14:06:22
    2、安卓五大存储方式 1、SharedPreference: 适用于存储少量数据,以key+value形式存储数据,存储的数据以xml文件的形式存储于设备 2、ContentProvider 进程之间进行数据的共享,即跨进程通信 ContentProvider的简单...
  • (2)针对跨域数据交互问题,指出并分析了跨域缓存交互问题出现的原因,通过在HTML5存储技术的基础上,重写LocalStorage,用移动端本地的Sqlite进行数据维护,实现跨域数据交互。 (3)针对页面自适应问题,本文结合...
  • 但是在安卓webview中却出现了<code>localStorage无法向移动的磁盘写数据的问题。最后通过网络搜索发现。在安卓上webview是默认不开启<code>localStorage想磁盘写文件的权限的。所以如果需要使用<code>localStorage的...
  • 扩展模块:新增用户扩展数据存储、备注; 调用模块:帖子调用、会员排行; 日志模块:接口日志: 提现模块:申请提现、后台打款; 用户组模块:购买、充值、切换; 论坛模块:列表、发帖、回帖 排行模块:会员...
  • 本地数据存储支持sqlite+mysql,支持远程数据同步到云端数据库。自动重连。 本地设备采集到的数据实时上传到云端,以便手机APP或者web等其他方式提取。 支持两种数据源,一种是串口和网络通过协议采集设备数据,一种...
  • 数据存储量 在线模式数据实时上传,离线消费记录数最多2万(离线消费记录数可扩展) 工作模式 在线模式与离线应急模式并存 支持加密算法 3DES,DES,RSA,MDS,SH1,SH2 内存 16M(可以扩展64M) 系统升级 支持GPRS,...
  • 作者简介:丰生强(网名非虫),Android软件安全专家,看雪论坛Android安全版版主,安卓巴士开发交流版版主。 目录 第1章 Android程序分析环境搭建 1.1 Windows分析环境搭建 1.1.1 安装JDK 1.1.2 安装Android SDK ...
  • 基础5 ElasticsSearch 多种搜索方式 基础6 ElasticSearch 嵌套聚合,下钻分析,聚合分析 基础7 Elasticsearch的基础分布式架构 基础8 ElasticSearch shard replica机制 基础9 ElasticSearch document及...
  • Android应用开发揭秘--详细书签版

    热门讨论 2012-12-12 13:27:46
     本书内容全面,不仅详细讲解了android框架、android组件、用户界面开发、游戏开发、数据存储、多媒体开发和网络开发等基础知识,而且还深入阐述了传感器、语音识别、桌面组件 开发、android游戏引擎设计、android...
  • 1、 新增安卓Android手机APP客户端程序,支持目前市面上流行的Android 2.1及以上版本;客户端程序主要面向个人求职者使用,目前具备以下功能; a.个人会员注册、登录和修改密码; b.提供关键字和更多条件搜索职位,...

空空如也

空空如也

1 2
收藏数 36
精华内容 14
关键字:

安卓5种数据存储方式