安卓源码学习之【系统属性与 ContentObserver】

1. SystemProperty

1.1 引入 SystemProperties 类

在 Android Framework 中,SystemProperties 类用于访问和操作系统属性。系统属性在 Android 系统中广泛用于存储和检索配置信息。

主要方法

java 复制代码
get(String key)
get(String key, String def)
getInt(String key, int def)
getLong(String key, long def)
getBoolean(String key, boolean def)
set(String key, String value)

1.2 使用示例

获取系统属性

java 复制代码
import android.os.SystemProperties;

public class SystemPropertyExample {
    public static void main(String[] args) {
        // 获取属性值,如果属性不存在则返回空字符串
        String value = SystemProperties.get("ro.build.version.release");
        System.out.println("Android Version: " + value);

        // 获取属性值,如果属性不存在则返回默认值
        String defaultValue = SystemProperties.get("non.existent.property", "default_value");
        System.out.println("Non-existent property: " + defaultValue);
    }
}

设置系统属性

java 复制代码
import android.os.SystemProperties;

public class SystemPropertyExample {
    public static void main(String[] args) {
        // 设置属性值
        SystemProperties.set("custom.property", "custom_value");

        // 验证设置的属性值
        String customValue = SystemProperties.get("custom.property");
        System.out.println("Custom Property: " + customValue);
    }
}

获取整数、长整数和布尔值

java 复制代码
import android.os.SystemProperties;

public class SystemPropertyExample {
    public static void main(String[] args) {
        // 获取整数属性
        int intValue = SystemProperties.getInt("ro.build.version.sdk", 0);
        System.out.println("SDK Version: " + intValue);

        // 获取长整数属性
        long longValue = SystemProperties.getLong("some.long.property", 0L);
        System.out.println("Long Property: " + longValue);

        // 获取布尔值属性
        boolean boolValue = SystemProperties.getBoolean("some.boolean.property", false);
        System.out.println("Boolean Property: " + boolValue);
    }
}

1.3 注意事项

  1. 权限:某些系统属性可能需要特定权限才能读取或修改,特别是在非系统应用中。
  2. 不可滥用:系统属性用于存储全局配置参数,不应滥用或频繁修改,以免影响系统稳定性。
  3. 性能:频繁访问系统属性可能会影响性能,建议将其值缓存到内存中以优化性能。

1.4 总结

SystemProperties 类在 Android Framework 中非常有用,可以方便地获取和设置系统配置参数。虽然它是一个隐藏 API,但在系统开发和调试中非常有帮助。

2. ContentObserver 的使用

ContentObserver 在 Android 开发中常用于监听系统设置的变化,因为系统设置存储在内容提供者(Content Provider)中。

2.1 创建一个 ContentObserver 类

java 复制代码
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;

public class SettingsObserver extends ContentObserver {
    public SettingsObserver(Handler handler) {
        super(handler);
    }

    @Override
    public void onChange(boolean selfChange, Uri uri) {
        super.onChange(selfChange, uri);
        // 在这里处理设置变化
        System.out.println("Settings changed: " + uri.toString());
    }
}

2.2 注册 ContentObserver

ActivityService 中注册 ContentObserver

java 复制代码
import android.app.Activity;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;

public class MainActivity extends Activity {
    private SettingsObserver settingsObserver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Handler handler = new Handler();
        settingsObserver = new SettingsObserver(handler);

        // 注册观察器,监听系统设置的变化
        getContentResolver().registerContentObserver(
            Settings.System.CONTENT_URI,  // 可选择 Settings.Global.CONTENT_URI 或 Settings.Secure.CONTENT_URI
            true, // 是否监听所有的子 URI
            settingsObserver
        );
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (settingsObserver != null) {
            getContentResolver().unregisterContentObserver(settingsObserver);
        }
    }
}

2.3 处理设置变化

SettingsObserveronChange 方法中处理设置变化。例如,如果你只关心特定的设置项,可以根据 URI 进行过滤处理:

java 复制代码
@Override
public void onChange(boolean selfChange, Uri uri) {
    super.onChange(selfChange, uri);
    if (uri.equals(Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS))) {
        int brightness = Settings.System.getInt(
            context.getContentResolver(),
            Settings.System.SCREEN_BRIGHTNESS,
            -1
        );
        System.out.println("Screen brightness changed: " + brightness);
    }
}

2.4 示例总结

SettingsObserver.java

java 复制代码
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;

public class SettingsObserver extends ContentObserver {
    private Context context;

    public SettingsObserver(Handler handler, Context context) {
        super(handler);
        this.context = context;
    }

    @Override
    public void onChange(boolean selfChange, Uri uri) {
        super.onChange(selfChange, uri);
        if (uri.equals(Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS))) {
            int brightness = Settings.System.getInt(
                context.getContentResolver(),
                Settings.System.SCREEN_BRIGHTNESS,
                -1
            );
            System.out.println("Screen brightness changed: " + brightness);
        }
    }
}

MainActivity.java

java 复制代码
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;

public class MainActivity extends Activity {
    private SettingsObserver settingsObserver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Handler handler = new Handler();
        settingsObserver = new SettingsObserver(handler, this);

        getContentResolver().registerContentObserver(
            Settings.System.CONTENT_URI,
            true,
            settingsObserver
        );
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (settingsObserver != null) {
            getContentResolver().unregisterContentObserver(settingsObserver);
        }
    }
}

2.5 注意事项

  1. 监听或操作 SettingsProvider 数据库,需要系统应用权限
xml 复制代码
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:sharedUserId="android.uid.system">
  
    <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
</manifest>
  1. 部分设置项可能需要额外权限或无法被修改

3. 实战演示

修改 MyApplication 代码:

xml 复制代码
public class MainActivity extends AppCompatActivity {

    private SettingsObserver mSettingsObserver;
    private String TEST_KEY = "test_key";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);

        int value = Settings.System.getInt(getContentResolver(),TEST_KEY,-1);
        Log.d("wyd"," onCreate get TEST_KEY value :" + value);
        Settings.System.putInt(getContentResolver(),TEST_KEY,-3);
        mSettingsObserver = new SettingsObserver(new Handler());
        getContentResolver().registerContentObserver(Settings.System.getUriFor(TEST_KEY),true,mSettingsObserver);
    }

    class SettingsObserver extends ContentObserver {

        /**
         * Creates a content observer.
         *
         * @param handler The handler to run {@link #onChange} on, or null if none.
         */
        public SettingsObserver(Handler handler) {
            super(handler);
        }


        @Override
        public void onChange(boolean selfChange, @Nullable Uri uri) {
            super.onChange(selfChange, uri);

            int value = Settings.System.getInt(getContentResolver(),TEST_KEY,-1);
            Log.d("wyd"," value : " + value);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        getContentResolver().unregisterContentObserver(mSettingsObserver);
    }
}

AndroidManifest.xml 增加:

xml 复制代码
android:sharedUserId="android.uid.system"

和权限

xml 复制代码
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>

修改编译文件: vendor/apps/MyApplication/Android.mk

makefile 复制代码
#每个 Android.mk 文件必须以定义 LOCAL_PATH 为开始,它用于在开发树中查找源文件。  
LOCAL_PATH:= $(call my-dir)
#CLEAR_VARS 变量由 Build System 提供,并指向一个指定的 GNU Makefile,由它负责清理很多 LOCAL_xxx。
include $(CLEAR_VARS)
#模块名
LOCAL_MODULE := MyApplication
#apk 名  
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
#user、eng、tests、optional(所有版本都编译)
LOCAL_MODULE_TAGS := optional
#指定模块的类型,可不用定义 APPS、JAVA_LIBRAYIES、 SHARED_LIBRAYIES、 EXECUTABLES
LOCAL_MODULE_CLASS := APPS
#签名 platform 、PRESIGNED、 shared
LOCAL_CERTIFICATE := platform
# in system/app/
LOCAL_SYSTEM_MODULE := true
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
include $(BUILD_PREBUILT)

主要注意使用平台签名:LOCAL_CERTIFICATE := platform 和 将应用放到 system/app/LOCAL_SYSTEM_MODULE := true

然后删除之前编译的镜像文件out/target/product/emulator_x86_64/ 目录下搜索 .img 全部删除

然后执行四步走:

makefile 复制代码
//先初始化环境(每次打开虚拟机只需要执行一次环境即可)
source build/envsetup.sh

//选择上次编译过的机型(这个也是只选一次)
lunch sdk_phone_x86_64-eng

//开始整编(后续修改源码,只需要执行m就行,上面两个指令执行一次就行了)
m 

//启动模拟器
emulator -writable-system

编译完成,运行模拟器,打开预装的应用,在终端输入以下指令设置值和获取值:

makefile 复制代码
adb shell settings put system test_key 0
adb shell settings put system test_key 1
adb shell settings get system test_key

日志打印:

总结

  • SystemProperties 可用于获取和修改系统属性,但它是隐藏 API,需要特殊方法访问。
  • ContentObserver 用于监听 ContentProvider 数据变化,适用于监听系统设置的修改。
相关推荐
顾林海1 小时前
Flutter Dart 泛型详解
android·前端·flutter
xq95271 小时前
Android 俄罗斯vk授权登录接入来了
android
小狗很可爱4 小时前
将Django连接到mysql
android·mysql·django
QING6184 小时前
Android RecyclerView 性能优化指南
android·性能优化·app
代码AC不AC4 小时前
【数据结构】顺序表(附源码)
c语言·数据结构·源码·顺序表·线性表
故事与他6454 小时前
vulhub-Billu-b0x攻略
android·linux·运维·服务器·web安全·github
QING6185 小时前
一文带你吃透Android中显示Intent与隐式Intent的区别
android·kotlin·app
QING6185 小时前
Android 性能优化全面指南 —— 大纲
android·性能优化·app
&有梦想的咸鱼&5 小时前
Android Fresco 框架兼容模块源码深度剖析(六)
android