task manager 读取
This commit is contained in:
parent
9ce2bda2bc
commit
1424f72256
|
|
@ -0,0 +1,130 @@
|
||||||
|
{
|
||||||
|
"task_module_config": {
|
||||||
|
"basic_info": {
|
||||||
|
"module_name": "任务中心",
|
||||||
|
"page_path": "底部第二个页签",
|
||||||
|
"layout_style": "上下滑动长页面",
|
||||||
|
"currency_display": ["金币账户", "巴西雷亚尔现金账户"]
|
||||||
|
},
|
||||||
|
"task_categories": [
|
||||||
|
{
|
||||||
|
"category_id": "newbie_task",
|
||||||
|
"category_name": "新手任务(Missão Para Iniciantes)",
|
||||||
|
"valid_period": "注册后7天内",
|
||||||
|
"display_priority": 1,
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"task_id": "newbie_first_withdraw",
|
||||||
|
"task_name": "完成第一次提现",
|
||||||
|
"task_desc": "完成首次提现操作(0.1 BRL门槛),即可获得100金币奖励",
|
||||||
|
"target_action": "用户完成首次提现流程(含绑定Pix账户、观看广告)",
|
||||||
|
"reward_type": "金币",
|
||||||
|
"reward_value": 100,
|
||||||
|
"is_one_time": true,
|
||||||
|
"status": "active"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"task_id": "newbie_push_notify",
|
||||||
|
"task_name": "开启消息推送",
|
||||||
|
"task_desc": "启用APP消息推送权限,实时获取任务更新与奖励通知",
|
||||||
|
"target_action": "用户授权APP系统推送通知",
|
||||||
|
"reward_type": "金币",
|
||||||
|
"reward_value": 300,
|
||||||
|
"is_one_time": true,
|
||||||
|
"status": "active"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"task_id": "newbie_join_discord",
|
||||||
|
"task_name": "加入Discord社区",
|
||||||
|
"task_desc": "通过APP内链接加入官方Discord社区,获取专属活动与客服支持",
|
||||||
|
"target_action": "用户通过指定链接成功加入Discord社区",
|
||||||
|
"reward_type": "金币",
|
||||||
|
"reward_value": 200,
|
||||||
|
"is_one_time": true,
|
||||||
|
"status": "active"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"task_id": "newbie_7day_checkin",
|
||||||
|
"task_name": "7日连续签到",
|
||||||
|
"task_desc": "连续7天完成签到,奖励逐级递增,第7天最高可得800金币",
|
||||||
|
"target_action": "用户每日完成签到操作(支持广告补签)",
|
||||||
|
"reward_type": "金币",
|
||||||
|
"reward_details": [
|
||||||
|
{"day": 1, "value": 100},
|
||||||
|
{"day": 2, "value": 300},
|
||||||
|
{"day": 3, "value": 300},
|
||||||
|
{"day": 4, "value": 500},
|
||||||
|
{"day": 5, "value": 300},
|
||||||
|
{"day": 6, "value": 300},
|
||||||
|
{"day": 7, "value": 800}
|
||||||
|
],
|
||||||
|
"support_makeup": true,
|
||||||
|
"makeup_method": "观看15-30秒激励视频",
|
||||||
|
"is_one_time": true,
|
||||||
|
"status": "active"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category_id": "daily_task",
|
||||||
|
"category_name": "日常任务(Missão Diária)",
|
||||||
|
"valid_period": "每日凌晨00:00重置",
|
||||||
|
"display_priority": 2,
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"task_id": "daily_checkin",
|
||||||
|
"task_name": "每日签到",
|
||||||
|
"task_desc": "每日签到可获金币,7天为一周期,奖励循环递增(支持双倍广告奖励)",
|
||||||
|
"target_action": "用户当日完成签到操作",
|
||||||
|
"reward_type": "金币",
|
||||||
|
"reward_details": [
|
||||||
|
{"day": 1, "value": 100},
|
||||||
|
{"day": 2, "value": 300},
|
||||||
|
{"day": 3, "value": 300},
|
||||||
|
{"day": 4, "value": 500},
|
||||||
|
{"day": 5, "value": 300},
|
||||||
|
{"day": 6, "value": 300},
|
||||||
|
{"day": 7, "value": 500}
|
||||||
|
],
|
||||||
|
"double_reward_method": "观看15-30秒激励视频",
|
||||||
|
"support_makeup": true,
|
||||||
|
"makeup_method": "观看15-30秒激励视频",
|
||||||
|
"is_one_time": false,
|
||||||
|
"status": "active"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"task_id": "daily_video_ladder",
|
||||||
|
"task_name": "阶梯观看视频",
|
||||||
|
"task_desc": "累计观看指定数量短视频,分3档领取奖励(与基础观看收益叠加)",
|
||||||
|
"target_action": "用户累计观看短视频",
|
||||||
|
"reward_type": "金币",
|
||||||
|
"reward_details": [
|
||||||
|
{"target_count": 10, "value": 100},
|
||||||
|
{"target_count": 20, "value": 150},
|
||||||
|
{"target_count": 30, "value": 200}
|
||||||
|
],
|
||||||
|
"reward_stackable": true,
|
||||||
|
"is_one_time": false,
|
||||||
|
"status": "active"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"task_id": "daily_ad_ladder",
|
||||||
|
"task_name": "阶梯观看激励视频",
|
||||||
|
"task_desc": "累计观看指定数量激励视频,分3档领取奖励(每日上限10次)",
|
||||||
|
"target_action": "用户累计观看激励视频",
|
||||||
|
"reward_type": "金币",
|
||||||
|
"reward_details": [
|
||||||
|
{"target_count": 1, "value": 100},
|
||||||
|
{"target_count": 5, "value": 150},
|
||||||
|
{"target_count": 10, "value": 200}
|
||||||
|
],
|
||||||
|
"daily_limit": 10,
|
||||||
|
"reward_stackable": true,
|
||||||
|
"is_one_time": false,
|
||||||
|
"status": "active"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,23 @@
|
||||||
package com.gamedog.vididin
|
package com.gamedog.vididin
|
||||||
|
|
||||||
import com.ama.core.architecture.BaseApp
|
import com.ama.core.architecture.BaseApp
|
||||||
|
import com.gamedog.vididin.manager.TaskManager
|
||||||
import dagger.hilt.android.HiltAndroidApp
|
import dagger.hilt.android.HiltAndroidApp
|
||||||
|
|
||||||
|
|
||||||
@HiltAndroidApp
|
@HiltAndroidApp
|
||||||
class VidiDinApp : BaseApp() {
|
class VidiDinApp : BaseApp() {
|
||||||
|
|
||||||
|
init {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
initManagers()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initManagers() {
|
||||||
|
TaskManager.instance()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6,14 +6,18 @@ import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.ama.core.architecture.appBase.AppViewsFragment
|
import com.ama.core.architecture.appBase.AppViewsFragment
|
||||||
import com.ama.core.architecture.appBase.OnFragmentBackgroundListener
|
import com.ama.core.architecture.appBase.OnFragmentBackgroundListener
|
||||||
import com.ama.core.architecture.util.SpUtil
|
import com.ama.core.architecture.util.SpUtil
|
||||||
import com.ama.core.architecture.util.setOnClickBatch
|
import com.ama.core.architecture.util.setOnClickBatch
|
||||||
import com.ama.core.architecture.util.setStatusBarDarkFont
|
import com.ama.core.architecture.util.setStatusBarDarkFont
|
||||||
import com.gamedog.vididin.main.fragments.task.DailySignDialog
|
import com.gamedog.vididin.main.fragments.task.DailySignDialog
|
||||||
|
import com.gamedog.vididin.main.fragments.task.TaskBean
|
||||||
import com.gamedog.vididin.main.interfaces.OnTabClickAgainListener
|
import com.gamedog.vididin.main.interfaces.OnTabClickAgainListener
|
||||||
|
import com.gamedog.vididin.manager.TaskManager
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.getValue
|
import kotlin.getValue
|
||||||
import com.gamedog.vididin.databinding.VididinappFeatureMessageFragmentMessageBinding as ViewBinding
|
import com.gamedog.vididin.databinding.VididinappFeatureMessageFragmentMessageBinding as ViewBinding
|
||||||
import com.gamedog.vididin.main.fragments.home.YoutubeViewModel as ViewModel
|
import com.gamedog.vididin.main.fragments.home.YoutubeViewModel as ViewModel
|
||||||
|
|
@ -24,6 +28,7 @@ import com.gamedog.vididin.main.fragments.home.YoutubeUiState as UiState
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class TasksFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnTabClickAgainListener, OnFragmentBackgroundListener {
|
class TasksFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnTabClickAgainListener, OnFragmentBackgroundListener {
|
||||||
|
|
||||||
|
private var mTaskConfig: TaskBean? = null
|
||||||
override val mViewModel: ViewModel by viewModels()
|
override val mViewModel: ViewModel by viewModels()
|
||||||
override var isBackgroundBright: Boolean = true
|
override var isBackgroundBright: Boolean = true
|
||||||
|
|
||||||
|
|
@ -42,6 +47,7 @@ class TasksFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnTab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun ViewBinding.initViews() {
|
override fun ViewBinding.initViews() {
|
||||||
with(binding) {
|
with(binding) {
|
||||||
setOnClickBatch(ivGotoDailySign) {
|
setOnClickBatch(ivGotoDailySign) {
|
||||||
|
|
@ -52,6 +58,10 @@ class TasksFragment : AppViewsFragment<ViewBinding, UiState, ViewModel>(), OnTab
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
mTaskConfig = TaskManager.instance().getTaskConfig()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun ViewBinding.initListeners() {
|
override fun ViewBinding.initListeners() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.gamedog.vididin.main.fragments.task
|
||||||
|
|
||||||
|
data class TaskBean(
|
||||||
|
val task_module_config: TaskModuleConfig
|
||||||
|
)
|
||||||
|
|
||||||
|
data class TaskModuleConfig(
|
||||||
|
val basic_info: BasicInfo,
|
||||||
|
val task_categories: List<TaskCategory>
|
||||||
|
)
|
||||||
|
|
||||||
|
data class BasicInfo(
|
||||||
|
val currency_display: List<String>,
|
||||||
|
val layout_style: String,
|
||||||
|
val module_name: String,
|
||||||
|
val page_path: String
|
||||||
|
)
|
||||||
|
|
||||||
|
data class TaskCategory(
|
||||||
|
val category_id: String,
|
||||||
|
val category_name: String,
|
||||||
|
val display_priority: Int,
|
||||||
|
val tasks: List<Task>,
|
||||||
|
val valid_period: String
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Task(
|
||||||
|
val daily_limit: Int,
|
||||||
|
val double_reward_method: String,
|
||||||
|
val is_one_time: Boolean,
|
||||||
|
val makeup_method: String,
|
||||||
|
val reward_details: List<RewardDetail>,
|
||||||
|
val reward_stackable: Boolean,
|
||||||
|
val reward_type: String,
|
||||||
|
val reward_value: Int,
|
||||||
|
val status: String,
|
||||||
|
val support_makeup: Boolean,
|
||||||
|
val target_action: String,
|
||||||
|
val task_desc: String,
|
||||||
|
val task_id: String,
|
||||||
|
val task_name: String
|
||||||
|
)
|
||||||
|
|
||||||
|
data class RewardDetail(
|
||||||
|
val day: Int,
|
||||||
|
val target_count: Int,
|
||||||
|
val value: Int
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
package com.gamedog.vididin.manager
|
||||||
|
|
||||||
|
import com.ama.core.architecture.util.FileUtil
|
||||||
|
import com.gamedog.vididin.main.fragments.task.TaskBean
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
|
class TaskManager private constructor() {
|
||||||
|
companion object {
|
||||||
|
@Volatile
|
||||||
|
private var instance: TaskManager? = null
|
||||||
|
|
||||||
|
fun instance(): TaskManager {
|
||||||
|
return instance ?: synchronized(this) {
|
||||||
|
instance ?: TaskManager().also {
|
||||||
|
instance = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val mutex = Mutex()
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
private var initialized = false
|
||||||
|
private var mTaskConfigBean: TaskBean? = null
|
||||||
|
private val mGson = GsonBuilder().create()
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
loadTaskConfigAsync()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
suspend fun getTaskConfig(): TaskBean? = mutex.withLock {
|
||||||
|
if (!initialized) {
|
||||||
|
loadTaskConfigFromAsset()
|
||||||
|
}
|
||||||
|
return mTaskConfigBean
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadTaskConfigAsync() {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
mutex.withLock {
|
||||||
|
if (!initialized) {
|
||||||
|
loadTaskConfigFromAsset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun loadTaskConfigFromAsset() {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
val configStr = FileUtil.readAssetsFile("taskConfig.json")
|
||||||
|
mTaskConfigBean = mGson.fromJson(configStr, TaskBean::class.java)
|
||||||
|
initialized = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,144 @@
|
||||||
|
package com.ama.core.architecture.util
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.LifecycleEventObserver
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
object AsyncUtil {
|
||||||
|
private val jobMap = ConcurrentHashMap<String, Job>()
|
||||||
|
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
||||||
|
|
||||||
|
|
||||||
|
fun <T> doGlobalAsync(
|
||||||
|
backgroundWork: suspend () -> T,
|
||||||
|
onStart: (() -> Unit)? = null,
|
||||||
|
onComplete: ((T) -> Unit)? = null,
|
||||||
|
onError: ((Exception) -> Unit)? = null
|
||||||
|
): Job {
|
||||||
|
return scope.launch {
|
||||||
|
onStart?.invoke()
|
||||||
|
try {
|
||||||
|
val result = withContext(Dispatchers.IO) { backgroundWork() }
|
||||||
|
onComplete?.invoke(result)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
onError?.invoke(e)
|
||||||
|
}
|
||||||
|
}.also { job ->
|
||||||
|
job.invokeOnCompletion { cause ->
|
||||||
|
if (cause != null) Log.d("AsyncTaskUtil", "Global task completed with error: $cause")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定组件生命周期的异步任务
|
||||||
|
*/
|
||||||
|
fun <T> doLifecycleAwareAsync(
|
||||||
|
lifecycleOwner: LifecycleOwner,
|
||||||
|
backgroundWork: suspend () -> T,
|
||||||
|
onStart: (() -> Unit)? = null,
|
||||||
|
onComplete: ((T) -> Unit)? = null,
|
||||||
|
onError: ((Exception) -> Unit)? = null
|
||||||
|
) {
|
||||||
|
val key = lifecycleOwner::class.java.simpleName + System.identityHashCode(lifecycleOwner)
|
||||||
|
|
||||||
|
// 清理现有任务
|
||||||
|
jobMap[key]?.cancel()
|
||||||
|
|
||||||
|
val job = scope.launch {
|
||||||
|
onStart?.invoke()
|
||||||
|
try {
|
||||||
|
val result = withContext(Dispatchers.IO) { backgroundWork() }
|
||||||
|
if (isActive) onComplete?.invoke(result)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (e is CancellationException) throw e
|
||||||
|
if (isActive) onError?.invoke(e)
|
||||||
|
}
|
||||||
|
}.also { jobMap[key] = it }
|
||||||
|
|
||||||
|
// 绑定生命周期
|
||||||
|
lifecycleOwner.lifecycle.addObserver(object : LifecycleEventObserver {
|
||||||
|
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
|
||||||
|
when (event) {
|
||||||
|
Lifecycle.Event.ON_DESTROY -> {
|
||||||
|
job.cancel()
|
||||||
|
jobMap.remove(key)
|
||||||
|
lifecycleOwner.lifecycle.removeObserver(this)
|
||||||
|
Log.d("AsyncTaskUtil", "Lifecycle task cleaned up: $key")
|
||||||
|
}
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消所有任务(用于应用退出)
|
||||||
|
*/
|
||||||
|
fun shutdown() {
|
||||||
|
scope.cancel()
|
||||||
|
jobMap.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
// 1 全局任务 ----------------------
|
||||||
|
val job = AsyncTaskUtil.doGlobalAsync(
|
||||||
|
backgroundWork = {
|
||||||
|
// 在IO线程执行
|
||||||
|
simulateNetworkRequest()
|
||||||
|
},
|
||||||
|
onStart = { showProgressBar() },
|
||||||
|
onComplete = { result ->
|
||||||
|
// 在主线程执行
|
||||||
|
updateUI(result)
|
||||||
|
},
|
||||||
|
onError = { e ->
|
||||||
|
showError(e.message ?: "Unknown error")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 手动取消(如果需要)
|
||||||
|
job.cancel()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 2 生命周期绑定任务 ----------------------
|
||||||
|
class MainActivity : AppCompatActivity() {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
// 任务自动绑定到Activity生命周期
|
||||||
|
AsyncTaskUtil.doLifecycleAwareAsync(
|
||||||
|
lifecycleOwner = this,
|
||||||
|
backgroundWork = { loadUserData() },
|
||||||
|
onComplete = { data -> updateUserInterface(data) },
|
||||||
|
onError = { e -> showErrorMessage(e) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 3 ViewModel中 ----------------------
|
||||||
|
class MyViewModel : ViewModel() {
|
||||||
|
fun loadData() {
|
||||||
|
// 使用viewModelScope而非全局Scope
|
||||||
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
|
val data = withContext(Dispatchers.IO) { fetchData() }
|
||||||
|
_uiState.value = SuccessState(data)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
_uiState.value = ErrorState(e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
package com.ama.core.architecture.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.ama.core.architecture.BaseApp
|
||||||
|
import java.io.BufferedReader
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.InputStreamReader
|
||||||
|
|
||||||
|
|
||||||
|
class FileUtil private constructor() {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
|
||||||
|
fun readAssetsFile(fileName: String, encoding: String = "UTF-8"): String? {
|
||||||
|
return try {
|
||||||
|
// 使用use关键字自动关闭资源
|
||||||
|
BaseApp.appContext().assets.open(fileName).use { inputStream ->
|
||||||
|
InputStreamReader(inputStream, encoding).use { reader ->
|
||||||
|
val buffer = CharArray(1024)
|
||||||
|
val result = StringBuilder()
|
||||||
|
while (true) {
|
||||||
|
val bytesRead = reader.read(buffer)
|
||||||
|
if (bytesRead == -1) break
|
||||||
|
result.append(buffer, 0, bytesRead)
|
||||||
|
}
|
||||||
|
result.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 逐行读取文本文件(适合处理大文件或需要按行处理的场景)
|
||||||
|
*/
|
||||||
|
fun readTextFileLineByLine(context: Context, fileName: String, encoding: String = "UTF-8"): List<String> {
|
||||||
|
return try {
|
||||||
|
context.assets.open(fileName).use { inputStream ->
|
||||||
|
InputStreamReader(inputStream, encoding).use { reader ->
|
||||||
|
BufferedReader(reader).useLines { lines ->
|
||||||
|
lines.toList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.ama.core.architecture.util
|
||||||
|
|
||||||
|
class ResUtil private constructor() {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue