安卓源码学习之【系统属性与 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 数据变化,适用于监听系统设置的修改。
相关推荐
阿pin28 分钟前
Android随笔-AIDL
android·开发语言·aidl
2501_916007471 小时前
Bundle ID 注册与管理 App ID 创建指南 命名规则 权限开关与删除注意事项
android·ios·小程序·https·uni-app·iphone·webview
雨白1 小时前
面向对象六大基本原则实战:从零重构支持引擎切换的网络框架
android·架构
天空之城--4 小时前
Android Flutter行业动态与学习参考(2026年8月)
android·flutter
quantdash_cc5 小时前
基于 QuantDash 5 分钟 K 线的网格交易策略参数网格搜索寻优实战
android·开发语言·pandas·量化·quantdash
杉氧6 小时前
原生交互:如何在 Flutter 中嵌入 Android/iOS 原生组件并解决手势冲突
android·flutter·dart
Android打工仔6 小时前
Continuation 的链式关系 —— 一个 suspend 函数如何把结果交还给调用者?
android·kotlin
hunterandroid6 小时前
[Android 从零到一] Kotlin Channel 与复杂并发场景:从生产者-消费者到结构化并发治理
android
FlightYe7 小时前
linux系统编程(八):阻塞与非阻塞IO对比
android·linux·运维·服务器·github·vim
恋猫de小郭7 小时前
Flutter iOS Deep Link 为什么会突然失效:一系列难以言喻的问题
android·前端·flutter