Android运用Kotlin封装MMKVUtils

Android使用Kotlin封装MMKVUtils

1.简介:

MMKV 是根据 mmap 内存映射的 key-value 组件,底层序列化/反序列化运用 protobuf 完成,功能高,稳定性强。从 2015 年中至今在微信上运用,其功能和稳定性经过了时间的验证。近期也已移植到 Android / macOS / Win32 / POSIX 渠道,一并开源。

2.MMKV 源起

在微信客户端的日常运营中,时不时就会迸发特殊文字引起体系的 crash, 参阅文章,文章里面规划的技术计划是在要害代码前后进行计数器的加减,经过检查计数器的反常,来发现引起闪退的反常文字。在会话列表、会话界面等有大量 cell 的地方,期望新加的计时器不会影响滑动功能;别的这些计数器还要永久存储下来——由于闪退随时可能发生。这就需求一个功能十分高的通用 key-value 存储组件,咱们考察了 SharedPreferences、NSUserDefaults、SQLite 等常见组件,发现都没能满足如此严苛的功能要求。考虑到这个防 crash 计划最主要的诉求仍是实时写入,而 mmap 内存映射文件刚好满足这种需求,咱们测验经过它来完成一套 key-value 组件。

3.MMKV 原理

  • 内存预备 经过 mmap 内存映射文件,提供一段可供随时写入的内存块,App 只管往里面写数据,由操作体系负责将内存回写到文件,不用担心 crash 导致数据丢失。
  • 数据组织 数据序列化方面咱们选用 protobuf 协议,pb 在功能和空间占用上都有不错的表现。
  • 写入优化 考虑到主要运用场景是频频地进行写入更新,咱们需求有增量更新的才能。咱们考虑将增量 kv 目标序列化后,append 到内存末尾。
  • 空间增加 运用 append 完成增量更新带来了一个新的问题,便是不断 append 的话,文件大小会增加得不可控。咱们需求在功能和空间上做个折中。

更详细的规划原理参阅 MMKV 原理。

4.MMKV优势:

MMKV的呈现其实是为了处理SharedPreferences的一些问题,微信团队期望以此来代替SharedPreferences,现在在Android中,对于经常运用的快速本地化存储,大部分人往往会挑选SharedPreferences来作为存储方式, 作为Android库中自带的存储方式,SharePreferences在运用方式上仍是很快捷的,可是也往往存在以下的一些问题。

1、经过 getSharedPreferences 可以获取 SP 实例,从初次初始化到读到数据会存在延迟,由于读文件的操作阻塞调用的线程直到文件读取结束,假如在主线程调用,可能会对 UI 流畅度形成影响。(线程阻塞)

2、虽然支撑设置 MODE_MULTI_PROCESS 标志位,可是跨进程同享 SP 存在许多问题,所以不建议运用该模式。(文件跨进程同享)

3、将数据写入文件需求将数据复制两次,再写入到文件中,假如数据量过大,也会有很大的功能损耗。(二次写入)

5.MMKV支撑的数据类型:

支撑以下 Java 言语基础类型:

boolean、int、long、float、double、byte[],String、Set,任何完成了Parcelable的类型,目标存储方式是,转化成json串,经过字符串存储,运用的时分在取出来反序列化.

6.依靠导入:

implementation(libs.mmkv)

Android使用Kotlin封装MMKVUtils

7.AGP8.1统一依靠装备:

[versions]
agp = "8.1.0"
org-jetbrains-kotlin-android = "1.8.0"
core-ktx = "1.10.1"
junit = "4.13.2"
androidx-test-ext-junit = "1.1.5"
espresso-core = "3.5.1"
appcompat = "1.6.1"
material = "1.9.0"
constraintlayout = "2.1.4"
mmkv = "1.3.0"[libraries]
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" }
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" }
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
mmkv = { group = "com.tencent", name = "mmkv", version.ref = "mmkv" }
​
[plugins]
com-android-application = { id = "com.android.application", version.ref = "agp" }
org-jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "org-jetbrains-kotlin-android" }
​
[bundles]

8.App.gradle装备:

@Suppress("DSL_SCOPE_VIOLATION")
plugins {
  alias(libs.plugins.com.android.application)
  alias(libs.plugins.org.jetbrains.kotlin.android)
}
​
android {
  namespace = "com.example.mmkvdemo"
  compileSdk = 33
​
  defaultConfig {
    applicationId = "com.example.mmkvdemo"
    minSdk = 23
    targetSdk = 33
    versionCode = 1
    versionName = "1.0"testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
   }
​
  buildTypes {
    release {
      isMinifyEnabled = false
      proguardFiles(
        getDefaultProguardFile("proguard-android-optimize.txt"),
        "proguard-rules.pro"
       )
     }
   }
  compileOptions {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
   }
  kotlinOptions {
    jvmTarget = "1.8"
   }
}
​
dependencies {
  implementation(libs.core.ktx)
  implementation(libs.appcompat)
  implementation(libs.material)
  implementation(libs.constraintlayout)
  implementation(libs.mmkv)
  testImplementation(libs.junit)
  androidTestImplementation(libs.androidx.test.ext.junit)
  androidTestImplementation(libs.espresso.core)
}

9.运用java封装的东西类:

package com.example.lib_common.utils;
​
import android.content.Context;
import android.os.Environment;
​
import com.tencent.mmkv.MMKV;
​
/**
 * @author: njb
 * @date: 2023/8/9 14:53
 * @desc:
 */
public class MMKVUtils {
  private MMKV mmkv;
  private static volatile MMKVUtils mInstance;
​
  private MMKVUtils() {
​
   }
​
  public void init(Context context) {
    String dir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/mmkv";
    //mmkv初始化
    MMKV.initialize(context, dir);
    mmkv = MMKV.mmkvWithID("MyMMID");
    //开启跨进程通讯
    mmkv = MMKV.mmkvWithID("MyMMID", MMKV.MULTI_PROCESS_MODE);
   }
​
  public static MMKVUtils getInstance() {
    if (mInstance == null) {
      synchronized (MMKVUtils.class) {
        if (mInstance == null) {
          mInstance = new MMKVUtils();
         }
       }
     }
    return mInstance;
   }
​
  public void encode(String key, Object value) {
    if (value instanceof String) {
      mmkv.encode(key, (String) value);
     } else if (value instanceof Integer) {
      mmkv.encode(key, (Integer) value);
     } else if (value instanceof Boolean) {
      mmkv.encode(key, (Boolean) value);
     } else if (value instanceof Long) {
      mmkv.encode(key, (Long) value);
     } else if (value instanceof Float) {
      mmkv.encode(key, (Float) value);
     } else if (value instanceof Double) {
      mmkv.encode(key, (Double) value);
     }
   }
​
​
  public Integer decodeInt(String key) {
    return mmkv.decodeInt(key);
   }
​
  public String decodeString(String key) {
    return mmkv.decodeString(key, "");
   }
​
  public Boolean decodeBoolean(String key) {
    return mmkv.decodeBool(key);
   }
​
  public Long decodeLong(String key) {
    return mmkv.decodeLong(key);
   }
​
  public Float decodeFloat(String key) {
    return mmkv.decodeFloat(key);
   }
​
  public Double decodeDouble(String key) {
    return mmkv.decodeDouble(key);
   }
​
  public void clearAllData(){
    mmkv.clearAll();
   }
}
​

10.运用kotlin封装的东西类:

package com.example.lib_common.utils
​
import android.content.Context
import com.tencent.mmkv.MMKV
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
​
/**
 * @author: njb
 * @date: 2023/8/9 22:40
 * @desc:
 */
class MMKVUtil private constructor(){
  lateinit var mmKv:MMKV
  companion object {
    const val DATE_FORMAT = "yyyy-MM-dd HH.mm.ss"
    val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { MMKVUtil() }
   }
​
  fun init(context: Context) {
    //第一种运用mmkv默许目录
    //MMKV.initialize(context)
    //第二种运用自定义包名目录
     //MMKV.initialize(context, FileManager.getStorageRootDir() + FileManager.MMKV_DIR)val mFileDateFormat = SimpleDateFormat(DATE_FORMAT, Locale.US)
    //视频保存途径
    val file =
      File(FileManager.getMMKVPath(), mFileDateFormat.format(Date()) + "/mmkv")
    //第三种运用自定义的体系目录 dcim、download、music其中一个即可
    MMKV.initialize(context,file.absolutePath)
    mmKv = MMKV.mmkvWithID("MyMMKVTestID", MMKV.MULTI_PROCESS_MODE)
    mmKv.encode("bool", true)
   }
​
  fun initTest(context: Context) {
    //第一种运用mmkv默许目录
    //MMKV.initialize(context)
    //第二种运用自定义包名目录
    MMKV.initialize(context, FileManager.getStorageRootDir() + FileManager.MMKV_DIR)
    //第三种运用自定义的体系目录 dcim、download、music其中一个即可
    //MMKV.initialize(context,FileManager.getMMKVPath())
    mmKv = MMKV.mmkvWithID("MyTestID", MMKV.MULTI_PROCESS_MODE)
    mmKv.encode("bool", true)
   }
​
  fun encode(key: String, value: Any) {
    when (value) {
      is String -> mmKv.encode(key, value)
      is Int -> mmKv.encode(key, value)
      is Boolean -> mmKv.encode(key, value)
      is Long -> mmKv.encode(key, value)
      is Float -> mmKv.encode(key, value)
      is Double -> mmKv.encode(key, value)
     }
   }
​
  inline fun <reified T> decode(key: String, defaultValue: T): T = when (T::class) {
    String::class -> mmKv.decodeString(key, defaultValue as String?) as T
    Int::class -> mmKv.decodeInt(key, defaultValue as Int) as T
    Boolean::class -> mmKv.decodeBool(key, defaultValue as Boolean) as T
    Long::class -> mmKv.decodeLong(key, defaultValue as Long) as T
    Float::class -> mmKv.decodeFloat(key, defaultValue as Float) as T
    Double::class -> mmKv.decodeDouble(key, defaultValue as Double) as T
    else -> throw IllegalArgumentException("Unsupported type")
   }
}
​
​

11.初始化:

private fun performFileOperations() {
  MyApp.mInstance.initMMKV()
  // 履行文件读写操作
  initMMKVData()
}
​
package com.example.mmkvdemo
​
import android.app.Application
import com.example.mmkvdemo.utils.MMKVUtils
​
/**
 * @author: njb
 * @date: 2023/8/9 23:19
 * @desc:
 */
class MyApp :Application(){
  override fun onCreate() {
    super.onCreate()
    // initMMKV()
    mInstance = this
   }
​
  fun initMMKV() {
    MMKVUtils.instance.init(this)
   }
​
  companion object{
    lateinit var mInstance: MyApp
      private set
   }
}

Android使用Kotlin封装MMKVUtils

12.简单运用:

private fun performFileOperations() {
    MyApp.mInstance.initMMKV()
    // 履行文件读写操作
    initMMKVData()
   }
​
  private fun initMMKVData() {
    // 存储数据
    MMKVUtils.instance.encode("key1", "value1")
    MMKVUtils.instance.encode("key2", "456")
   }
  
@SuppressLint("SetTextI18n")
private fun initView() {
  textView.setOnClickListener {
    // 读取数据
    val value1: String = MMKVUtils.instance.decode("key1","")
    val value2: String = MMKVUtils.instance.decode("key2","")
    Log.d(TAG, "====数据为===$value1$value2")
    textView.text = value1 + value2
   }
}

13.适配Android13:

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)
  // 检查并恳求权限
  if (checkPermissions()) {
    // 已经有权限,履行文件读写操作
    performFileOperations()
   } else {
    // 恳求权限
    requestPermission()
   }
  initView()
}
​
 private fun checkPermissions(): Boolean {
    if (VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
      PERMISSIONS = arrayOf<String>(Manifest.permission.READ_EXTERNAL_STORAGE)
      for (permission in PERMISSIONS) {
        if (ContextCompat.checkSelfPermission(
            this,
            permission
           ) != PackageManager.PERMISSION_GRANTED
         ) {
          return false
         }
       }
     } else {
      for (permission in PERMISSIONS) {
        if (ContextCompat.checkSelfPermission(
            this,
            permission
           ) != PackageManager.PERMISSION_GRANTED
         ) {
          return false
         }
       }
     }
    return true
   }
​
  private fun requestPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
      PERMISSIONS = arrayOf<String>(Manifest.permission.READ_EXTERNAL_STORAGE)
      ActivityCompat.requestPermissions(
        this,
        PERMISSIONS,
        REQUEST_PERMISSION_CODE
       )
     } else {
      ActivityCompat.requestPermissions(
        this,
        PERMISSIONS,
        REQUEST_PERMISSION_CODE
       )
     }
   }
​
  private fun performFileOperations() {
    MyApp.mInstance.initMMKV()
    // 履行文件读写操作
    initMMKVData()
   }
​
  override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<String?>,
    grantResults: IntArray
   ) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == REQUEST_PERMISSION_CODE) {
      var allPermissionsGranted = true
      for (result in grantResults) {
        if (result != PackageManager.PERMISSION_GRANTED) {
          allPermissionsGranted = false
          break
         }
       }
      if (allPermissionsGranted) {
        // 权限已颁发,履行文件读写操作
        performFileOperations()
       } else {
        // 权限被回绝,处理权限恳求失利的状况
       }
     }
   }

14.完整运用代码:

package com.example.mmkvdemo
​
import android.Manifest
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.os.Build
import android.os.Build.VERSION
import android.os.Bundle
import android.util.Log
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.example.mmkvdemo.utils.MMKVUtils
​
class MainActivity : AppCompatActivity() {
  private val TAG = MainActivity::class.java.name
  private val REQUEST_PERMISSION_CODE = 100
  private var PERMISSIONS: Array<String> = arrayOf(
    Manifest.permission.WRITE_EXTERNAL_STORAGE,
    Manifest.permission.READ_EXTERNAL_STORAGE
   )
  private val textView:TextView by lazy { findViewById(R.id.tv_test) }
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    // 检查并恳求权限
    if (checkPermissions()) {
      // 已经有权限,履行文件读写操作
      performFileOperations()
     } else {
      // 恳求权限
      requestPermission()
     }
    initView()
   }
​
  @SuppressLint("SetTextI18n")
  private fun initView() {
    textView.setOnClickListener {
      // 读取数据
      val value1: String = MMKVUtils.instance.decode("key1","")
      val value2: String = MMKVUtils.instance.decode("key2","")
      Log.d(TAG, "====数据为===$value1$value2")
      textView.text = value1 + value2
     }
   }
​
  private fun checkPermissions(): Boolean {
    if (VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
      PERMISSIONS = arrayOf<String>(Manifest.permission.READ_EXTERNAL_STORAGE)
      for (permission in PERMISSIONS) {
        if (ContextCompat.checkSelfPermission(
            this,
            permission
           ) != PackageManager.PERMISSION_GRANTED
         ) {
          return false
         }
       }
     } else {
      for (permission in PERMISSIONS) {
        if (ContextCompat.checkSelfPermission(
            this,
            permission
           ) != PackageManager.PERMISSION_GRANTED
         ) {
          return false
         }
       }
     }
    return true
   }
​
  private fun requestPermission() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
      PERMISSIONS = arrayOf<String>(Manifest.permission.READ_EXTERNAL_STORAGE)
      ActivityCompat.requestPermissions(
        this,
        PERMISSIONS,
        REQUEST_PERMISSION_CODE
       )
     } else {
      ActivityCompat.requestPermissions(
        this,
        PERMISSIONS,
        REQUEST_PERMISSION_CODE
       )
     }
   }
​
  private fun performFileOperations() {
    MyApp.mInstance.initMMKV()
    // 履行文件读写操作
    initMMKVData()
   }
​
  private fun initMMKVData() {
    // 存储数据
    MMKVUtils.instance.encode("key1", "value1")
    MMKVUtils.instance.encode("key2", "456")
   }
​
  override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<String?>,
    grantResults: IntArray
   ) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == REQUEST_PERMISSION_CODE) {
      var allPermissionsGranted = true
      for (result in grantResults) {
        if (result != PackageManager.PERMISSION_GRANTED) {
          allPermissionsGranted = false
          break
         }
       }
      if (allPermissionsGranted) {
        // 权限已颁发,履行文件读写操作
        performFileOperations()
       } else {
        // 权限被回绝,处理权限恳求失利的状况
       }
     }
   }
​
}

15.布局代码:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".MainActivity">
​
  <TextView
    android:id="@+id/tv_test"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello World!"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />
​
</androidx.constraintlayout.widget.ConstraintLayout>

16.跨进程运用:

16.1 主App存储数据

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    // 检查并恳求权限
    if (checkPermissions()) {
      // 已经有权限,履行文件读写操作
      performFileOperations()
     } else {
      // 恳求权限
      requestPermission()
     }
    initView()
 }
​
private fun performFileOperations() {
    //BaseApplication.Instance.initMMKV()
    // 履行文件读写操作
    initMMKVData()
}
​
private fun initMMKVData() {
    // 存储数据
    MMKVUtils.getInstance().encode("key1", "用户小明")
    MMKVUtils.getInstance().encode("age", 23)
    MMKVUtils.getInstance().encode("sex", "男")
    MMKVUtils.getInstance().encode("address", "北京市朝阳区")
    MMKVUtils.getInstance().encode("birthday", "2020-01-18")
    MMKVUtils.getInstance().encode("account", "188888")
    MMKVUtils.getInstance().encode("identity", false)
    MMKVUtils.getInstance().encode("amount", 888888.88)
}
​
@SuppressLint("SetTextI18n")
private fun initView() {
    textView.setOnClickListener {
      // 读取数据
      val value1: String = MMKVUtils.getInstance().decodeString("key1")
      val age: Int = MMKVUtils.getInstance().decodeInt("age")
      val sex: String = MMKVUtils.getInstance().decodeString("sex")
      val address: String = MMKVUtils.getInstance().decodeString("address")
      val birthday: String = MMKVUtils.getInstance().decodeString("birthday")
      val account: String = MMKVUtils.getInstance().decodeString("account")
      val identity: Boolean = MMKVUtils.getInstance().decodeBoolean("identity")
      val amount: Double = MMKVUtils.getInstance().decodeDouble("amount")
      Log.d(TAG, "====数据为===$value1$age$sex$address$birthday$account$identity$account$amount")
      textView.text = value1
      try {
        ToolUtils.openApp("com.example.testmmkv", this@MainActivity)
        // ToolUtils.openThirdApp("om.example.testmmkv", this@MainActivity)
       }catch (e:Exception){
        e.printStackTrace()
       }
     }
}
​
​

16.2 跨进程TestApp接收数据:

private fun performFileOperations() {
  // BaseApplication.Instance.initMMKV()
  initData()
}
  private fun initData() {
    val userName = MMKVUtils.getInstance().decodeString("key1")
    val age: Int = MMKVUtils.getInstance().decodeInt("age")
    val sex: String = MMKVUtils.getInstance().decodeString("sex")
    val address: String = MMKVUtils.getInstance().decodeString("address")
    val birthday: String = MMKVUtils.getInstance().decodeString("birthday")
    val account: String = MMKVUtils.getInstance().decodeString("account")
    val identity: Boolean = MMKVUtils.getInstance().decodeBoolean("identity")
    val amount: Double = MMKVUtils.getInstance().decodeDouble("amount")
    textView.text = "用户姓名:$userName"
    tvAddress.text = "用户地址:$address"
    tvAge.text = "用户年龄:$age"
    tvAccount.text = "用户账号:$account"
    tvAmount.text = "用户金额:$amount"
    tvBirthday.text = "用户生日:$birthday"
    tvIdentity.text = "是否党员:$identity"
    tvSex.text = "用户性别:$sex"
    Log.d(TAG, "====跨进程通讯测试数据===$userName$age$sex$address$birthday$account$identity$account$amount")
    tvBack.setOnClickListener {
      try {
        MMKVUtils.getInstance().encode("backKey","用户小明回到本来的运用")
        finish()
        // ToolUtils.openApp("com.example.mmkvdemo", this@MainActivity)
        // ToolUtils.openThirdApp("om.example.testmmkv", this@MainActivity)
       }catch (e:Exception){
        e.printStackTrace()
       }
     }
   }

17.日志打印:

Android使用Kotlin封装MMKVUtils

Android使用Kotlin封装MMKVUtils

Android使用Kotlin封装MMKVUtils

18.翻开第三方app东西类:

package com.example.mmkvdemo.utils;
​
import static android.content.Context.ACTIVITY_SERVICE;
​
import android.app.Activity;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
​
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.util.List;
​
/**
 * @author: njb
 * @date: 2023/8/8 0:03
 * @desc:
 */
public class ToolUtils {
  private static final String TAG = ToolUtils.class.getName();
​
  /**
   * 翻开软件
   *
   * @param packageName 包名
   * @param context   上下文目标
   */
  public static void openApp(String packageName, Context context) {
    if (packageName != null) {
      PackageManager packageManager = context.getPackageManager();
      Intent intent = packageManager.getLaunchIntentForPackage(packageName);
      context.startActivity(intent);
     }
   }
​
  public static void openApp(String packageName, Context context, Bundle bundle) {
    Intent intent = new Intent();
    ComponentName comp = new ComponentName("com.tencent.mobileqq", "com.tencent.mobileqq.activity.SplashActivity");
    intent.setComponent(comp);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(intent);
   }
​
​
  /**
   * 获取前台程序包名
   */
  public static String getForegroundAppPackageName(Context context) {
    ActivityManager am = (ActivityManager) context.getSystemService(Activity.ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
    ComponentName componentInfo = taskInfo.get(0).topActivity;
    return componentInfo.getPackageName();
   }
​
  /**
   * 根据报名杀死运用
   */
  public static void killApp(Context context, String packageName) {
    try {
      ActivityManager m = (ActivityManager) context.getSystemService(ACTIVITY_SERVICE);
      Method method = m.getClass().getMethod("forceStopPackage", String.class);
      method.setAccessible(true);
      method.invoke(m, packageName);
     } catch (Exception e) {
      e.printStackTrace();
     }
   }
​
  /**
   * 杀死第三方运用
   *
   * @param context
   * @param packageName
   */
  public static void killThirdApp(Context context, String packageName) {
    if (packageName != null) {
      killApp(context, packageName);
     }
   }
​
​
​
  /**
   * 获取前台activity名称
   *
   * @param context
   * @return
   */
  public static String getForegroundActivityName(Context context) {
    if (context == null) {
      return "";
     }
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> list = am.getRunningTasks(1);
    if (list != null && list.size() > 0) {
      ComponentName cpn = list.get(0).topActivity;
      return cpn.getClassName();
     }
    return "";
   }
​
​
  /**
   * 判断APP是否安装了
   *
   * @param packageName 包名
   * @return
   */
  public static boolean isAppInstalled(Context context, String packageName) {
    PackageManager packageManager = context.getPackageManager();
    try {
      packageManager.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
      return true;
     } catch (PackageManager.NameNotFoundException e) {
      e.printStackTrace();
      return false;
     }
   }
​
​
​
  public static void unInstall(Context context, String packageName) {
    if (packageName == null) {
      return;
     }
    Uri uri = Uri.parse("package:" + packageName);
    Intent uninstall = new Intent(Intent.ACTION_DELETE, uri);
    uninstall.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(uninstall);
   }
​
  /**
   * 静默卸载App
   *
   * @param packageName  包名
   * @return 是否卸载成功
   */
  public static boolean uninstall(String packageName) {
    Process process = null;
    BufferedReader successResult = null;
    BufferedReader errorResult = null;
    StringBuilder successMsg = new StringBuilder();
    StringBuilder errorMsg = new StringBuilder();
    try {
      process = new ProcessBuilder("pm", "uninstall", packageName).start();
      successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
      errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
      String s;
      while ((s = successResult.readLine()) != null) {
        successMsg.append(s);
       }
      while ((s = errorResult.readLine()) != null) {
        errorMsg.append(s);
       }
     } catch (Exception e) {
      Log.d("e = " , e.toString());
     } finally {
      try {
        if (successResult != null) {
          successResult.close();
         }
        if (errorResult != null) {
          errorResult.close();
         }
       } catch (Exception e) {
        Log.d("Exception : " , e.toString());
       }
      if (process != null) {
        process.destroy();
       }
     }
    //假如含有"success"单词则认为卸载成功
    return successMsg.toString().equalsIgnoreCase("success");
   }
​
  /**
   * 判断运用是否存在
   *
   * @param context   上下文
   * @param packageName 包名
   * @return 是否存在
   */
  private boolean appExist(Context context, String packageName) {
    try {
      List<PackageInfo> packageInfoList = context.getPackageManager().getInstalledPackages(0);
      for (PackageInfo packageInfo : packageInfoList) {
        if (packageInfo.packageName.equalsIgnoreCase(packageName)) {
          return true;
         }
       }
     } catch (Exception e) {
      Log.d(TAG,e.toString());
     }
    return false;
   }
}

19.完成作用:

Android使用Kotlin封装MMKVUtils

Android使用Kotlin封装MMKVUtils

20.总结:

以上便是今日的内容运用Kotlin封装根据MMKV的东西类,现在基本的数据存储没啥问题,可是跨进程在Android13中有点问题,两个app的存储目录不一样导致数据储存成功,可是跨进程时只能读取到本app目录下的数据,还没想好处理方法,Android9中及以下是可以正常运用的,由于11及以上内外部存储发生了改变,官网在1.3.1版别中更新了关于Android13的适配,他们给出的计划把两个app的mmkv文件存储写入到同一个公共的目录,后边有时间在测验一下,如有处理的小伙伴们说一下.

21.项目demo源码:

gitee.com/jackning_ad…