【Android 基础知识】Android 五种主要存储方式的用法

完整代码在文章结尾。

一、共享参数 SharedPreferences

  • SharedPreferences 是 Android 的一个轻量级存储工具,采用的存储结构是 Key-Value 的键值对方式,符合 XML 规范的配置文件。

SharedPreferences 主要适用于:

  1. 简单且孤立的数据。若是复杂且相互间有关的数据,则要保存在数据库中。
  2. 文本形式的数据。若是二进制数据,则要保存在文件中。
  3. 需要持久化存储的数据。在 App 退出后再次启动时,之前保存的数据仍然有效。

SharedPreferences 对数据的存储和读取操作类似与 Map,也有 put 函数用于存储数据、get 函数用于读取数据。在使用前,要先调用 getSharedPreferences 函数声明文件名与操作模式,示例代码:

//从 share.xml 中获取共享参数对象
SharedPreferences shared = getSharedPreferences("share",MODE_PRIVATE);

getSharedPreferences 方法的第一个参数是文件名,上面的 share 表示当前使用的共享参数文件名是 share.xml;第二个参数是操作模式,一般都填 MODE_PRIVATE,表示私有模式。

共享参数存储数据要借助于 Editor 类,示例代码:

SharedPreferences.Editor editor = shared.edit();	//获得编辑器的对象
editor.putString("name","Lee");	//添加一个名叫name的字符串
editor.putInt("age",21);
editor.commit();	//提交编辑器中的修改

共享参数读取数据直接使用对象就可,get 方法第二个参数表示默认值,示例代码:

String name = shared.getString("name","");
int age = shared.getInt("age",0);

以下是一个实例
在页面上利用 EditText 录入用户注册信息,并保存到共享参数文件中。在另一个页面,App 从共享参数文件中读取用户注册信息(局限在于只能记住一个用户的登录信息)。

写入共享参数:

public class ShareWriteActivity extends AppCompatActivity implements OnClickListener {
	private SharedPreferences mShared; // 声明一个共享参数对象
	private EditText et_name;
	private EditText et_age;
	private EditText et_height;
	private EditText et_weight;
	private boolean bMarried = false;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_share_write);
		et_name = findViewById(R.id.et_name);
		et_age = findViewById(R.id.et_age);
		et_height = findViewById(R.id.et_height);
		et_weight = findViewById(R.id.et_weight);
		findViewById(R.id.btn_save).setOnClickListener(this);
		initTypeSpinner();
		// 从share.xml中获取共享参数对象
		mShared = getSharedPreferences("share", MODE_PRIVATE);
	}

	// 初始化婚姻状况的下拉框
	private void initTypeSpinner() {
		ArrayAdapter<String> typeAdapter = new ArrayAdapter<String>(this,
				R.layout.item_select, typeArray);
		typeAdapter.setDropDownViewResource(R.layout.item_dropdown);
		Spinner sp_married = findViewById(R.id.sp_married);
		sp_married.setPrompt("请选择婚姻状况");
		sp_married.setAdapter(typeAdapter);
		sp_married.setSelection(0);
		sp_married.setOnItemSelectedListener(new TypeSelectedListener());
	}

	private String[] typeArray = {"未婚", "已婚"};
	class TypeSelectedListener implements OnItemSelectedListener {
		public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
			bMarried = (arg2==0)?false:true;
		}

		public void onNothingSelected(AdapterView<?> arg0) {
		}
	}
	
	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.btn_save) {
			String name = et_name.getText().toString();
			String age = et_age.getText().toString();
			String height = et_height.getText().toString();
			String weight = et_weight.getText().toString();
			if (TextUtils.isEmpty(name)) {
				showToast("请先填写姓名");
				return;
			} else if (TextUtils.isEmpty(age)) {
				showToast("请先填写年龄");
				return;
			} else if (TextUtils.isEmpty(height)) {
				showToast("请先填写身高");
				return;
			} else if (TextUtils.isEmpty(weight)) {
				showToast("请先填写体重");
				return;
			}
			
			SharedPreferences.Editor editor = mShared.edit(); // 获得编辑器的对象
			editor.putString("name", name); // 添加一个名叫name的字符串参数
			editor.putInt("age", Integer.parseInt(age)); // 添加一个名叫age的整型参数
			editor.putLong("height", Long.parseLong(height)); // 添加一个名叫height的长整型参数
			editor.putFloat("weight", Float.parseFloat(weight)); // 添加一个名叫weight的浮点数参数
			editor.putBoolean("married", bMarried); // 添加一个名叫married的布尔型参数
			editor.putString("update_time", DateUtil.getNowDateTime("yyyy-MM-dd HH:mm:ss"));
			editor.commit(); // 提交编辑器中的修改
			showToast("数据已写入共享参数");
		}
	}
	
	private void showToast(String desc) {
		Toast.makeText(this, desc, Toast.LENGTH_SHORT).show();
	}
	
}

从共享参数读取:

@SuppressLint("DefaultLocale")
public class ShareReadActivity extends AppCompatActivity {
    private TextView tv_share;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_share_read);
        tv_share = findViewById(R.id.tv_share);
        readSharedPreferences();
    }

    private void readSharedPreferences() {
        // 从share.xml中获取共享参数对象
        SharedPreferences shared = getSharedPreferences("share", MODE_PRIVATE);
        String desc = "共享参数中保存的信息如下:";
        // 获取共享参数中保存的所有映射配对信息
        Map<String, Object> mapParam = (Map<String, Object>) shared.getAll();
        // 遍历该映射对象,并将配对信息形成描述文字
        for (Map.Entry<String, Object> item_map : mapParam.entrySet()) {
            String key = item_map.getKey(); // 获取该配对的键信息
            Object value = item_map.getValue(); // 获取该配对的值信息
            if (value instanceof String) { // 如果配对值的类型为字符串
                desc = String.format("%s\n %s的取值为%s", desc, key,
                        shared.getString(key, ""));
            } else if (value instanceof Integer) { // 如果配对值的类型为整型数
                desc = String.format("%s\n %s的取值为%d", desc, key,
                        shared.getInt(key, 0));
            } else if (value instanceof Float) { // 如果配对值的类型为浮点数
                desc = String.format("%s\n %s的取值为%f", desc, key,
                        shared.getFloat(key, 0.0f));
            } else if (value instanceof Boolean) { // 如果配对值的类型为布尔数
                desc = String.format("%s\n %s的取值为%b", desc, key,
                        shared.getBoolean(key, false));
            } else if (value instanceof Long) { // 如果配对值的类型为长整型
                desc = String.format("%s\n %s的取值为%d", desc, key,
                        shared.getLong(key, 0L));
            } else { // 如果配对值的类型为未知类型
                desc = String.format("%s\n参数%s的取值为未知类型", desc, key);
            }
        }
        if (mapParam.size() <= 0) {
            desc = "共享参数中保存的信息为空";
        }
        tv_share.setText(desc);
    }
}

在这里插入图片描述
在这里插入图片描述

二、数据库 SQLite

  • SQLite 是一个小巧的嵌入式数据库,SQLite 的多数 SQL 语法与 Oracle 一样。

SQLiteDatabase 是 SQLite 的数据库管理类,可以在活动页面代码或任何能娶到 Context 的地方获取数据库实例:

//创建名叫 test.db 的数据库,数据库如果不存在就创建,如果存在就打开
SQLiteDatabase db = openOrCreateDatabase(getFilesDir()+"/test.db",Context.MODE_PRIVATE,null);
//删除名叫 test.db 数据库
deleteDatabase(getFilesDir()+"/test.db");

SQLiteDatabase 提供了若干操作数据表的 API,常用的方法有 3 类:

1、 管理类,用于数据库层面的操作

  • openDatabase:打开指定路径的数据库
  • isOpen:判断数据库是否已经打开
  • close:关闭数据库
  • getVersion:获取数据库的版本号
  • setVersion:设置数据库的版本号

2、事务类,用于事务层面的操作

  • beginTransaction:开始事务
  • setTransactionSuccessful:设置事务的成功标志
  • endTransaction:结束事务。执行本方法时,系统会判断是否已执行 setTransactionSuccessful,如果已设置就提交,未设置就回滚

3、数据处理类,用于数据表层面的操作

  • execSQL:执行拼接好的 SQL 控制语句。一般用于建表、删表、变更表结构
  • delete:删除符合条件的记录
  • update:更新符合条件的记录
  • insert:插入一条记录
  • query:执行查询操作,返回结果集的游标
  • rawQuery:执行拼接好的 SQL 查询语句,返回结果集的游标

数据库帮助器 SQLiteOpenHelper 用于指导开发者进行 SQLite 的合理使用。

SQLiteOpenHelper 具体使用步骤:

  1. 新建一个继承自 SQLiteOpenHelper 的数据库操作类,重写 onCreate 和 onUpgrade 两个方法。
  2. 封装保证数据库安全的必要方法,包括获取单例对象、打开数据库连接、关闭数据库连接。
  3. 提供对表记录进行增加、删除、修改、查询的操作方法。

下面是用户注册信息数据库的 SQLiteOpenHelper 操作类的完整代码:

@SuppressLint("DefaultLocale")
public class UserDBHelper extends SQLiteOpenHelper {
    private static final String TAG = "UserDBHelper";
    private static final String DB_NAME = "user.db"; // 数据库的名称
    private static final int DB_VERSION = 1; // 数据库的版本号
    private static UserDBHelper mHelper = null; // 数据库帮助器的实例
    private SQLiteDatabase mDB = null; // 数据库的实例
    public static final String TABLE_NAME = "user_info"; // 表的名称

    private UserDBHelper(Context context) {

        super(context, DB_NAME, null, DB_VERSION);
    }

    private UserDBHelper(Context context, int version) {

        super(context, DB_NAME, null, version);
    }

    // 利用单例模式获取数据库帮助器的唯一实例
    public static UserDBHelper getInstance(Context context, int version) {
        if (version > 0 && mHelper == null) {
            mHelper = new UserDBHelper(context, version);
        } else if (mHelper == null) {
            mHelper = new UserDBHelper(context);
        }
        return mHelper;
    }

    // 打开数据库的读连接
    public SQLiteDatabase openReadLink() {
        if (mDB == null || !mDB.isOpen()) {
            mDB = mHelper.getReadableDatabase();
        }
        return mDB;
    }

    // 打开数据库的写连接
    public SQLiteDatabase openWriteLink() {
        if (mDB == null || !mDB.isOpen()) {
            mDB = mHelper.getWritableDatabase();
        }
        return mDB;
    }

    // 关闭数据库连接
    public void closeLink() {
        if (mDB != null && mDB.isOpen()) {
            mDB.close();
            mDB = null;
        }
    }

    // 创建数据库,执行建表语句
    public void onCreate(SQLiteDatabase db) {
        Log.d(TAG, "onCreate");
        String drop_sql = "DROP TABLE IF EXISTS " + TABLE_NAME + ";";
        Log.d(TAG, "drop_sql:" + drop_sql);
        db.execSQL(drop_sql);
        String create_sql = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " ("
                + "_id INTEGER PRIMARY KEY  AUTOINCREMENT NOT NULL,"
                + "name VARCHAR NOT NULL," + "age INTEGER NOT NULL,"
                + "height LONG NOT NULL," + "weight FLOAT NOT NULL,"
                + "married INTEGER NOT NULL," + "update_time VARCHAR NOT NULL"
                //演示数据库升级时要先把下面这行注释
                + ",phone VARCHAR" + ",password VARCHAR"
                + ");";
        Log.d(TAG, "create_sql:" + create_sql);
        db.execSQL(create_sql);
    }

    // 修改数据库,执行表结构变更语句
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.d(TAG, "onUpgrade oldVersion=" + oldVersion + ", newVersion=" + newVersion);
        if (newVersion > 1) {
            //Android的ALTER命令不支持一次添加多列,只能分多次添加
            String alter_sql = "ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + "phone VARCHAR;";
            Log.d(TAG, "alter_sql:" + alter_sql);
            db.execSQL(alter_sql);
            alter_sql = "ALTER TABLE " + TABLE_NAME + " ADD COLUMN " + "password VARCHAR;";
            Log.d(TAG, "alter_sql:" + alter_sql);
            db.execSQL(alter_sql);
        }
    }

    // 根据指定条件删除表记录
    public int delete(String condition) {
        // 执行删除记录动作,该语句返回删除记录的数目
        return mDB.delete(TABLE_NAME, condition, null);
    }

    // 删除该表的所有记录
    public int deleteAll() {
        // 执行删除记录动作,该语句返回删除记录的数目
        return mDB.delete(TABLE_NAME, "1=1", null);
    }

    // 往该表添加一条记录
    public long insert(UserInfo info) {
        ArrayList<UserInfo> infoArray = new ArrayList<UserInfo>();
        infoArray.add(info);
        return insert(infoArray);
    }

    // 往该表添加多条记录
    public long insert(ArrayList<UserInfo> infoArray) {
        long result = -1;
        for (int i = 0; i < infoArray.size(); i++) {
            UserInfo info = infoArray.get(i);
            ArrayList<UserInfo> tempArray = new ArrayList<UserInfo>();
            // 如果存在同名记录,则更新记录
            // 注意条件语句的等号后面要用单引号括起来
            if (info.name != null && info.name.length() > 0) {
                String condition = String.format("name='%s'", info.name);
                tempArray = query(condition);
                if (tempArray.size() > 0) {
                    update(info, condition);
                    result = tempArray.get(0).rowid;
                    continue;
                }
            }
            // 如果存在同样的手机号码,则更新记录
            if (info.phone != null && info.phone.length() > 0) {
                String condition = String.format("phone='%s'", info.phone);
                tempArray = query(condition);
                if (tempArray.size() > 0) {
                    update(info, condition);
                    result = tempArray.get(0).rowid;
                    continue;
                }
            }
            // 不存在唯一性重复的记录,则插入新记录
            ContentValues cv = new ContentValues();
            cv.put("name", info.name);
            cv.put("age", info.age);
            cv.put("height", info.height);
            cv.put("weight", info.weight);
            cv.put("married", info.married);
            cv.put("update_time", info.update_time);
            cv.put("phone", info.phone);
            cv.put("password", info.password);
            // 执行插入记录动作,该语句返回插入记录的行号
            result = mDB.insert(TABLE_NAME, "", cv);
            // 添加成功后返回行号,失败后返回-1
            if (result == -1) {
                return result;
            }
        }
        return result;
    }

    // 根据条件更新指定的表记录
    public int update(UserInfo info, String condition) {
        ContentValues cv = new ContentValues();
        cv.put("name", info.name);
        cv.put("age", info.age);
        cv.put("height", info.height);
        cv.put("weight", info.weight);
        cv.put("married", info.married);
        cv.put("update_time", info.update_time);
        cv.put("phone", info.phone);
        cv.put("password", info.password);
        // 执行更新记录动作,该语句返回记录更新的数目
        return mDB.update(TABLE_NAME, cv, condition, null);
    }

    public int update(UserInfo info) {
        // 执行更新记录动作,该语句返回记录更新的数目
        return update(info, "rowid=" + info.rowid);
    }

    // 根据指定条件查询记录,并返回结果数据队列
    public ArrayList<UserInfo> query(String condition) {
        String sql = String.format("select rowid,_id,name,age,height,weight,married,update_time," +
                "phone,password from %s where %s;", TABLE_NAME, condition);
        Log.d(TAG, "query sql: " + sql);
        ArrayList<UserInfo> infoArray = new ArrayList<UserInfo>();
        // 执行记录查询动作,该语句返回结果集的游标
        Cursor cursor = mDB.rawQuery(sql, null);
        // 循环取出游标指向的每条记录
        while (cursor.moveToNext()) {
            UserInfo info = new UserInfo();
            info.rowid = cursor.getLong(0); // 取出长整型数
            info.xuhao = cursor.getInt(1); // 取出整型数
            info.name = cursor.getString(2); // 取出字符串
            info.age = cursor.getInt(3);
            info.height = cursor.getLong(4);
            info.weight = cursor.getFloat(5); // 取出浮点数
            //SQLite没有布尔型,用0表示false,用1表示true
            info.married = (cursor.getInt(6) == 0) ? false : true;
            info.update_time = cursor.getString(7);
            info.phone = cursor.getString(8);
            info.password = cursor.getString(9);
            infoArray.add(info);
        }
        cursor.close(); // 查询完毕,关闭游标
        return infoArray;
    }

    // 根据手机号码查询指定记录
    public UserInfo queryByPhone(String phone) {
        UserInfo info = null;
        ArrayList<UserInfo> infoArray = query(String.format("phone='%s'", phone));
        if (infoArray.size() > 0) {
            info = infoArray.get(0);
        }
        return info;
    }

}

完整代码在文章结尾,实在太长了

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、SD 卡文件操作

获取手机上的 SD 卡信息通过 Environment 类实现,该类是 App 获取各种目录信息的工具,主要有 7 种方法:

  • getRootDirectory:获得系统根目录的路径
  • getDataDirectory:获得系统数据目录的路径
  • getDownloadCacheDirectory:获得下载缓存目录的路径
  • getExternalStorageDirectory:获得外部存储(SD卡)的路径
  • getExternalStorageState:获得 SD 卡的状态
  • getStorageState:获得指定目录的状态
  • getExternalStoragePublicDirectory:获得 SD 卡指定类型目录的路径

外部存储分为公共空间和私有空间两部分。

  • 获取公共空间的存储路径,调用的是 Environment.getExternalStoragePublicDirectory 方法;
  • 获取应用私有空间的存储路径,调用的是 getExternalFilesDir方法。

文本文件写入:

文本文件的读写一般借助于 FileOutputStream 和 FileInputStream 。FileOutputStream 用于写文件,FileInputStream 用于读文件。

public static void saveText(String path, String txt) {
        try {
            // 根据指定文件路径构建文件输出流对象
            FileOutputStream fos = new FileOutputStream(path);
            // 把字符串写入文件输出流
            fos.write(txt.getBytes());
            // 关闭文件输出流
            fos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 从指定路径的文本文件中读取内容字符串
    public static String openText(String path) {
        String readStr = "";
        try {
            // 根据指定文件路径构建文件输入流对象
            FileInputStream fis = new FileInputStream(path);
            byte[] b = new byte[fis.available()];
            // 从文件输入流读取字节数组
            fis.read(b);
            // 把字节数组转换为字符串
            readStr = new String(b);
            // 关闭文件输入流
            fis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 返回文本文件中的文本字符串
        return readStr;
    }

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
图片文件读写:

Android 的图片处理类是 Bitmap,App 读写 Bitmap 可以使用 FileOutputStream 和 FileInputStream。但在实际开发中,读写图片文件一般用性能更好的 BufferedOutputStreamBufferedInputStream

保存图片文件时用到 Bitmap 的 compress 方法,可指定图片类型和压缩质量;打开图片文件时使用 BitmapFactory 的 decodeStream 方法:

// 把位图数据保存到指定路径的图片文件
    public static void saveImage(String path, Bitmap bitmap) {
        try {
            // 根据指定文件路径构建缓存输出流对象
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(path));
            // 把位图数据压缩到缓存输出流中
            bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);
            // 完成缓存输出流的写入动作
            bos.flush();
            // 关闭缓存输出流
            bos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 从指定路径的图片文件中读取位图数据
    public static Bitmap openImage(String path) {
        Bitmap bitmap = null;
        try {
            // 根据指定文件路径构建缓存输入流对象
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
            // 从缓存输入流中解码位图数据
            bitmap = BitmapFactory.decodeStream(bis);
            bis.close(); // 关闭缓存输入流
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 返回图片文件中的位图数据
        return bitmap;
    }

在这里插入图片描述
在这里插入图片描述

四、Application

适合在 Application 中保存的全局变量主要有 3 种数据:

  • 会频繁读取的信息;
  • 从网络上获取的临时数据,如logo、商品图片
  • 容易因频繁分配内存而导致内存泄漏的对象,如 Handle 对象等

五、ContentProvider

1、内容提供器 ContentProvider

ContentProvider 为 App 存取内存数据提供统一的外部接口,让不同的应用之间得以共享数据。

在实际编码中,ContentProvider 只是一个服务端的数据存取接口,开发者需要在其基础上实现一个具体类,并重写以下方法:

  • onCreate:创建数据库并获得连接
  • query:查询数据
  • insert:插入数据
  • update:更新数据
  • delete:删除数据
  • getType:获取数据类型

下面是使用 ContentProvider 提供用户信息对外接口的代码:

public class UserInfoProvider extends ContentProvider {
    private final static String TAG = "UserInfoProvider";
    private UserDBHelper userDB; // 声明一个用户数据库的帮助器对象
    public static final int USER_INFO = 1; // Uri匹配时的代号
    public static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    static { // 往Uri匹配器中添加指定的数据路径
        uriMatcher.addURI(UserInfoContent.AUTHORITIES, "/user", USER_INFO);
    }

    // 根据指定条件删除数据
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int count = 0;
        if (uriMatcher.match(uri) == USER_INFO) {
            // 获取SQLite数据库的写连接
            SQLiteDatabase db = userDB.getWritableDatabase();
            // 执行SQLite的删除操作,返回删除记录的数目
            count = db.delete(UserInfoContent.TABLE_NAME, selection, selectionArgs);
            db.close(); // 关闭SQLite数据库连接
        }
        return count;
    }

    // 插入数据
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        Uri newUri = uri;
        if (uriMatcher.match(uri) == USER_INFO) {
            // 获取SQLite数据库的写连接
            SQLiteDatabase db = userDB.getWritableDatabase();
            // 向指定的表插入数据,返回记录的行号
            long rowId = db.insert(UserInfoContent.TABLE_NAME, null, values);
            if (rowId > 0) { // 判断插入是否执行成功
                // 如果添加成功,利用新记录的行号生成新的地址
                newUri = ContentUris.withAppendedId(UserInfoContent.CONTENT_URI, rowId);
                // 通知监听器,数据已经改变
                getContext().getContentResolver().notifyChange(newUri, null);
            }
            db.close(); // 关闭SQLite数据库连接
        }
        return uri;
    }

    // 创建ContentProvider时调用,可在此获取具体的数据库帮助器实例
    @Override
    public boolean onCreate() {
        userDB = UserDBHelper.getInstance(getContext(), 1);
        return false;
    }

    // 根据指定条件查询数据库
    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        Cursor cursor = null;
        if (uriMatcher.match(uri) == USER_INFO) {
            // 获取SQLite数据库的读连接
            SQLiteDatabase db = userDB.getReadableDatabase();
            // 执行SQLite的查询操作
            cursor = db.query(UserInfoContent.TABLE_NAME,
                    projection, selection, selectionArgs, null, null, sortOrder);
            // 设置内容解析器的监听
            cursor.setNotificationUri(getContext().getContentResolver(), uri);
        }
        return cursor;
    }

    // 获取Uri数据的访问类型,暂未实现
    @Override
    public String getType(Uri uri) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    // 更新数据,暂未实现
    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

2、内容解析器 ContentResolver

内容解析器 ContentResolver 是客户端 App 操作服务端数据的工具,相对应的内容提供器是服务端的数据接口。

要获取 ContentResolver 对象,在 Activity 代码中调用 getContentResolver 方法即可。

3、内容观察器 ContentObserver

给目标内容注册一个观察器,目标内容的数据一旦发生变化,观察器规定好的动作马上触发,从而执行开发者预先定义的代码。

  • registerContentObserver:注册内容观察器
  • unregisterContentObserver:注销内容观察器
  • notifyChange:通知内容观察器发生了数据变化

完整代码:https://download.csdn.net/download/zeroheitao/16621611

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

玳宸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值