Android中的数据存储方式

本文介绍了Android应用程序中的多种数据存储方式,包括使用SharedPreferences进行简单的配置信息存储、文件存储、SQLite数据库存储以及ContentProvider等内容。

所有的应用程序都必然涉及数据的输入输出,Android中我们用以下几种方法来进行数据存储。

使用SharedPreferences存储数据;

当应用程序有少量的数据要保存,并且这些数据的格式简单。我们就会用到sharedpreferences来保存,比如程序的各种配置信息等。其中保存的形式为 “key-value”的键值对。

获取SharedPreferences

SharedPreferences本身是一个接口,只能通过Context 提供的 getSharedPreferences(String name,int mode) 方法来获取SharedPreferences实例。
mode 有以下几种常用的:
1. Context.MODE_PRIVATE : 数据只能被本应用读、写
2. Context.MODE_WORLD_READABLE: 数据可以被其他应用读,但不能写
3. Context.MODE_WORLD_WRITEABLE 数据可以被其他应用读、写等。

SharedPreferences位置与格式

SharedPreferences数据保存在 data/data/包名/shared_prefs 目录下, 以XML形式保存。

读取数据

SharedPreferences 接口主要负责读取应用程序的Preferences数据。他提供了以下几个常用方法来访问SharedPreferences中的key-value。
1. boolean contains(String key) :判断SharedPreferences中是否包含特定的key的值
2. abstract Map< String ,?> getAll(): 获取SharedPreferences中的全部的key-value
3. boolean getXXX(String key,xxx defaultValue) :获取指定key对应的value ,如果不存在 则返回 defaultValue,其中的XXX 为int ,string,boolean,float ,double,long 等基本类型。

写入数据

我们可以通过SharedPreferences调用edit()方法 获取 Editor对象,Editor对象提供了以下几个方法来写入数据

  1. SharedPreferences.Editor clear() : 清空SharedPreferences中的所有数据
  2. SharedPreferences.Editor putXXX(String key,XXX value) 存入指定的key 对应的数据。
  3. boolean commit() 当Editor 编辑完成后,调用此方法提交修改。现在建议用 apply()方法提交

实例

布局文件:

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

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:hint="name" />


    <Button
        android:id="@+id/btn_submit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="提交" />

    <Button
        android:id="@+id/btn_clean"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="清空" />

</LinearLayout>

操作代码为:

public class AddActivity extends AppCompatActivity {
    private TextView mShow;
    private Button mSubmit;
    private Button mClean;
    SharedPreferences sp;
    //几个key
    private final String USER_NAME = "user_name";
    private final String USER_AGE = "user_age";
    private final String USER_SEX = "user_sex";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add);
        initViews();
    }

    private void initViews() {
        mSubmit = (Button) findViewById(R.id.btn_submit);
        mShow = (TextView) findViewById(R.id.tv_name);
        mClean = (Button) findViewById(R.id.btn_clean);
        /**如果要在其他程序中访问本程序的sp,则要修改此处的Mode*/
        sp = getSharedPreferences("table_name", Context.MODE_PRIVATE);
        /**当sp中的值改变之后时回调此方法*/
        sp.registerOnSharedPreferenceChangeListener(new SharedPreferences.OnSharedPreferenceChangeListener() {
            @Override
            public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
                Toast.makeText(AddActivity.this, "改变的key为:" + key, Toast.LENGTH_SHORT).show();
            }
        });

        /**如果没有key对应的值,则插入新值,会回调监听方法*/
        if (!sp.contains(USER_NAME)) {//如果没有user_name  则插入user_name
            sp.edit().putString(USER_NAME, "遗憾").apply();
        }
        if (!sp.contains(USER_SEX)) {//如果没有user_name  则插入user_name
            sp.edit().putString(USER_SEX, "男").apply();
        }
        if (!sp.contains(USER_AGE)) {//如果没有user_name  则插入user_name
            sp.edit().putInt(USER_AGE, 25).apply();
        }

        mSubmit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mShow.setText(sp.getAll().toString());
            }
        });

        mClean.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sp.edit().clear().apply();
                Toast.makeText(AddActivity.this, "清空了", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

我们将上面getSharedPreferences中的mode 改为Context.MODE_WORLD_READABLE
然后我们新建一个程序,来读取上述程序中的SharedPreferences。
我们在我们新建的程序中添加以下代码:

  Context userTable = null;
        try {
            userTable = createPackageContext("要访问的sp所在的包名", Context.CONTEXT_IGNORE_SECURITY);
            SharedPreferences sp = userTable.getSharedPreferences("sp的文件名", Context.MODE_WORLD_READABLE);
            TextView mTextView = (TextView) findViewById(R.id.tv);
            mTextView.setText(sp.getAll().toString());
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }

文件存储数据;

打开应用程序的数据文件夹下的文件

Android中支持通过FileInputStream 、FileOutputStream 来访问文件内容。
Context提供了两个方法来打开文件的IO流:

FileInputStream openFileInput(String name):打开应用程序的数据文件夹下的name文件对应输入流

FileOutputStream openFileOutput(String name,int mode) : 打开应用程序的数据文件夹下的name文件对应的输出流

int mode 的几种类型:
1. MODE_PRIVATE 该文件只能被当前程序读写
2. MODE_APPEND 以追加的方式打开文件,应用程序可以向该文件中追加内容。
3. MODE_WORLD_READABLE: 该文件可由其他应用程序读。
4. MODE_WORLD_WRITEABLE 该文件可由其他应用程序读、写。

Context中的几个方法:
1. getDir(String name,int mode) 在应用程序的文件夹下创建或者获取name对应的子目录
2. File getFilesDir() 获取该应用程序下的数据文件夹的绝对路径
3. String [] fileList () 返回该应用程序文件夹下的所有文件
4. deleteFile (String xx) 删除该应该程序下的指定文件

文件形式保存到 data/data/包名/files 目录下。

测试实例:

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

    <TextView
        android:id="@+id/tv_name"
        android:layout_width="match_parent"
        android:layout_height="50dp"
         />

    <Button
        android:id="@+id/btn_write"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="写入" />

    <Button
        android:id="@+id/btn_read"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="读取" />

</LinearLayout>
public class AddActivity extends AppCompatActivity implements View.OnClickListener {
    private TextView mShow;
    private Button mWrite;
    private Button mRead;
    private String detail = "指定写入的内容";
    private final String FILE_NAME = "my_data.txt";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add);
        initViews();
    }

    private void initViews() {
        mWrite = (Button) findViewById(R.id.btn_write);
        mShow = (TextView) findViewById(R.id.tv_name);
        mRead = (Button) findViewById(R.id.btn_read);

        mWrite.setOnClickListener(this);
        mRead.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_write:
                write(detail);
                break;
            case R.id.btn_read:
                read();
                mShow.setText(read());
                break;
        }
    }

    /**
     * 读取内容
     */
    @Nullable
    private String read() {
        try {
            FileInputStream fis = openFileInput(FILE_NAME);
            byte[] buff = new byte[1024];
            int hasRead = 0;
            StringBuilder sb = new StringBuilder("");
            while ((hasRead = fis.read(buff)) > 0) {
                sb.append(new String(buff, 0, hasRead));
            }
            return sb.toString();
        } catch (java.io.IOException e) {
            e.printStackTrace();
        }
        return null;

    }

    /**
     * 写入内容
     */
    private void write(String detail) {
        try {
            FileOutputStream fos = openFileOutput(FILE_NAME, MODE_APPEND);
            PrintStream ps = new PrintStream(fos);
            ps.println(detail);
            ps.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }
}

打开手机SD卡中的文件:

为了更好的存取应用程序的大文件数据,应用程序需要读、写SD卡中的文件。
读写SD卡文件的步骤:
1. 调用Environment 的 getExternalStorageState()方法判断是否有SD卡,并且程序具有读写sd卡的权限 。
//如果有sd卡,并且有读写权限则下面语句返回true
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
2. Environment.getExternalStorageDirectory() 来获取sd卡的目录
3. 用 FileInputStream 、FileOutputStream、FileReader、FileWriter读、写SD卡中的文件。
4. 读写SD卡需要特定的权限才可以正常的操作。

我们往SD卡中的特定文件中写内容

 /**
     * 写入内容
     */
    private void write(String detail) {
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            File sdcardDir = Environment.getExternalStorageDirectory();//获取外置sd卡路径
            try {
                File f = new File(sdcardDir.getCanonicalFile() + File.separator + FILE_NAME);
                //判断f是否已经创建了
                if (!f.exists()) {
                    try {
                        //没有创建,则创建
                        f.getParentFile().mkdirs();
                        f.createNewFile();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                //以指定文件创建RandomAccessFile
                RandomAccessFile raf = new RandomAccessFile(f, "rw");
                raf.seek(f.length());
                raf.write(detail.getBytes());
                raf.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

读我们写入的内容

 /**
     * 读取内容
     */
    @Nullable
    private String read() {
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            File sdDir = Environment.getExternalStorageDirectory();
            try {
                //获取指定文件对应的输入流
                FileInputStream fis = new FileInputStream(sdDir.getCanonicalFile() + File.separator + FILE_NAME);
                //将输入流包装成BufferReader
                BufferedReader btr = new BufferedReader(new InputStreamReader(fis));
                StringBuilder sb = new StringBuilder("");
                String line = null;
                while ((line = btr.readLine()) != null) {
                    sb.append(line);
                }
                return sb.toString();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;

    }

需要的权限

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

读取SD卡中的所有文件:

 private void searchAndShow() {
        File file = new File("/mnt/sdcard/");
        if (file.exists()) {
            fileList = file.listFiles();
        }
        if (fileList != null) {
            adapter = new MyAdapter(this, fileList);
            mListView.setAdapter(adapter);
        }
        /**
         * 点击事件
         * */
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (fileList[position].isFile()) {
                    return;
                }
                File[] temp = fileList[position].listFiles();
                if (temp.length == 0 || temp == null) {
                    Toast.makeText(AddActivity.this, "此文件为空", Toast.LENGTH_SHORT).show();
                    //跳转一个空的Activity
                    startActivity(new Intent(AddActivity.this,EmptyActivity.class));
                }else {
                    currentParent = fileList[position];
                    adapter = new MyAdapter(AddActivity.this,temp);
                    mListView.setAdapter(adapter);
                }
            }
        });
    }

添加一个返回按钮:

 Button mBack = (Button) findViewById(R.id.btn_back);
        mBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    if (!currentParent.getCanonicalPath().equals("/mnt/sdcard")){
                        currentParent = currentParent.getParentFile();
                        adapter = new MyAdapter(AddActivity.this,currentParent.listFiles());
                        mListView.setAdapter(adapter);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        });

适配器:

public class MyAdapter extends BaseAdapter {
   File [] fileList;
    Context mContext;

    public MyAdapter(Context mContent, File[] fileList) {
        this.mContext = mContent;
        this.fileList = fileList;
    }

    @Override
    public int getCount() {
        return fileList.length;
    }

    @Override
    public Object getItem(int i) {
        return fileList[i];
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder holder = null;
        if (view == null) {
            view = LayoutInflater.from(mContext).inflate(R.layout.item, null);
            holder = new ViewHolder();
            holder.tv_name = (TextView) view.findViewById(R.id.item_name);
            view.setTag(holder);
        } else {
            holder = (ViewHolder) view.getTag();
        }
        holder.tv_name.setText(fileList[i].getName());

        return view;
    }

    class ViewHolder {
        TextView tv_name;
    }
}

SQLite数据库存储数据;

http://blog.youkuaiyun.com/qq_27561483/article/details/52610686

使用ContentProvider存储数据;

网络存储数据;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值