SharedPreferences与Editor

SharedPreferences保存的数据只要是类似于配置信息格式的数据,因此它保存的数据主要是简单的key-value对形式。下面关系图


上图完全可以看出,存的时候用SharedPreferences的内部类Editor,取的时候用SharedPreferences。

SharedPreference是接口无法创建实例,Context提供下面方法创建实例 该实例只能有一个,也就是单例模式。

getSharedPreferences(String name,int mode);


存取例子

 public class MainActivity extends Activity { SharedPreferences sp;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//获取SharedPreferences实例  Test是文件名,不要加后缀,默认为XML格式sp = getSharedPreferences("Test", Context.MODE_WORLD_WRITEABLE);//得到内部类写数据SharedPreferences.Editor editor = sp.edit();editor.putString("name", "value");//不提交则无法获得数据editor.commit();}public void btn(View view){String string = sp.getString("name", "null");Toast.makeText(this, string, 1).show();}}
存储路径为:data/data/包名/shared_prefs/Test.xml

打开该文件看到

<?xml version="1.0" encoding="utf-8" standalone ="yes" ?><map><string name="name">value</string></map>

存储的放值的时候String对应XML文件里就是string节点,Int的时候对应int节点。

存储时长:卸载软件时包名所在的文件夹会消失,所以该文件无法同样会消失。


读写其他应用的SharedPreferences

上述是在本身的APP中玩耍,这次看如何读取其他应用,关键是获得其他应用的程序的Context(代表Android应用的全局信息的接口)又因为包名是Andoird应用的唯一标示,所以调用本APP的Context的方法

createPackageContext("android.example.homework", CONTEXT_IGNORE_SECURITY);

得到其他应用的Context对象并且其他应用SharedPreferences是可读状态(可写不行,必须可读)后就可以“为所欲为”了。

public class MainActivity extends Activity {SharedPreferences sp;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 获取SharedPreferences实例try {//通过包名得到该应用的Context对象Context context=createPackageContext("com.example.homework", CONTEXT_IGNORE_SECURITY);//用其他应用的Context创建SharedPreferencessp = context.getSharedPreferences("Test", Context.MODE_WORLD_READABLE+Context.MODE_WORLD_WRITEABLE);} catch (NameNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public void btn(View view) {String string = sp.getString("name", "null");Toast.makeText(this, string, 1).show();}}

上述的读写并不是唯一的,程序员完全可以利用IO流来直接操作本应用和其他应用的SharedPreferences数据,只是Android将他封装好了,很简便。

无法存储自定义类型,主要存储的APP配置信息,例如(用户名,密码等)。

Chche存储

存储空间不够系统会删除Cache存储,但不要依赖系统删除

存:

File dir = getCacheDir();File file = new File(dir,"test.txt");try {FileOutputStream fos = new FileOutputStream(file);fos.write("缓冲存储".getBytes());} catch (Exception e) {// TODO: handle exception}

取:

FileInputStream fis = new FileInputStream(file)

以上两种方式均为内部存储,卸载应用时数据都会丢失。


File存储

FIle存储就是Android继续使用Java中的IO流继续读写文件的一种方式

两个核心方法:

openFileInput(String name);

openFIleOutput(String name);

下面是简单读写的例子

public class MainActivity extends Activity {SharedPreferences sp;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}public void readed(View view) {FileInputStream fis = null;StringBuffer sb=null;try {//打开文件输入流     files文件名,这里系统不给添加后缀,不写无后缀fis = openFileInput("files");byte[] buff = new byte[1024];int len = 0;sb = new StringBuffer();while ((len = fis.read(buff)) != -1) {sb.append(new String(buff, 0, len));}//关流fis.close();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}Toast.makeText(this, sb, 0).show();}public void writer(View view) {FileOutputStream fos = null;try {// 以追加模式打开文件输出流fos = openFileOutput("files", MODE_APPEND);// 将流包装成PrintStreamPrintStream printStream = new PrintStream(fos);printStream.print("内容啦啦啦啦");Toast.makeText(this, "写入成功", 0).show();} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {if (fos != null)try {fos.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}

该文件无后缀,系统默认不添加后缀,存放路径为data/data/包名/file/文件夹下

该文件依然存放在包名下,所以卸载时依然会丢失数据。


SD卡存储

使用File存储和SharedPreferences存储的缺点是容量小,因为在应用程序的数据文件夹下。所以才有了SD卡存储。使用SD卡存储总共分为三步:

(1)判断应用是否有读写SD卡权限

Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
(2)获得SD卡的目录

File dir = Environment.getExternalStorageDirectory();
(3)使用流读写数据


SD卡的权限

<!-- 添加SD卡的创建与删除文件权限 --><uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/><!-- 添加SD卡写入权限 --><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

读写SD卡例子

public class MainActivity extends Activity {private final String FILE_NAME="test.txt";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}/**读取数据*/public void readed(View view) {BufferedReader bis=null;//当SD状态装备就绪时if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){File dir = Environment.getExternalStorageDirectory();try {File file = new File(dir, FILE_NAME);FileInputStream fis = new FileInputStream(file);//将fis流包装成BufferedReaderbis= new BufferedReader(new InputStreamReader(fis));String len = null;StringBuffer sb = new StringBuffer("");while((len=bis.readLine())!=null){sb.append(len);}Toast.makeText(this, "读到的数据是:"+sb, 0).show();} catch (Exception e) {e.printStackTrace();} finally{if(bis!=null){try {bis.close();} catch (IOException e) {e.printStackTrace();}}}}else Toast.makeText(this, "SD卡不可用", 0).show();}/**写入数据*/public void writer(View view) {RandomAccessFile raf = null;if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){File dir = Environment.getExternalStorageDirectory();File file = new File(dir, FILE_NAME);//用指定文件创建RandomAccessFIletry {raf = new RandomAccessFile(file, "rw");//将文件记录指针移动到最后  防止再次写入覆盖之前的raf.seek(file.length()); raf.write("来一个字符串玩玩".getBytes());Toast.makeText(this, "写入成功", 0).show();} catch (Exception e) {e.printStackTrace();}finally{if(raf!=null){try {raf.close();} catch (IOException e) {e.printStackTrace();}}}}}}

SQLite存储

SQLite是轻量级的数据库(底层就是一个数据库文件)一旦应用获得了代表指定数据库的SQLiteDatabase对象,接下来就可以通过该对象来管理,操作数据库了。

(1)获取SQLiteDatabase对象,它代表了与数据库的链接。

(2).调用SQLiteDatabase的方法来执行SQL语句。

(3).操作SQL语句的执行结果,比如用SimpleCursorAdapter封装Cursor

(4).关闭SQLiDatabase,回收资源。

常用方法

//创建(如果不存在)或打开数据库static SQLiteDatabase openOrCreateDatabase(String path, CursorFactory factory)
//打卡一个已经存在的数据库static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags)

MainActivity.java

public class MainActivity extends Activity {private ListView listview;private SQLiteDatabase db;private EditText editText;private String TABLE_NAME="student";//创建表语句private String CREATE_TABLE = "create table "+TABLE_NAME+" (_id integer primary key autoincrement,name varchar(20),age integer)";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//初始化editText = (EditText) findViewById(R.id.et);listview=(ListView) findViewById(R.id.listivew);//打开或创建数据库(这里需要绝对路径)db=SQLiteDatabase.openOrCreateDatabase("/mnt/sdcard/my.db3", null);if(!exits(TABLE_NAME)){db.execSQL(CREATE_TABLE);}}@Overrideprotected void onDestroy() {super.onDestroy();//关闭数据库if(db!=null&&db.isOpen())db.close();}public void btn(View view){switch (view.getId()) {case R.id.btn1://插入String str = editText.getText().toString();String sql = "insert into "+TABLE_NAME+" (name) values ('"+str+"') ";System.out.println(sql);db.execSQL(sql);break;case R.id.btn2://读取String sql2 = "select * from "+TABLE_NAME+"";Cursor cursor = db.rawQuery(sql2, null);inflateListView(cursor);break;}}public boolean exits(String table){String sql= "select * from sqlite_master where name="+"'"+table+"'";System.out.println(sql);Cursor cursor = db.rawQuery(sql, null);if(cursor.getCount()!=0){return true;}return false;}private void inflateListView(Cursor cursor){//构建Cursor适配器的同时就是对Cursor封装成为AdapterSimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_expandable_list_item_1, cursor, new String[]{"name"}, new int[]{android.R.id.text1},CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);listview.setAdapter(adapter);}}


activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/container"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <EditText        android:id="@+id/et"        android:layout_width="match_parent"        android:layout_height="wrap_content" />    <Button        android:id="@+id/btn1"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:onClick="btn"        android:text="插入 字符串数据" />    <Button        android:id="@+id/btn2"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:onClick="btn"        android:text="取出数据" />    <ListView        android:id="@+id/listivew"        android:layout_width="match_parent"        android:layout_height="wrap_content" >    </ListView></LinearLayout>

效果图:


由于是自定义的路径,所以卸载软件依然存在。这种直接使用SQLiteDatabase的方式使用的极少的。

注意:这里主键的列名必须为_id,因为SimpleCursorAdapter只能识别列名为_id的主键。

android还为我们提供操作数据库的一些便捷方法

insert方法

无论第三个参数是否有数据,执行该方法都会添加一条数据。

        //table插入的表名        //nullColumnHack强行插入为null列的列名 当values参数为null或不包含任意key-value对时该参数有效        //values代表一行记录的数据        insert(String table, String nullColumnHack, ContentValues values)
实际insert方法底层依然通过SQL语句来插入的,因为它生成的SQL语句总是形如下面的语句

//ContentValue里的key-value对的数量决定了下面的key-value对。insert into <表名>(key1,key2...)values(value1,value2....)
如果此时第三个参数为空

insert into <表名>()values()


updata方法

该方法返回的数据库影响的行数

//要更改数据库表名//更新完成后的值//满足whereClaues字句的记录将会被更新//用于为whereClause字句传入参数update(String table, ContentValues values, String whereClause, String[] whereArgs)
例如我们想更新person表中的所有主键大于20的人的人名,可调用如下方法:

ContentValues values = new ContentValues();//存放更新之后的人名values.put("name", "新人名"); db.update("person", values, "_id>?", new Integer[]{20});

对应SQL语句

updata person set key1=value1,key2=value2...where _id>20


delete方法

返回值更改的行数

//table表名,whereClause删除的条件 ,whereArgs给whereClause传入删除的参数delete(String table, String whereClause, String[] whereArgs)
例如:想删除person表中所有人名以王字开头的记录

db.delete("person","name like?",new String[]{"王%"});
对应SQl语句

delete person where name like '王%'


query方法

//distinct指定是否去除重复记录//table 执行查询数据的表名//columns要查询出来的列名//selection查询条件的字句 相当于select语句where关键字后面的部分,//selectionArgs查询语句匹配的参数//groupBy用于控制分组,//having 对分组进行过滤//orderBy 排序,personid desc降序,age asc升序;//limit 进行分页 例如:5,10db.query(distinct, table, columns, selection, selectionArgs, groupBy, having, orderBy, limit, cancellationSignal);


db.query("person", new String[]{"_id,name,age"}, "name like ?", new String[]{"张%"}, null, null, "desc", null);

SQLiteOpenHelper

这种继承SQLiteOpenHelper方式用的还是比较多的。它是Android提供的一个管理数据库的工具类,可用于管理数据库的创建的版本和更新。

常用方法:

synchronized SQLiteDatabase getReadableDatabase();以只读方式打开对应SQLiteDatabase 对象

synchronized SQLiteDatabase getWritableDatabase();以写方式打开对应SQLiteDatabase 对象

abstract void Create(SQLiteDatabase db);第一次创建数据库时回调该方法。

abstract void Upgrade(SQLiteDatabase db,int oldVersion,int newVersion);当数据库版本更新时回调该方法。

在获得数据库实例时建议使用getReadableDatabase();如果用getWritableDatabase()一旦磁盘满了,打开数据库就会出错,而getReadableDatabase方法先只读方式打开,就算磁盘空间满了,也不会出错,而是继续使用只读方式。(getReadableDatabase调用时会包含getWritableDatabase)当调用getReadableDatabase()如果数据库不存在调用onCreate(SQLiteDatabase db);存在之后返回该实例

MyDB.java

public class MyDB extends SQLiteOpenHelper {//参数1:上下文//参数2:数据库名字//参数3:游标工厂(自定义的时候才用,不需要自定义null)//数据库版本号public MyDB(Context context, String name,  int version) {super(context, name, null, version);// TODO Auto-generated constructor stub}public SQLiteDatabase db;final String CREATE_TABLE="create table student(_id integer primary key autoincrement,word varchar(20),detail varchar(20))";//第一次创建数据库的时候调用,当运行第二次时db==null@Overridepublic void onCreate(SQLiteDatabase db) {this.db=db;db.execSQL(CREATE_TABLE);}//软件升级的时候更新表结构调用,当newVersion>oldVersion时,系统自动触发该方法。//当打开数据库时传入的版本号与当前的版本号不同时会调用该方法@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}}





MainActivity.java

public class MainActivity extends Activity {String a;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MyDB db = new MyDB(this, "mydb.db3", 1);SQLiteDatabase database = db.getReadableDatabase();}}

存储路径data/data/包名/databases/mydb.db3

卸载时文件依然丢失。


查询的时候会用到Cursor:

常用方法:

isAfterLast()游标的指针是否指向了最后一条数据的后面

moveToNext() 让游标的指针指向下一条数据

moveToFirst() 让游标的指针指向第一条数据

getString(int columnIndex) 获取当前行中指定列的String值,参数列索引

getColumnIndex(StringcolumnName) 根据列名字获取列索引

插入会用到:ContentValus

ContentValus的方法很简单,键值对而已

修改数据:

//修改 参数1:被修改的表的名字 参数2:修改的成为的值 参数3:更新条件 参数4:更新条件中占位符的值

db.update(DBHelper.TABLE_NAME, values,DBHelper.ENSCORE_NAME+" = ?", new String[]{"hanhan"});

删除数据:

//数据删除 参数1:要删除数据的表的名字 参数2:删除条件 参数3:删除条件中的占位符的值

//返回值---》删除数据的行数

db.delete(DBHelper.TABLE_NAME,DBHelper.ENSCORE_NAME+" = ?", new String[]{"zhangsan"});






更多相关文章

  1. SpringBoot 2.0 中 HikariCP 数据库连接池原理解析
  2. 一句话锁定MySQL数据占用元凶
  3. android activity启动过程分析
  4. Android中的Intent Filter匹配规则介绍
  5. Android初始ViewRoot和DecorView
  6. 在launcher 2.1上实现2.2的屏幕标记
  7. 2019年Android中高级工程师部分面试题
  8. android.support.v7.widget.TintContextWrapper cannot be cast
  9. 学习笔记:Android中使用网络技术的方法(webview、httpurlconnectio

随机推荐

  1. EventThread线程对VSync的接收
  2. 在Android中借助TensorFlow使用机器学习(
  3. Tensorflow编译android平台的so库和jar包
  4. Android(安卓)studio JavaDoc的使用
  5. Android——systrace使用分析
  6. android,actionbar,menu显示,图片,菜单禁
  7. React Native Android(安卓)即时热更新bu
  8. Android对ListView控件增删改查
  9. 【 Android(安卓)10 系统启动 】系列 --
  10. Android(安卓)帧动画 的实现