ContentProvider
外部存储
外部存储属于永久性存储方式。使用这种类型存储的文件可以共享给其他的应用程序使用,也可以被删除、修改、查看等,不是一种安全的存储方式。
1.使用Environment.getExternalStorageState()方法来查看外部设备是否存在
2.使用Environment.getExternalStorageDirectory()获取外部存储的路径,就可以通过路径创建文件
3.使用FileInputStream、FileReader、 FileOutputStream、 FileWriter对象来读写外部设备中的文件。
<!--往sdcard中写入数据的权限 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!—从sdcard中读取数据的权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> |
外部存储中写入文本文件。 public void click0(View view) throws IOException { // 检查外部存储是否可用(即是否挂载)
String environment = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(environment)) {
//外部设备可以进行读写操作
File sd_path =new File(getExternalFilesDir("exter_test").getAbsolutePath()); //
Log.i("====",sd_path.toString()); // 创建一个新的文件对象,指向外部存储中的 test.txt 文件
File file = new File(sd_path, "test.txt");
String str = editText.getText().toString();
FileOutputStream fos;
try {
//写入数据,创建文件输出流和输出流写入器
fos = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fos);
osw.write(str);
osw.flush();
osw.close();
fos.close();
} catch (Exception exception) {
exception.printStackTrace();
}
}
} |
外部存储中读取文本文件 public void click1(View view) throws IOException {
// 检查外部存储是否可用(即是否挂载)
String environment = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(environment)) {
// 外部设备可以进行读写操作
File sd_path = new File(getExternalFilesDir("exter_test").getAbsolutePath());
// 创建一个新的文件对象,指向外部存储中的 test.txt 文件
File file = new File(sd_path, "test.txt");
FileInputStream fis;
try {
// 创建文件输入流和输入流读取器
fis = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
// 创建一个字符数组用于存储读取到的数据
char[] input = new char[fis.available()];
isr.read(input);
// 将字符数组转换为字符串并设置到 EditText 中
String s = new String(input);
editText.setText(s);
isr.close();
fis.close();
} catch (Exception exception) {
exception.printStackTrace();
}
}
} |
内部存储
1.将应用程序的数据以文件的形式存储在应用程序的目录下(data/data/<packagename/files/目录下>)
2.文件属于该应用程序私有,默认只能被该应用访问,且一个应用所创建的所有文件都在和应用包名相同的目录下。
3.如果其他应用程序想要操作本应用程序的文件,就需要设置权限。
4.内部存储的文件随着应用程序的卸载而删除,随着应用程序的生成而创建。
5.使用的是Context提供的openFileOutput()方法和openFileInput()方法,通过这两个方法获取FileOutputStream对象和FileInputStream对象。
内部存储中读取文本数据 public void click3(View view){
String file_name="test.txt";
//保存读取的数据
String str="";
FileInputStream fi_in;
try{ 核心代码
fi_in=openFileInput(file_name); !!!!! 打开输入流,获取输入流对象
//fi_in.available()返回的实际可读字节数
byte[] buffer=new byte[fi_in.available()];
fi_in.read(buffer);
str=new String(buffer);
editText.setText(str);
}
catch(Exception exception){
exception.printStackTrace();
}
}
} |
内部存储中输出存储文本数据 public void click2(View view){
//文件名称
String file_name="test.txt";
//写入文件的数据
String str=editText.getText().toString();
FileOutputStream fi_out;
try{ 核心代码
fi_out=openFileOutput (file_name, MODE_PRIVATE); !!!!!打开输出流,获取输出流对象,将数据存储到文件中
fi_out.write(str.getBytes());
fi_out.close();
}
catch(Exception exception){
exception.printStackTrace();
}
} |
ShardPreferences存储
1.SharedPreferences 是 Android 提供的一种轻量级的数据存储方式,适用于存储少量的键值对,NVP(Name/Value Pair,名称/值对)数据。它常用于保存应用的配置参数、用户设置或简单的数据。
2.SharedPreferences 数据以 XML 文件形式存储在设备的文件系统中,适合存储基本数据类型(如布尔值、浮点数、整数、长整数、字符串和字符串集)。
获取SharedPreferences 对象
SharedPreferences sharedPreferences = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE); 参数:文件名,如"MyPrefs",默认值
保存数据
使用 SharedPreferences.Editor 对象,通过 edit()
方法获取,并调用相应的 putXXX
方法。(如putString,puInt,putLong,putFloat)
private void saveSharedPreferences(){
@SuppressLint("WrongConstant") SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCE_NAME, MODE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("Name", nameText.getText().toString());
editor.putInt("Age", Integer.parseInt(ageText.getText().toString()));
editor.putFloat("Height", Float.parseFloat(heightText.getText().toString()));
editor.commit();
} |
读取数据(载入数据)
private void loadSharedPreferences(){ 第一个参数指定数据项名称,第二个参数指定没有找到数据项时,返回的默认值
@SuppressLint("WrongConstant") SharedPreferences sharedPreferences = getSharedPreferences(PREFERENCE_NAME,MODE);
String name = sharedPreferences.getString("Name","Tom");
int age = sharedPreferences.getInt("Age", 20);
float height = sharedPreferences.getFloat("Height",1.81f);
nameText.setText(name);
ageText.setText(String.valueOf(age));
heightText.setText(String.valueOf(height));
} |
SQLite(重中之重)
1.SQLite 是 Android 平台上内置的轻量级关系型数据库管理系统。它适用于在移动设备上存储结构化数据,广泛用于应用程序中数据持久化需求。
2.SQLite 数据库在 Android 中以单个文件的形式存储在设备的内部存储中,具备高效、简单和无需服务器支持等特点。
3.对使用SQLite保存数据库的整个思路要非常清晰
1.设计、创建数据库及版本管理(继承SQLiteOpenHelper类)
通常通过创建一个继承自 SQLiteOpenHelper 的类来管理数据库的创建和版本管理。 封装SQLiteOpenHelper类的子类后,然后还可以对应用中的数据库操作(增、删、改、查)进行扩展和封装。
必须重写的方法:
1、onCreate(SQLiteDatabase db),创建对象时对数据库进行初始化操作。
2、onUpgrade(SQLiteDatabase db,int oldVersion, int newVersion),版本更新时对数据库进行维护操作。
构造函数
super(context, DATABASE_NAME, null, DATABASE_VERSION) 调用父类 SQLiteOpenHelper 的构造函数,并传递四个参数:
2.context: 应用的上下文,提供访问资源和文件的能力。
3.DATABASE_NAME: 数据库的名称,这里是 "user_db_1"。
4.null: 第三个参数是 CursorFactory,用于自定义游标对象,通常传递 null 以使用默认的游标。
5.DATABASE_VERSION: 数据库的版本号,这里是 10。每次更改数据库结构时,应增加此版本号,以触发 onUpgrade 方法。
public final class User_Database extends SQLiteOpenHelper {
// 定义静态变量counter
static int counter = 0;
// 数据库版本号和数据库名称。
private static final int DATABASE_VERSION = 10; // 更新版本号
private static final String DATABASE_NAME = "user_db_1"; // 表名称
private static final String TABLE_USER = "user";
// 构造函数
public User_Database(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
String sql = "CREATE TABLE user (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"name TEXT NOT NULL," +
"number TEXT NOT NULL," +
"sex TEXT NOT NULL," +
"address TEXT NOT NULL," +
"major TEXT NOT NULL)";
sqLiteDatabase.execSQL(sql);
}
// 手动删除旧数据库文件的方法
public void deleteDatabase(Context context) {
context.deleteDatabase(DATABASE_NAME);
}
//数据库版本号更新时调用,空函数体
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
//添加数据方法
public void adddata(SQLiteDatabase sqLiteDatabase, String name, String number, String sex, String address, String major) {
// 记录条数序号
Log.i("TAG", "Inserting Data: name=" + name + ", number=" + number + ", sex=" + sex + ", address=" + address + ", major=" + major);
counter++;
ContentValues values = new ContentValues();
values.put("id", counter);
values.put("name", name);
values.put("number", number);
values.put("sex", sex);
values.put("address", address);
values.put("major", major);
sqLiteDatabase.insert("user", null, values);
Log.i("TAG", "This is an info message");
sqLiteDatabase.close();
}
//删除数据方法,参数(数据库,记录id)
public void delete(SQLiteDatabase sqLiteDatabase, int id) {
// 表名:user
sqLiteDatabase.delete("user", "id=?", new String[]{id + ""});
sqLiteDatabase.close();
}
//修改(更新)数据方法
public void update(SQLiteDatabase sqLiteDatabase, int id, String name, String number, String sex, String address, String major) {
Log.i("TAG", "Inserting Data: name=" + name + ", number=" + number + ", sex=" + sex + ", address=" + address + ", major=" + major);
//创建一个ContentValues对象
ContentValues values = new ContentValues();
Log.i("TAG", "This is an info message");
//以键值对的形式插入信息
values.put("id", id);
values.put("name", name);
values.put("number", number);
values.put("sex", sex);
values.put("address", address);
values.put("major", major);
// 修改学生信息
sqLiteDatabase.update("user",values,"id=?",new String[]{id+""})
//
sqLiteDatabase.close();
}
//查询数据方法
public List<UserInfo> queryData(SQLiteDatabase sqLiteDatabase) {
// 定义游标cursor,初始化为一个query+查询条件:id按照升序排序
Cursor cursor = sqLiteDatabase.query("user", null, null, null, null, null, "id ASC");
// 初始化结果列表
List<UserInfo> list = new ArrayList<>();
// 游标遍历查询结果,通过moveToNext
while (cursor.moveToNext()) {
// 通过列索引获取学生记录这一条记录的所有信息
@SuppressLint("Range") int id=cursor.getInt(cursor.getColumnIndex("id"));
String name = cursor.getString(1);
String number = cursor.getString(2);
String sex = cursor.getString(3);
String address = cursor.getString(4);
String major = cursor.getString(5);
Log.i("TAG!!!!!", "Inserting Data: name=" + name + ", number=" + number + ", sex=" + sex + ", address=" + address + ", major=" + major);
// 将获得信息方法到列表中
list.add(new UserInfo(id, name, number, sex, address, major));
}
// 关闭游标,关闭数据库
cursor.close();
sqLiteDatabase.close();
return list;
}
} |
|
ContentProvider应用程序之间的传递
在Android当中,每一个应用程序的数据都是采用私有的形式进行操作的(对安全的要求越来越严格),不管这些数据是文件保存还是数据库保存,都不能被外部应用程序所访问。
但是在很多情况下用户是需要可以在不同的应用程序之间进行数据的交换,所以为了解决这样的问题,在Android中专门提供了一个ContentProvider类,此类的主要功能是将不同的应用程序的数据操作标准统一起来,并且将各个应用程序的数据操作标准暴露给其他应用程序,这样,一个应用程序的数据就可以按照ContentProvider所制定的标准被外部所操作。
ContentProvider 是 Android 提供的一种组件,用于在应用之间共享数据。通过 ContentProvider,应用程序可以访问其他应用的数据,同时也可以向其他应用提供自己的数据。这种机制保证了数据访问的一致性和安全性。常见的使用场景包括联系人、媒体文件和设置等系统级数据的访问。
ContentProvider
在应用中,向外部传递数据,需要使用ContentProvider类实现
ContentResolver
在使用外部资源时,需要使用ContentResolver类进行处理。
Uri简介
在创建ContentProvider时,提到了一个参数Uri uri,它代表了数据的操作方法。Uri由scheme、authorites、path三部分组成,其中: scheme部分 content://是一个标准的前缀,表明了这个数据被内容提供者管理,它不会修改。 Authorites部分是在清单文件注册的android:authorites属性值,该值唯一,表明了当前的内容提供者。 path部分代表数据,当访问者操作不同数据时,这个值是动态变化的。 |
创建ContentProvider(内容提供器)
开发ContentProvider时只需要两步,首先需要创建一个它的子类,该类需要实现它的抽象方法,如query()、insert()、update()和delete()等方法;然后在AndroidManifest.xml文件中注册ContentProvider。 几个抽象方法的具体的作用如下: public boolean onCreate():ContentProvider创建时调用。 public int delete(…):根据传入的Uri删除指定条件下的数据。 public Uri insert(…):根据传入的Uri插入数据。 public Cursor query(…):根据传入的Uri查询指定的数据。 public int update(…):根据传入的Uri更新指定的数据。 |
完整代码package com.peace.contentprovider;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class MyContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
return false;
}
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
return null;
}
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
return null;
}
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
} |
注册ContentProvider
<provider
android:name=".MyContentProvider" 重要属性
android:authorities="com.example.mycontentprovider" 重要属性
android:exported="true" 重要属性
android:grantUriPermissions="true"> 重要属性
</provider> android:name: 指定ContentProvider类的名称。通常是你的ContentProvider类的完整路径或者相对路径(如上例中的.MyContentProvider)。 android:authorities: 一个唯一标识符,用来确定ContentProvider的URI授权。这通常是你应用的包名(如com.example.mycontentprovider)。 android:exported: 是否允许其他应用程序访问该ContentProvider。设置为true表示允许外部访问,false表示不允许。 android:grantUriPermissions: 是否允许动态授予URI权限。设置为true表示允许。 |