From 89e35a1933ba40513a96572b27291c0aa65c918c Mon Sep 17 00:00:00 2001
From: Runt <qingingrunt2010@qq.com>
Date: Sat, 11 Oct 2025 10:21:42 +0000
Subject: [PATCH] 框架优化
---
libmvi/src/main/java/com/runt/open/mvi/base/BaseActivity.kt | 360 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 318 insertions(+), 42 deletions(-)
diff --git a/libmvi/src/main/java/com/runt/open/mvi/base/BaseActivity.kt b/libmvi/src/main/java/com/runt/open/mvi/base/BaseActivity.kt
index 4076d40..5e1dfb0 100644
--- a/libmvi/src/main/java/com/runt/open/mvi/base/BaseActivity.kt
+++ b/libmvi/src/main/java/com/runt/open/mvi/base/BaseActivity.kt
@@ -1,18 +1,28 @@
package com.runt.open.mvi.base
import android.Manifest
+import android.app.ActivityManager
+import android.app.UiModeManager
+import android.content.ClipData
+import android.content.ClipboardManager
+import android.content.ContentResolver
import android.content.Context
import android.content.Intent
-import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
+import android.content.res.Configuration
+import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
+import android.provider.MediaStore
+import android.provider.Settings
+import android.text.TextUtils
import android.util.Log
import android.view.MotionEvent
import android.view.View
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
+import android.webkit.MimeTypeMap
import android.widget.EditText
import android.widget.Toast
import androidx.activity.ComponentActivity
@@ -22,6 +32,7 @@
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.ColorRes
+import androidx.annotation.StringDef
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
@@ -29,6 +40,7 @@
import com.runt.open.mvi.R
import com.runt.open.mvi.base.model.BaseViewModel
import com.runt.open.mvi.base.model.ViewModelFactory
+import com.runt.open.mvi.utils.FileUtils
import com.runt.open.mvi.utils.PreferencesUtils
import java.io.File
import java.lang.reflect.ParameterizedType
@@ -53,6 +65,12 @@
val PARAMS_TITLE = "title"
+ private var requestFileResult:Observer<List<String>>? = null;
+
+ private var fileLauncher : ActivityResultLauncher<Intent>? = null //选择文件
+ private var multipleFileLauncher : ActivityResultLauncher<Array<String>>? = null //选择文件
+ private var filePermissionLauncher : ActivityResultLauncher<Intent>? = null //文件权限
+ private val fileUriList = mutableListOf<Uri>()
override fun onCreate(savedInstanceState : Bundle?) {
super.onCreate(savedInstanceState) // get genericity "B"
@@ -77,7 +95,7 @@
init();
//setContentView(mLayout)
setContent {
- mLayout!!.layout()
+ mLayout!!.layoutFrame()
}
mContext = this
TAG = this.javaClass.simpleName
@@ -85,18 +103,50 @@
mViewModel!!.onCreate(this as BaseActivity<LayoutView<BaseViewModel> , BaseViewModel>)
loadData() //加载数据
}
+
+ override fun onPause() {
+ super.onPause()
+ mViewModel!!.onPause()
+ Log.i(TAG , "onPause: ")
+ }
+
+ override fun onResume() {
+ super.onResume()
+ mViewModel!!.onResume()
+ Log.i(TAG , "onResume: ")
+ }
+
+ override fun onStart() {
+ super.onStart()
+ mViewModel!!.onStart()
+ Log.i(TAG , "onStart: ")
+ }
+
+ override fun onStop() {
+ super.onStop()
+ mViewModel!!.onStop()
+ Log.i(TAG , "onStop: ")
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ mViewModel!!.onDestroy()
+ Log.i(TAG , "onDestroy: ")
+ }
+
abstract fun init()
abstract fun initViews()
abstract fun loadData()
- fun registerPermissionResult(){
+ protected fun registerPermissionResult(){
permissionsLauncher = this.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result ->
if (result == null || result.size === 0) {
permissionObserver !!.onChanged("")
return@registerForActivityResult
}
+ mViewModel!!.hidePopupWindow()
Log.d(TAG , "result:" + result + " size:" + result.size)
var allGranted = true
for (key in result.keys) {
@@ -112,6 +162,130 @@
permissionObserver !!.onChanged(com.google.gson.Gson().toJson(result.keys).replace("[" , "").replace("]" , "").replace("\"" , ""))
}
}
+ }
+
+ protected fun registerFileResult(){
+
+ filePermissionLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
+ Log.i(TAG,"filePermission ${result}")
+ onRequestFileResult();
+ }
+ multipleFileLauncher = registerForActivityResult(ActivityResultContracts.OpenMultipleDocuments()) { uris ->
+ fileUriList.clear();
+ fileUriList.addAll(uris);
+ Log.i(TAG,"multipleFileLauncher ${uris}")
+ if(fileUriList.size == 0){
+ requestFileResult?.onChanged(ArrayList())
+ }else{
+ onRequestFileResult();
+ }
+ }
+
+ //选择文件
+ fileLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult() , object : ActivityResultCallback<ActivityResult?> {
+ override fun onActivityResult(result : ActivityResult?) {
+ Log.i(TAG,"fileLauncher ${result!!.data?.data}")
+ Log.i(TAG,"fileLauncher clipData= ${result!!.data?.clipData}")
+ fileUriList.clear();
+ result!!.data?.data?.let{
+ fileUriList.add(it);
+ }
+ result!!.data?.clipData?.let{
+ val count = it.itemCount
+ for (i in 0 until count) {
+ fileUriList.add(it.getItemAt(i).uri)
+ }
+ }
+ if(fileUriList.size == 0){
+ requestFileResult?.onChanged(ArrayList())
+ }else{
+ onRequestFileResult();
+ }
+ }
+ })
+ }
+
+ private fun onRequestFileResult(){
+
+ val cR : ContentResolver = getContentResolver()
+ val mime = MimeTypeMap.getSingleton()
+ var filePath = FileUtils.getFilePathFromUri(fileUriList.get(0)!!);
+ //文件不存在或读写权限受限
+ if(filePath == null){
+ //android 11需要申请权限 //是否有所有问读写权限
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && ! Environment.isExternalStorageManager()) {
+ //跳转到打开权限页面
+ var intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
+
+ intent.setData(Uri.parse("package:" + mContext!!.getPackageName()));
+ filePermissionLauncher!!.launch(intent)
+ return;
+ }
+ requestFileResult?.onChanged(ArrayList())
+ }else{
+ var filePathes = ArrayList<String>()
+ for (i in 0 until fileUriList.size) {
+ var filePath = FileUtils.getFilePathFromUri(fileUriList.get(i)!!);
+ filePathes.add(filePath!!)
+ }
+ requestFileResult?.onChanged(filePathes)
+ }
+ }
+
+ @Retention(AnnotationRetention.SOURCE)
+ @StringDef(Manifest.permission.READ_MEDIA_VIDEO, Manifest.permission.READ_MEDIA_AUDIO, Manifest.permission.READ_MEDIA_IMAGES)
+ annotation class ManifestType
+
+ fun requestFile(@ManifestType fileType :String,maxCount:Int = 1,fileResult:Observer<List<String>>){
+ requestFileResult = fileResult;
+ var permissions = "";
+ //android 13 权限申请细化类型
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ permissions = fileType ;
+ //android 14 选择文件授权
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ permissions+=","+ Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED;
+ }
+ }else{
+ //读取权限
+ permissions = Manifest.permission.READ_EXTERNAL_STORAGE ;
+ }
+ //申请权限
+ requestPermissions(permissions , object :Observer<String>{
+ override fun onChanged(value : String) {
+ if(!value.isEmpty()){
+ when(fileType){
+ Manifest.permission.READ_MEDIA_VIDEO,Manifest.permission.READ_MEDIA_IMAGES ->{
+ var intent = Intent()
+ intent.action = MediaStore.ACTION_PICK_IMAGES
+ var type = if(fileType == Manifest.permission.READ_MEDIA_VIDEO) "video/*" else "image/*"
+ intent.setType(type) // 设置文件类型,可以更具体如"application/pdf"
+ // 设置可多选
+ intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, maxCount > 1);
+ if(maxCount > 1){
+ //设置最大数量
+ intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, maxCount);
+ }
+ fileLauncher!!.launch(intent)
+ }
+ Manifest.permission.READ_MEDIA_AUDIO ->{
+ var intent = Intent(Intent.ACTION_PICK, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI)
+ fileLauncher!!.launch(intent)
+ //multipleFileLauncher!!.launch(arrayOf("audio/*"
+ // "audio/mp3", // MP3
+ // "audio/m4a", // M4A
+ // "audio/aac", // AAC
+ // "audio/ogg", // OGG
+ // "audio/wav" // WAV
+ // ))
+ }
+ else -> {}
+ }
+ }else{
+ requestFileResult?.onChanged(ArrayList())
+ }
+ }
+ })
}
fun registerForActivityResult(callback : ActivityResultCallback<ActivityResult>):ActivityResultLauncher<Intent>{
@@ -241,6 +415,16 @@
return result
}
+ @Suppress("DEPRECATION")
+ protected fun isMyServiceRunning(serviceClass: Class<*>): Boolean {
+ val manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
+ for (service in manager.getRunningServices(Integer.MAX_VALUE)) {
+ if (serviceClass.name == service.service.className) {
+ return true
+ }
+ }
+ return false
+ }
/**
* 检查权限
@@ -261,7 +445,37 @@
allGranted = false
if (showPop) {
// TODO:
- //showPermissionPopu(permission)
+ var title = ""
+ var message = "";
+ if(permissions.contains(Manifest.permission.READ_EXTERNAL_STORAGE)){
+ title = "申请文件读取权限";
+ message = " 通过文件读取权限后,可无障碍使用图片类、音乐类、视频类文件,并将读取的文件数据添加到直播中的音视频流中。"
+ }else if(permissions.contains(Manifest.permission.CAMERA)){
+ title = "申请相机权限";
+ message = " 通过相机权限后,可无障碍使用相机及USB采集设备,并将设备采集的画面添加到直播中的视频流中。"
+ }else if(permissions.contains(Manifest.permission.RECORD_AUDIO)){
+ title = "申请话筒权限";
+ message = " 通过话筒权限后,可无障碍使用话筒设备,并将话筒采集的音频数据添加到直播中的音频流中"
+ }else if(permissions.contains(Manifest.permission.READ_MEDIA_IMAGES) ||
+ permissions.contains(Manifest.permission.READ_MEDIA_VIDEO)){
+ title = "申请图片和视频文件权限";
+ message = " 通过图片类和视频类文件权限后,可将读取的图片和视频数据添加到直播中的音视频流中。"
+ }/*else if(permissions.contains(Manifest.permission.READ_MEDIA_IMAGES)){
+ title = "申请图片文件权限";
+ message = "通过图片类文件权限后,可将读取的图片数据添加到直播中的视频流中。"
+ }else if(permissions.contains(Manifest.permission.READ_MEDIA_VIDEO)){
+ title = "申请视频文件权限";
+ message = "通过视频类文件权限后,可将读取的视频数据添加到直播中的音视频流中。"
+ }*/else if(permissions.contains(Manifest.permission.READ_MEDIA_AUDIO)){
+ title = "申请音频文件权限";
+ message = " 通过音频文件权限后,可将音频文件的声音添加到直播中的音频流中"
+ }/*else if(permissions.contains(Manifest.permission.POST_NOTIFICATIONS)){
+ title = "申请通知栏权限";
+ message = "通过通知栏权限后,可开启后台服务,保证相机、话筒、截屏、扬声器等功能不被系统终止"
+ }*/
+ if(!TextUtils.isEmpty(title)){
+ mViewModel!!.showPopupWindow(title = title, message = message)
+ }
}
break
}
@@ -271,6 +485,7 @@
var permissionsLauncher : ActivityResultLauncher<Array<String>>? = null //权限
var permissionObserver : Observer<String>? = null //权限和文件请求回调
+
/**
* 统一权限申请
*/
@@ -308,6 +523,14 @@
showToast(getString(msg))
}
+ fun copyStr(str:String){
+ // 获取系统剪贴板
+ val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+ // 创建一个剪贴数据集,包含一个普通文本数据条目(需要复制的数据)
+ val clipData = ClipData.newPlainText(null ,str)
+ // 把数据集设置(复制)到剪贴板
+ clipboard.setPrimaryClip(clipData)
+ }
/**
* 获取文件保存路径 sdcard根目录/download/文件名称
* @param fileUrl
@@ -323,111 +546,164 @@
return storePath + File.separator + fileName
}
+ fun isTabletDevice(): Boolean {
+ val uiModeManager = getSystemService(Context.UI_MODE_SERVICE) as UiModeManager
+ return (uiModeManager.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION).not() &&
+ (resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK >= Configuration.SCREENLAYOUT_SIZE_LARGE)
+ }
+
//===========================================
//以下为preferences操作
- fun getBooleanUserPrefrence(key : String?) : Boolean {
- return PreferencesUtils.getBoolean(this , key , false , PreferencesUtils.USER)
+ fun getBooleanUserPrefrence(key : String) : Boolean {
+ return getBooleanUserPrefrence(key,false)
}
- fun getBooleanProjectPrefrence(key : String?) : Boolean {
- return PreferencesUtils.getBoolean(this , key , false , PreferencesUtils.PROJECT)
+ fun getBooleanUserPrefrence(key : String,value : Boolean) : Boolean {
+ return PreferencesUtils.getBoolean(this , key , value , PreferencesUtils.USER)
}
- fun getStringUserPrefrence(key : String?) : String {
- return PreferencesUtils.getString(this , key , "" , PreferencesUtils.USER)
+ fun getBooleanProjectPrefrence(key : String) : Boolean {
+ return getBooleanProjectPrefrence(key,false)
}
- fun getStringProjectPrefrence(key : String?) : String {
- return PreferencesUtils.getString(this , key , "" , PreferencesUtils.PROJECT)
+ fun getBooleanProjectPrefrence(key : String,value : Boolean) : Boolean {
+ return PreferencesUtils.getBoolean(this , key , value , PreferencesUtils.PROJECT)
}
- fun getIntProjectPrefrence(key : String?) : Int {
- return PreferencesUtils.getInt(this , key , 0 , PreferencesUtils.PROJECT)
+ fun getStringUserPrefrence(key : String) : String {
+ return getStringUserPrefrence(key,"");
}
- fun getLongProjectPrefrence(key : String?) : Long {
- return PreferencesUtils.getLong(this , key , 0 , PreferencesUtils.PROJECT)
+ fun getStringUserPrefrence(key : String,value : String?) : String {
+ return PreferencesUtils.getString(this , key , value, PreferencesUtils.USER)
}
- fun getFloatProjectPrefrence(key : String?) : Float {
- return PreferencesUtils.getFloat(this , key , 0f , PreferencesUtils.PROJECT)
+ fun getStringProjectPrefrence(key : String) : String {
+ return getStringProjectPrefrence(key,"");
}
- fun getStringSetProjectPrefrence(key : String?) : Set<*> {
- return PreferencesUtils.getStringSet(this , key , PreferencesUtils.PROJECT)
+ fun getStringProjectPrefrence(key : String,value : String?) : String {
+ return PreferencesUtils.getString(this , key , value, PreferencesUtils.PROJECT)
}
- fun getIntUserPrefrence(key : String?) : Int {
- return PreferencesUtils.getInt(this , key , 0 , PreferencesUtils.USER)
+ fun getIntProjectPrefrence(key : String) : Int {
+ return getIntProjectPrefrence(key,0);
}
- fun getLongUserPrefrence(key : String?) : Long {
- return PreferencesUtils.getLong(this , key , 0 , PreferencesUtils.USER)
+ fun getIntProjectPrefrence(key : String,value : Int) : Int {
+ return PreferencesUtils.getInt(this , key , value , PreferencesUtils.PROJECT)
}
- fun getFloatUserPrefrence(key : String?) : Float {
- return PreferencesUtils.getFloat(this , key , 0f , PreferencesUtils.USER)
+ fun getLongProjectPrefrence(key : String) : Long {
+ return getLongProjectPrefrence(key,0);
}
- fun getStringSetUserPrefrence(key : String?) : Set<*> {
- return PreferencesUtils.getStringSet(this , key , PreferencesUtils.USER)
+ fun getLongProjectPrefrence(key : String,value : Long) : Long {
+ return PreferencesUtils.getLong(this , key , value , PreferencesUtils.PROJECT)
}
+ fun getFloatProjectPrefrence(key : String) : Float {
+ return getFloatProjectPrefrence(key,0f);
+ }
- fun putBooleanUserPrefrence(key : String? , value : Boolean) {
+ fun getFloatProjectPrefrence(key : String,value : Float) : Float {
+ return PreferencesUtils.getFloat(this , key , value , PreferencesUtils.PROJECT)
+ }
+
+ fun getStringSetProjectPrefrence(key : String) : Set<*> {
+ return getStringSetProjectPrefrence(key, HashSet<Any?>() )
+ }
+
+ fun getStringSetProjectPrefrence(key : String,value : Set<*>?) : Set<*> {
+ return PreferencesUtils.getStringSet(this , key ,value, PreferencesUtils.PROJECT)
+ }
+
+ fun getIntUserPrefrence(key : String) : Int {
+ return getIntUserPrefrence(key,0)
+ }
+
+ fun getIntUserPrefrence(key : String,value : Int) : Int {
+ return PreferencesUtils.getInt(this , key , value , PreferencesUtils.USER)
+ }
+
+ fun getLongUserPrefrence(key : String) : Long {
+ return getLongUserPrefrence(key,0)
+ }
+
+ fun getLongUserPrefrence(key : String,value : Long) : Long {
+ return PreferencesUtils.getLong(this , key , value , PreferencesUtils.USER)
+ }
+
+ fun getFloatUserPrefrence(key : String) : Float {
+ return getFloatUserPrefrence(key,0f)
+ }
+
+ fun getFloatUserPrefrence(key : String,value : Float) : Float {
+ return PreferencesUtils.getFloat(this , key , value , PreferencesUtils.USER)
+ }
+
+ fun getStringSetUserPrefrence(key : String) : Set<*> {
+ return getStringSetUserPrefrence(key,HashSet<Any?>())
+ }
+
+ fun getStringSetUserPrefrence(key : String,value : Set<*>) : Set<*> {
+ return PreferencesUtils.getStringSet(this , key ,value, PreferencesUtils.USER)
+ }
+
+ fun putBooleanUserPrefrence(key : String , value : Boolean) {
PreferencesUtils.putBoolean(this , key , value , PreferencesUtils.USER)
}
- fun putBooleanProjectPrefrence(key : String? , value : Boolean) {
+ fun putBooleanProjectPrefrence(key : String , value : Boolean) {
PreferencesUtils.putBoolean(this , key , value , PreferencesUtils.PROJECT)
}
- fun putStringUserPrefrence(key : String? , value : String?) {
+ fun putStringUserPrefrence(key : String , value : String?) {
PreferencesUtils.putString(this , key , value , PreferencesUtils.USER)
}
- fun putStringProjectPrefrence(key : String? , value : String?) {
+ fun putStringProjectPrefrence(key : String , value : String?) {
PreferencesUtils.putString(this , key , value , PreferencesUtils.PROJECT)
}
- fun putIntProjectPrefrence(key : String? , value : Int) {
+ fun putIntProjectPrefrence(key : String , value : Int) {
PreferencesUtils.putInt(this , key , value , PreferencesUtils.PROJECT)
}
- fun putLongProjectPrefrence(key : String? , value : Long) {
+ fun putLongProjectPrefrence(key : String , value : Long) {
PreferencesUtils.putLong(this , key , value , PreferencesUtils.PROJECT)
}
- fun putFloatProjectPrefrence(key : String? , value : Float) {
+ fun putFloatProjectPrefrence(key : String , value : Float) {
PreferencesUtils.putFloat(this , key , value , PreferencesUtils.PROJECT)
}
- fun putStringSetProjectPrefrence(key : String? , value : Set<*>?) {
+ fun putStringSetProjectPrefrence(key : String , value : Set<*>?) {
PreferencesUtils.putStringSet(this , key , value , PreferencesUtils.PROJECT)
}
- fun putIntUserPrefrence(key : String? , value : Int) {
+ fun putIntUserPrefrence(key : String , value : Int) {
PreferencesUtils.putInt(this , key , value , PreferencesUtils.USER)
}
- fun putLongUserPrefrence(key : String? , value : Long) {
+ fun putLongUserPrefrence(key : String , value : Long) {
PreferencesUtils.putLong(this , key , value , PreferencesUtils.USER)
}
- fun putFloatUserPrefrence(key : String? , value : Float) {
+ fun putFloatUserPrefrence(key : String , value : Float) {
PreferencesUtils.putFloat(this , key , value , PreferencesUtils.USER)
}
- fun putStringSetUserPrefrence(key : String? , value : Set<*>?) {
+ fun putStringSetUserPrefrence(key : String , value : Set<*>?) {
PreferencesUtils.putStringSet(this , key , value , PreferencesUtils.USER)
}
- fun removeUserKey(key : String?) {
+ fun removeUserKey(key : String) {
PreferencesUtils.removeKey(this , key , PreferencesUtils.USER)
}
- fun removeProjectKey(key : String?) {
+ fun removeProjectKey(key : String) {
PreferencesUtils.removeKey(this , key , PreferencesUtils.PROJECT)
}
--
Gitblit v1.9.1