(1)概述

(A)

SettingsProvider顾名思义是一个提供设置数据共享的Provider,SettingsProvider和Android系统其它Provider有很多不一样的地方,如:

  • SettingsProvider只接受int、float、string等基本类型的数据;
  • SettingsProvider由Android系统framework进行了封装,使用更加快捷方便;
  • SettingsProvider的数据由键值对组成;

(B)

SettingsProvider有点类似Android的SystemProperties。SystemProperties除具有SettingsProvider以上的三个特性,SettingsProvider和SystemProperties的不同点在于:

  • 数据保存方式不同:SystemProperties的数据保存属性文件中(/system/build.prop等),开机后会被加载到system properties store,SettingsProvider的数据保存在文件/data/system/users/0/settings_***.xml和数据库settings.db中;
  • 作用范围不同:SystemProperties可以实现跨进程、跨层次调用,即底层的c/c++可以调用,java层也可以调用,SettingProvider只能在java层(APP)使用;

在Android 6.0版本时,SettingsProvider被重构,Android从性能、安全等方面考虑,把SettingsProvider中原本保存在settings.db中的数据,目前全部保存在XML文件中。

(C)

SettingsProvider对数据进行了分类,分别是Global、System、Secure三种类型,它们的区别如下:

  • Global:所有的偏好设置对系统的所有用户公开,第三方APP有读没有写的权限;
  • System:包含各种各样的用户偏好系统设置;
  • Secure:安全性的用户偏好系统设置,第三方APP有读没有写的权限;

上面对Global、System、Secure分别生成一个File对象实例,它们的File对象分别对应的文件是:

/data/system/users/0/settings_global.xml
/data/system/users/0/settings_system.xml
/data/system/users/0/settings_secure.xml

也就是说,Global类型的数据保存在文件settings_global.xml中,System类型的数据保存在文件settings_system.xml中,Secure类型的数据保存在文件settings_secure.xml中。

(2)AndroidManifest.xml

//frameworks/base/packages/SettingsProvider/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.android.providers.settings"coreApp="true"android:sharedUserId="android.uid.system"><application android:allowClearUserData="false"android:label="@string/app_label"android:process="system"android:backupAgent="SettingsBackupAgent"android:killAfterRestore="false"android:restoreAnyVersion="true"android:icon="@mipmap/ic_launcher_settings"android:defaultToDeviceProtectedStorage="true"android:forceQueryable="true"android:directBootAware="true"><provider android:name="SettingsProvider"android:authorities="settings"android:multiprocess="false"android:exported="true"android:singleUser="true"android:initOrder="100"android:visibleToInstantApps="true" /></application>
</manifest>

由上面Manifest配置的sharedUserId可知,SettingsProvider运行在系统进程中,定义的ContentProvider实现类是SettingsProvider。

(3)Code位置

在frameworks中跟Setting默认值相关的几个文件:

  • /frameworks/base/packages/SettingsProvider/res/values/defaults.xml
  • /frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
  • /frameworks/base/core/java/android/provider/Settings.java

备注:Mtk平台使用的是/vendor/mediatek/proprietary/packages/apps/SettingsProvider/自定义的Provider,而Settings类还是Framework层的。

  • /vendor/mediatek/proprietary/packages/apps/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
  • /vendor/mediatek/proprietary/packages/apps/SettingsProvider/res/values/defaults.xml

(4)defaults.xml
在defaults.xml文件中定义了相关的值,DatabaseHelper.java会把相应的值读取出来保存到ContentProvider。

//frameworks/base/packages/SettingsProvider/res/values/defaults.xml
<resources><bool name="def_dim_screen">true</bool><integer name="def_screen_off_timeout">60000</integer><integer name="def_sleep_timeout">-1</integer><bool name="def_airplane_mode_on">false</bool><bool name="def_theater_mode_on">false</bool><!-- Comma-separated list of bluetooth, wifi, and cell. --><string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi,nfc,wimax</string><string name="airplane_mode_toggleable_radios" translatable="false">bluetooth,wifi,nfc</string><string name="def_bluetooth_disabled_profiles" translatable="false">0</string><bool name="def_auto_time">true</bool><bool name="def_auto_time_zone">true</bool>//关闭自动旋转<bool name="def_accelerometer_rotation">false</bool><!-- Default screen brightness, from 0 to 255.  102 is 40%. --><integer name="def_screen_brightness">102</integer><bool name="def_screen_brightness_automatic_mode">false</bool><fraction name="def_window_animation_scale">100%</fraction><fraction name="def_window_transition_scale">100%</fraction><bool name="def_haptic_feedback">true</bool><bool name="def_bluetooth_on">true</bool><bool name="def_wifi_display_on">false</bool><bool name="def_install_non_market_apps">false</bool><!-- 0 == off, 3 == on --><integer name="def_location_mode">3</integer><bool name="assisted_gps_enabled">true</bool><bool name="def_netstats_enabled">true</bool><bool name="def_usb_mass_storage_enabled">true</bool><bool name="def_wifi_on">false</bool><!-- 0 == never, 1 == only when plugged in, 2 == always --><integer name="def_wifi_sleep_policy">2</integer><bool name="def_wifi_wakeup_enabled">true</bool><bool name="def_networks_available_notification_on">true</bool><bool name="def_backup_enabled">false</bool><string name="def_backup_transport" translatable="false">com.android.localtransport/.LocalTransport</string><!-- Default value for whether or not to pulse the notification LED when there is apending notification --><bool name="def_notification_pulse">true</bool><bool name="def_mount_play_notification_snd">true</bool><bool name="def_mount_ums_autostart">false</bool><bool name="def_mount_ums_prompt">true</bool><bool name="def_mount_ums_notify_enabled">true</bool><!-- user interface sound effects --><integer name="def_power_sounds_enabled">1</integer><string name="def_low_battery_sound" translatable="false">/product/media/audio/ui/LowBattery.ogg</string><integer name="def_dock_sounds_enabled">0</integer><integer name="def_dock_sounds_enabled_when_accessibility">0</integer><string name="def_desk_dock_sound" translatable="false">/product/media/audio/ui/Dock.ogg</string><string name="def_desk_undock_sound" translatable="false">/product/media/audio/ui/Undock.ogg</string><string name="def_car_dock_sound" translatable="false">/product/media/audio/ui/Dock.ogg</string><string name="def_car_undock_sound" translatable="false">/product/media/audio/ui/Undock.ogg</string><integer name="def_lockscreen_sounds_enabled">1</integer><string name="def_lock_sound" translatable="false">/product/media/audio/ui/Lock.ogg</string><string name="def_unlock_sound" translatable="false">/product/media/audio/ui/Unlock.ogg</string><string name="def_trusted_sound" translatable="false">/product/media/audio/ui/Trusted.ogg</string><string name="def_wireless_charging_started_sound" translatable="false">/product/media/audio/ui/WirelessChargingStarted.ogg</string><string name="def_charging_started_sound" translatable="false">/product/media/audio/ui/ChargingStarted.ogg</string><!-- sound trigger detection service default values --><integer name="def_max_sound_trigger_detection_service_ops_per_day" translatable="false">1000</integer><integer name="def_sound_trigger_detection_service_op_timeout" translatable="false">15000</integer><bool name="def_lockscreen_disabled">false</bool><bool name="def_device_provisioned">false</bool><integer name="def_dock_audio_media_enabled">1</integer><!-- Notifications use ringer volume --><bool name="def_notifications_use_ring_volume">true</bool><!-- Default for Settings.System.VIBRATE_IN_SILENT --><bool name="def_vibrate_in_silent">true</bool><!-- Default for Settings.Secure.SYNC_PARENT_SOUNDS --><bool name="def_sync_parent_sounds">true</bool><!-- Default for Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD --><bool name="def_accessibility_speak_password">true</bool><!-- Default for Settings.Secure.TOUCH_EXPLORATION_ENABLED --><bool name="def_touch_exploration_enabled">false</bool><!-- Default value for Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE --><fraction name="def_accessibility_display_magnification_scale">200%</fraction><!-- Default value for Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED --><bool name="def_accessibility_display_magnification_enabled">false</bool><!-- Default value for Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE --><bool name="def_accessibility_display_magnification_auto_update">true</bool><!-- Default for Settings.System.USER_ROTATION -->//屏幕旋转默认角度<integer name="def_user_rotation">0</integer><!-- Default for Settings.Secure.DOWNLOAD_MAX_BYTES_OVER_MOBILE. <=0 if no limit --><integer name="def_download_manager_max_bytes_over_mobile">-1</integer><!-- Default for Settings.Secure.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE. <=0 if no limit --><integer name="def_download_manager_recommended_max_bytes_over_mobile">-1</integer><!-- Default for Settings.Secure.LONG_PRESS_TIMEOUT_MILLIS --><integer name="def_long_press_timeout_millis">400</integer><!-- Default for Settings.Secure.MULTI_PRESS_TIMEOUT --><integer name="def_multi_press_timeout_millis">300</integer><!-- Default for Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD --><bool name="def_show_ime_with_hard_keyboard">false</bool><!-- Default for Settings.System.POINTER_SPEED --><integer name="def_pointer_speed">0</integer><!-- Default for DTMF tones enabled --><bool name="def_dtmf_tones_enabled">true</bool><!-- Default for UI touch sounds enabled --><bool name="def_sound_effects_enabled">true</bool><!-- Development settings --><bool name="def_stay_on_while_plugged_in">false</bool><!-- Number of retries for connecting to DHCP.Value here is the same as WifiStateMachine.DEFAULT_MAX_DHCP_RETRIES --><integer name="def_max_dhcp_retries">9</integer><!-- Default for Settings.Secure.USER_SETUP_COMPLETE --><bool name="def_user_setup_complete">false</bool><!-- Default for Settings.Global.LOW_BATTERY_SOUND_TIMEOUT.0 means no timeout; battery sounds will always play>0 is milliseconds of screen-off time after which battery sounds will not play --><integer name="def_low_battery_sound_timeout">0</integer><!-- Initial value for the Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS setting,which is a comma separated list of packages that no longer need confirmationfor immersive mode.Override to disable immersive mode confirmation for certain packages. --><string name="def_immersive_mode_confirmations" translatable="false"></string><!-- Default for Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE --><integer name="def_wifi_scan_always_available">0</integer><!-- Default for Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1==on --><integer name="def_lock_screen_show_notifications">1</integer><!-- Default for Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS --><bool name="def_lock_screen_allow_private_notifications">true</bool><!-- Default for Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, 1==on --><integer name="def_heads_up_enabled">1</integer><!-- Default for Settings.Global.DEVICE_NAME $1=MANUFACTURER $2=MODEL--><string name="def_device_name">%1$s %2$s</string><!-- Default for Settings.Global.DEVICE_NAME $1=MODEL--><string name="def_device_name_simple">%1$s</string><!-- Default for Settings.Secure.WAKE_GESTURE_ENABLED --><bool name="def_wake_gesture_enabled">true</bool><!-- Default state of tap to wake --><bool name="def_double_tap_to_wake">true</bool><!-- Default for Settings.Secure.NFC_PAYMENT_COMPONENT --><string name="def_nfc_payment_component"></string><!-- Default setting for ability to add users from the lock screen --><bool name="def_add_users_from_lockscreen">false</bool><!--  default setting for Settings.System.END_BUTTON_BEHAVIOR : END_BUTTON_BEHAVIOR_SLEEP --><integer name="def_end_button_behavior">0x2</integer><!-- default setting for Settings.Global.DEFAULT_RESTRICT_BACKGROUND_DATA --><bool name="def_restrict_background_data">false</bool><!-- Default for Settings.Secure.BACKUP_MANAGER_CONSTANTS --><string name="def_backup_manager_constants"></string><!-- Default setting for Settings.Global.MOBILE_DATA_ALWAYS_ON --><bool name="def_mobile_data_always_on">true</bool><!-- Default for Settings.Secure.BACKUP_LOCAL_TRANSPORT_PARAMETERS --><string name="def_backup_local_transport_parameters"></string><!-- Default for Settings.Global.ZEN_DURATIONIf 0, turning on dnd manually will last indefinitely.Else if non-negative, turning on dnd manually will last for this many minutes.Else (if negative), turning on dnd manually will surface a dialog that promptsuser to specify a duration.--><integer name="def_zen_duration">0</integer><!-- Default for Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS --><string name="def_backup_agent_timeout_parameters"></string><!-- Default for Settings.System.VIBRATE_WHEN_RINGING --><bool name="def_vibrate_when_ringing">false</bool><!-- Default for Settings.Global.APPLY_RAMPING_RINGER --><bool name="def_apply_ramping_ringer">false</bool><!-- Default for Settings.Secure.CHARGING_VIBRATION_ENABLED --><bool name="def_charging_vibration_enabled">true</bool><!-- Default for Settings.Secure.CHARGING_SOUNDS_ENABLED --><bool name="def_charging_sounds_enabled">true</bool><!-- Default for Settings.Secure.NOTIFICATION_BUBBLES --><bool name="def_notification_bubbles">true</bool><!-- Default for Settings.Secure.AWARE_ENABLED --><bool name="def_aware_enabled">false</bool><!-- Default for Settings.Secure.SKIP_GESTURE --><bool name="def_skip_gesture">false</bool><!-- Default for Settings.Secure.SILENCE_GESTURE --><bool name="def_silence_gesture">false</bool><!-- Default for Settings.Secure.AWARE_LOCK_ENABLED --><bool name="def_aware_lock_enabled">false</bool><!-- Default for setting for Settings.Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED --><bool name="def_hdmiControlAutoDeviceOff">false</bool>
</resources>

(5)DatabaseHelper.java

//frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.javaclass DatabaseHelper extends SQLiteOpenHelper {private static final String TAG = "SettingsProvider";private static final String DATABASE_NAME = "settings.db";private static final int DATABASE_VERSION = 118;private static final String DATABASE_BACKUP_SUFFIX = "-backup";private static final String TABLE_SYSTEM = "system";private static final String TABLE_SECURE = "secure";private static final String TABLE_GLOBAL = "global";private void createSecureTable(SQLiteDatabase db) {db.execSQL("CREATE TABLE secure (" +"_id INTEGER PRIMARY KEY AUTOINCREMENT," +"name TEXT UNIQUE ON CONFLICT REPLACE," +"value TEXT" +");");db.execSQL("CREATE INDEX secureIndex1 ON secure (name);");}private void createGlobalTable(SQLiteDatabase db) {db.execSQL("CREATE TABLE global (" +"_id INTEGER PRIMARY KEY AUTOINCREMENT," +"name TEXT UNIQUE ON CONFLICT REPLACE," +"value TEXT" +");");db.execSQL("CREATE INDEX globalIndex1 ON global (name);");}@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL("CREATE TABLE system (" +"_id INTEGER PRIMARY KEY AUTOINCREMENT," +"name TEXT UNIQUE ON CONFLICT REPLACE," +"value TEXT" +");");db.execSQL("CREATE INDEX systemIndex1 ON system (name);");createSecureTable(db);// Only create the global table for the singleton 'owner/system' userif (mUserHandle == UserHandle.USER_SYSTEM) {createGlobalTable(db);}db.execSQL("CREATE TABLE bluetooth_devices (" +"_id INTEGER PRIMARY KEY," +"name TEXT," +"addr TEXT," +"channel INTEGER," +"type INTEGER" +");");db.execSQL("CREATE TABLE bookmarks (" +"_id INTEGER PRIMARY KEY," +"title TEXT," +"folder TEXT," +"intent TEXT," +"shortcut INTEGER," +"ordering INTEGER" +");");db.execSQL("CREATE INDEX bookmarksIndex1 ON bookmarks (folder);");db.execSQL("CREATE INDEX bookmarksIndex2 ON bookmarks (shortcut);");// Populate bookmarks table with initial bookmarksboolean onlyCore = false;try {onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService("package")).isOnlyCoreApps();} catch (RemoteException e) {}if (!onlyCore) {loadBookmarks(db);}// Load initial volume levels into DBloadVolumeLevels(db);// Load inital settings valuesloadSettings(db);}//...private void loadSettings(SQLiteDatabase db) {loadSystemSettings(db);loadSecureSettings(db);// The global table only exists for the 'owner/system' userif (mUserHandle == UserHandle.USER_SYSTEM) {loadGlobalSettings(db);}}private void loadSystemSettings(SQLiteDatabase db) {SQLiteStatement stmt = null;try {stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"+ " VALUES(?,?);");loadBooleanSetting(stmt, Settings.System.DIM_SCREEN,R.bool.def_dim_screen);loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,R.integer.def_screen_off_timeout);// Set default cdma DTMF typeloadSetting(stmt, Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, 0);// Set default hearing aidloadSetting(stmt, Settings.System.HEARING_AID, 0);// Set default tty modeloadSetting(stmt, Settings.System.TTY_MODE, 0);loadIntegerSetting(stmt, Settings.System.SCREEN_BRIGHTNESS,R.integer.def_screen_brightness);loadIntegerSetting(stmt, Settings.System.SCREEN_BRIGHTNESS_FOR_VR,com.android.internal.R.integer.config_screenBrightnessForVrSettingDefault);loadBooleanSetting(stmt, Settings.System.SCREEN_BRIGHTNESS_MODE,R.bool.def_screen_brightness_automatic_mode);loadBooleanSetting(stmt, Settings.System.ACCELEROMETER_ROTATION,R.bool.def_accelerometer_rotation);loadDefaultHapticSettings(stmt);loadBooleanSetting(stmt, Settings.System.NOTIFICATION_LIGHT_PULSE,R.bool.def_notification_pulse);loadUISoundEffectsSettings(stmt);loadIntegerSetting(stmt, Settings.System.POINTER_SPEED,R.integer.def_pointer_speed);} finally {if (stmt != null) stmt.close();}}
}

在DatabaseHelper.java的方法中用于加载defaults.xml定义的相关字段。

(6)封装SettingsProvider接口(Settings.java)

对ContentProvider的一些接口进行封装,以保证在整个Android的java层任何一个地方都能方便、快捷的使用SettingsProvider进行数据查询,数据更新和数据插入。所以,framework有一个类Settings.java对SettingsProvider进行了封装。如下:

//frameworks/base/core/java/android/provider/Settings.java/*** The Settings provider contains global system-level device preferences.*/
public final class Settings {@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)public static final String ACTION_SETTINGS = "android.settings.SETTINGS";@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)public static final String ACTION_USER_SETTINGS ="android.settings.USER_SETTINGS";//...public static final class Global extends NameValueTable {public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/global");public static final String AIRPLANE_MODE_ON = "airplane_mode_on";public static final String THEATER_MODE_ON = "theater_mode_on";//...}public static final class System extends NameValueTable {public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/system");}public static final class Secure extends NameValueTable {public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/secure");
}

上面的代码中,分别声明了Global、Secure、System三个静态内部类,分别对应SettingsProvider中的Global、Secure、System三种数据类型。Global、Secure、System三个静态内部类会分别持有NameValueCache的实例变量,进而通过AIDL远程调用IContentProvider。

查询数据需要经过NameValueCache的getStringForUser()方法,插入数据需要经过putStringForUser()方法。

(7)操作SettingsProvider

由于Settings.java对SettingsProvider进行了封装,所以,使用起来相当简单简洁。Global、Secure、System三种数据类型的使用是几乎相同。

//查询数据
String globalValue = Settings.Global.getString(getContentResolver(), Settings.Global.AIRPLANE_MODE_ON);
//插入数据
boolean isSuccess = Settings.System.putInt(getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);

(8)第三方APP使用SettingsProvider

第三方APP可以通过framework的Settings.java查询SettingsProvider中的设置项,第三APP是否可以修改SettingsProvider的设置项?Android系统不允许第三方APP修改SettingsProvider中的设置项。

查阅SettingsProvider的设置项不需要声明任何权限。
修改SettingsProvider需要权限:

  • android.permission.WRITE_SETTINGS
  • android.permission.WRITE_SECURE_SETTINGS

Android系统之SettingsProvider(二)相关推荐

  1. 深入Android系统(十二)Android图形显示系统-2-SurfaceFlinger与图像输出

    最近有些忙,切实体验了一把拖更的羞耻感 ( *︾▽︾) 本文和上一篇深入Android系统(十二)Android图形显示系统-1-显示原理与Surface关系比较密切,撸完前篇更易理解本文啦 (๑‾ ...

  2. NDK JNI方式读写Android系统的demo(二)

    NDK & JNI(方式读写Android系统的Demo) 大家都知道Android系统是一种基于Linux的自由及开放源码的操作系统,所以读写GPIO也可以直接用Linux那一套export ...

  3. 定制Android系统开发之二——系统服务

    转自:http://blog.csdn.net/wtianok/article/details/49175581 何为系统服务 做Android APP开发的过程中,会经常需要调用类似于下面这样的函数 ...

  4. cm-14.1 Android系统定制(二):内置系统应用

    声明 Android系统定制时免不了预置一些APP进系统中: 预置的结果一般有三种:       1.预置的APK用户可以卸载,恢复出厂设置后APK不恢复:       2.预置的APP用户可以卸载, ...

  5. Android 系统开发系列二

    这一章主要是讲如何测试驱动. 1.驱动的简单测试 在上一篇文章中,我们已经把添加驱动模块做完了,并把驱动下载到了板子上.下面将介绍一下如何测试驱动是否正常. 这个ttt驱动,我们实现了一个读.一个写的 ...

  6. Android系统之ContentObserver和SettingsProvider结合使用(三)

    通过前两篇的文章: Android系统之registerContentObserver(一) Android系统之SettingsProvider(二) 我们了解了如何通过registerConten ...

  7. Android开发笔记(二)颜色的使用

    颜色的编码 Android中颜色值的定义是由透明度alpha和RGB(红绿蓝)三原色来定义的,有八位十六进制数与六位十六进制数两种编码,例如八位FFEEDDCC,前两位FF表示透明度,后面两位EE表示 ...

  8. android 服务端技术,移动应用服务器端开发(基于JSP技术)-2017 Android系统构架 Android系统构架.docx...

    Android系统构架 PAGE 1 目 录 TOC \o "1-3" \h \z \u 一.Android系统构架 1 二.Linux内核层 2 三.系统运行库层 3 (一)系统 ...

  9. 用于Android系统的pango + cairo交叉编译

    做Android系统下的开发也有几年了,这几年间也遇到过很多问题,大多是从网上搜索解决办法,虽然不是都能找到完美的解决办法,但是基本对于结局问题是有帮助的,所以一直也没有整理遇到的问题(主要是太懒了! ...

最新文章

  1. C#中接口和方法的运用(Fourteenth Day)
  2. Linux内核网络数据发送(六)——网络设备驱动
  3. Intent Flag介绍 intent.addFlags()
  4. 资深工程师为何否定这种单例模式
  5. Taro+react开发(15)--对应文件编译
  6. 出租车管理系统java_基于jsp的出租车管理系统-JavaEE实现出租车管理系统 - java项目源码...
  7. 扎实的基础知识、高质量的代码
  8. C++总结:static_cast ,reinterpret_cast
  9. Beyond Compare 4 智能比较工具、Everything 文件/夹搜索工具,WinRAR,7-Zip 解压缩工具、diagrams 流程图工具
  10. ie9以下兼容html5,兼容ie9以下支持媒体查询和html5
  11. Vmware安装vmware-tools后,仍无法上网
  12. [codility]Equi-leader
  13. android数据库可视化工具
  14. CCNP-OSPF中SPF(最短路径树)算法剖析,建树过程示例
  15. 保利威视云直播的python API
  16. 爱好-C语言秘钥产生器
  17. C语言PAT刷题 - 1019 数字黑洞
  18. 为什么OKR新手要懂得OKRs-E?
  19. Me and My Girlfriend:1
  20. 飞机躲子弹小游戏案例

热门文章

  1. 【微服务】RestClient查询文档
  2. python 语音数据加载和保存
  3. 配置管理-使用SVN创建分支
  4. 2021最全大数据面试题汇总---hadoop篇,附答案!
  5. 「面试必背」Java集合面试题(收藏)
  6. 大学计算机操作题模拟,《大学计算机基础》上模拟试卷操作题
  7. vue中如何使用JS通过a标签下载文件
  8. 机器学习-62-Structured Learning-03-Structured Support Vector Machine(结构化学习-结构化支持向量机)
  9. EGO1—实现8选1的数据选择器74HC151
  10. uin-app 使用阿里云iconfont图标