Android四大组件基础学习之Content Provider

系列文章目录

Android四大组件基础学习
第一章
Android四大组件基础学习之Activity-优快云博客

第二章 Android四大组件基础学习之Service-优快云博客

第三章 Android四大组件基础学习之Broadcast Receiver-优快云博客

第四章 Android四大组件基础学习之Content Provider
 



前言

       通过一个基础案例来学习Android四大组件,一共分为4章,这是最后一章,如果有做的不好的地方、文章上的错误,或者是建议,欢迎大家在评论区或者私信我,感谢大家的包容和理解!


一、Content Provider介绍

1.Content Provider的概念

(1.1)Content Provider定义

       Content Provider是Android系统中用于在不同应用之间共享数据的组件。它提供了一套标准的接口,使得其他应用能够访问和操作由该Content Provider管理的数据。

(1.2)数据模型

       Content Provider通过一种类似表格的结构来组织数据,每一行代表一条记录,每一列代表一个字段。这种数据模型类似于关系数据库中的表结构。

       例如,在联系人Content Provider中,每一行可能代表一个联系人,每一列可能代表联系人的姓名、电话号码、邮箱等信息。

(1.3)Uri

       Uri是Content Provider中用于标识数据的统一资源标识符。它通常以content://开头,后面跟着authority(唯一标识) 和path(资源路径)。例如,系统联系人Content Provider的Uri可能是content://contacts/people

2.Content Provider的特点

(1)不同应用间数据共享

(2)统一的访问接口

(3)抽象数据源,Content Provider可以抽象不同类型的底层数据源,如SQLite数据库、文件系统等,开发者只需关注数据的访问逻辑,而无需关心数据的实际存储方式。

二、Content Provider的方法

   通过context.getContentResolver()方法获取ContentResolver的实例,来使用以下方法

ContentResolver contentResolver = context.getContentResolver();

方法名描述参数
onCreate()在Content Provider被创建时调用,用于初始化工作,如打开数据库连接。
getType()返回指定Uri的数据的MIME类型。Uri uri:要查询的Uri。
insert()向Content Provider中插入一条新记录。

Uri uri:要插入的Uri

ContentValues values:要插入的数据。

delete()从Content Provider中删除记录。

Uri uri:要删除的Uri;

String selection:删除条件;

String[] selectionArgs:删除条件的参数。

update()更新Content Provider中的记录。

Uri uri:要更新的Uri;

ContentValues values:要更新的数据;

String selection:更新条件;

String[] selectionArgs:更新条件的参数。

query()查询Content Provider中的数据。

Uri uri:要查询的Uri;

String[] projection:要返回的列;

String selection:查询条件;

String[] selectionArgs:查询条件的参数;String sortOrder:排序。

举个例子:

//创建ContentResolver对象
ContentResolver contentResolver = context.getContentResolver();
//创建一个 ContentValues 对象,用于存储键值对
ContentValues contentValues = new ContentValues();
//添加数据
contentValues.put("column1", value1);
contentValues.put("column2", value2);
// 通过ContentResolver向指定的内容提供者URI插入数据
// insert()方法会将ContentValues中的数据插入到指定URI对应的内容提供者中
// 并返回新插入数据的URI,该URI可以用于后续的查询、更新或删除操作
Uri insertedUri = contentResolver.insert(insertUri, contentValues);

三、Content Provider的创建及使用

         假设我们需要在应用中存储用户的一些偏好设置,用户使用的用户名,并允许其他应用访问这些设置。

         同样的创建包和ContentProvider类,,取名UserPreferencesProvider,URI设定为com.example.myapp.userpreferences,四章下来文件目录如下

1.编写UserPreferencesProvider,实现存储用户偏好

UserPreferencesProvider.java:

package com.example.contentProvider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;

import java.util.Map;

public class UserPreferencesProvider extends ContentProvider {
    //定义 ContentProvider 的唯一标识(Authority)
    private static final String AUTHORITY = "com.example.myapp.userpreferences";
    //创建一个UriMatcher对象,用于匹配传入的URI,NO_MATCH表示初始时不匹配任何 URI
    private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    //创建SharedPreferences对象,用于存储和检索键值对
    private SharedPreferences sharedPreferences;

    //静态块,类加载时执行
    static {
        //URI的授权部分,匹配preferences,匹配成功时返回的整数值
        //content://com.example.myapp.userpreferences/preferences
        uriMatcher.addURI(AUTHORITY, "preferences", 1);
    }

    public UserPreferencesProvider() {
    }

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


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

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }

    //初始化方法
    @Override
    public boolean onCreate() {
        //获取名为 user_preferences 的 SharedPreferences 对象
        //MODE_PRIVATE 表示 SharedPreferences 数据只能被本应用访问
        sharedPreferences = getContext().getSharedPreferences("user_preferences", Context.MODE_PRIVATE);
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        //匹配传入的URI
        int match = uriMatcher.match(uri);
        if (match == 1) {
            //查询所有偏好设置
            //MatrixCursor是游标(Cursor)的一个实现类,模拟数据库表
            MatrixCursor cursor = new MatrixCursor(new String[]{"key", "value"});
            //将偏好设置复制到Map类allEntries
            Map<String, ?> allEntries = sharedPreferences.getAll();
            for (Map.Entry<String, ?> entry : allEntries.entrySet()) {
                cursor.addRow(new Object[]{entry.getKey(), entry.getValue().toString()});
            }
            return cursor;
        }
        return null;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        return 0;
    }
}

2.在 LoginActivity 中使用 Content Provider 存储用户偏好设置

LoginActivity.java:

package com.example.activity;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.ContentInfo;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import com.example.service.LoginStatusService;

public class LoginActivity extends AppCompatActivity {
    private EditText etUsername, etPassword;  //用户名、密码
    private Button btnLogin;  //登录按钮

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);    //设置布局文件(关联activity_login.xml与LoginActivity)

        etUsername = findViewById(R.id.et_username); //将变量与XML中组件关联
        etPassword = findViewById(R.id.et_password);
        btnLogin = findViewById(R.id.btn_login);

        btnLogin.setOnClickListener(new View.OnClickListener() {  //为按钮设置点击事件监听器
            @Override
            public void onClick(View v) {
                String username = etUsername.getText().toString().trim();
                String password = etPassword.getText().toString().trim();
                ContentResolver contentResolver = getContentResolver();
                //uri
                Uri uri = Uri.parse("content://com.example.myapp.userpreferences/preferences");
                ContentValues contentValues = new ContentValues();
                //存储当前用户的用户名
                contentValues.put("key", "username");
                contentValues.put("value", username);
                contentResolver.insert(uri, contentValues);
                contentValues.clear();

                if (!username.isEmpty() && !password.isEmpty()) {  //当用户名与密码不为空时
                    //创建一个从 LoginActivity 跳转到 MainActivity 的意图(Intent)
                    Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                    intent.putExtra("username", username);  // 将用户名传递给下一个 MainActivity
                    startActivity(intent);  // 跳转到 MainActivity
                    finish();  // 关闭当前 LoginActivity
                } else {
                    Toast.makeText(LoginActivity.this, "用户名和密码不能为空", Toast.LENGTH_SHORT).show();
                }

                // 使用startService启动服务LoginStatusService
                startService(new Intent(LoginActivity.this, LoginStatusService.class));


            }
        });
    }
}

3.不要忘了在清单文件注册

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <!-- 添加检测网络状态权限 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Activity"
        tools:targetApi="31">
        <provider
            android:name="com.example.contentProvider.UserPreferencesProvider"
            android:authorities="com.example.myapp.userpreferences"
            android:enabled="true"
            android:exported="true"></provider>

        <receiver
            android:name="com.example.broadcastReceiver.NetworkStateReceiver"
            android:enabled="true"
            android:exported="true" />

        <service
            android:name="com.example.service.LoginStatusService"
            android:enabled="true"
            android:exported="true" />

        <activity
            android:name=".LoginActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity"
            android:exported="false" />
    </application>

</manifest>

4.核心作用:允许其他应用访问数据,举例

//创建ContentResolver对象
ContentResolver contentResolver = getContentResolver();
//使用Uri
Uri uri = Uri.parse("content://com.example.myapp.userpreferences/preferences");
//查询
Cursor cursor = contentResolver.query(uri, null, null, null, null);
if (cursor != null) {
    //遍历输出
    while (cursor.moveToNext()) {
        String key = cursor.getString(cursor.getColumnIndex("key"));
        String value = cursor.getString(cursor.getColumnIndex("value"));
        Log.d("UserPreferences", key + ": " + value);
    }
    //关闭游标
    cursor.close();
}

四、总结

        感谢大家的观看与支持,这个系列文章完结了,后续我会补充相关内容,持续更新自己的学习过程,希望能给大家提供帮助,下期文章见!

Vivado2023是一款集成开发环境软件,用于设计和验证FPGA(现场可编程门阵列)和可编程逻辑器件。对于使用Vivado2023的用户来说,license是必不可少的。 Vivado2023的license是一种许可证,用于授权用户合法使用该软件。许可证分为多种类型,包括评估许可证、开发许可证和节点许可证等。每种许可证都有不同的使用条件和功能。 评估许可证是免费提供的,让用户可以在一段时间内试用Vivado2023的全部功能。用户可以使用这个许可证来了解软件的性能和特点,对于初学者和小规模项目来说是一个很好的选择。但是,使用评估许可证的用户在使用期限过后需要购买正式的许可证才能继续使用软件。 开发许可证是付费的,可以永久使用Vivado2023的全部功能。这种许可证适用于需要长期使用Vivado2023进行开发的用户,通常是专业的FPGA设计师或工程师。购买开发许可证可以享受Vivado2023的技术支持和更新服务,确保软件始终保持最新的版本和功能。 节点许可证是用于多设备或分布式设计的许可证,可以在多个计算机上安装Vivado2023,并共享使用。节点许可证适用于大规模项目或需要多个处理节点进行设计的用户,可以提高工作效率和资源利用率。 总之,Vivado2023 license是用户在使用Vivado2023时必须考虑的问题。用户可以根据自己的需求选择合适的许可证类型,以便获取最佳的软件使用体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值