首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

  • 24-12-05 21:06
  • 4734
  • 11633
juejin.cn

对于一个Android App来说,应用卡顿是让人非常难受的,特别是在低端手机上,有一种想砸手机的冲动。动不动手机就黑屏,打开一个界面卡半天。

应用性能的重要性

应用性能优化对于软件开发和维护至关重要。包括以下几点:

1. 提升用户体验

  • 用户更倾向于使用响应迅速、运行流畅的应用程序。性能差的应用可能会导致用户流失,特别是在竞争激烈的市场中。
  • 如页面加载时间过长或操作延迟过高,会直接影响用户满意度。

2. 提高资源利用率

  • 优化性能可以减少对计算资源(如 CPU、内存、带宽等)的消耗,从而降低服务器负载和运行成本。
  • 更高效的代码和架构设计有助于更好地利用硬件资源,尤其是在云计算或多租户环境中。

3. 支持扩展性与稳定性

  • 高性能应用通常具有更好的扩展能力,可以更轻松地处理用户增长或流量激增。
  • 性能优化还能减少系统崩溃和宕机的风险,提高整体的稳定性和可靠性。

4. 增强竞争力

  • 优化的应用在市场上更具竞争力,尤其是当用户的选择众多时。性能好的产品更容易赢得用户信任和忠诚度。

5. 降低长期维护成本

  • 提前解决性能问题可以避免后期因扩展或问题积累带来的高昂维护费用。
  • 通过优化代码和架构,可以使系统更易于调试和扩展。

6. 满足业务需求

  • 某些业务场景(如实时数据处理、大型并发请求)对性能要求极高。优化可以确保应用满足这些业务需求。

dcache-android框架写了这么久,连个异步还要自己封装吗?

抱歉,让大家失望了,一直没有时间弄这个异步问题,之前都在修复基础功能的bug。最近板块轮动终于轮到这个项目的这个功能了,哈哈。数据ORM框架连个异步执行都不支持,难道还要别人每次调API还要自己开个线程吗?确实,对于ORM框架来说,性能优化是不可跨越的一关。传送门:github.com/dora4/dcach… 。

异步封装的主要类

dcache对异步操作的封装在dora.db.async包下。

kotlin
代码解读
复制代码
package dora.db.async import android.os.Handler import android.os.Looper import android.os.Message import dora.db.OrmLog import dora.db.Transaction import dora.db.builder.QueryBuilder import dora.db.builder.WhereBuilder import dora.db.exception.OrmTaskException import dora.db.table.OrmTable import java.util.concurrent.BlockingQueue import java.util.concurrent.Callable import java.util.concurrent.ExecutorService import java.util.concurrent.Executors import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.TimeUnit import java.util.concurrent.locks.ReentrantLock import kotlin.concurrent.withLock internal class OrmExecutor<T : OrmTable> : Runnable, Handler.Callback { private val queue: BlockingQueue> = LinkedBlockingQueue() private val lock = ReentrantLock() private val condition = lock.newCondition() @Volatile private var executorRunning = false @Volatile var maxTaskCountToMerge: Int = 50 @Volatile var listener: OrmTaskListener? = null @Volatile var listenerMainThread: OrmTaskListener? = null @Volatile var waitForMergeMillis: Int = 50 private var countTasksEnqueued = 0 private var countTasksCompleted = 0 private var handlerMainThread: Handler? = null private var lastSequenceNumber = 0 private var stopQueue: Boolean = false fun resetQueueStopFlag() { stopQueue = false } private fun shouldStopQueue(task: OrmTask<T>): Boolean { return (task.flags and OrmTask.FLAG_STOP_QUEUE_ON_EXCEPTION) != 0 } fun enqueue(task: OrmTask<T>) { synchronized(this) { task.sequenceNumber = ++lastSequenceNumber queue.add(task) countTasksEnqueued++ if (!executorRunning) { executorRunning = true executor.execute(this) } } } @get:Synchronized val isCompleted: Boolean get() = lock.withLock { countTasksEnqueued == countTasksCompleted } /** * Waits until all enqueued operations are complete. If the thread gets interrupted, any * [InterruptedException] will be rethrown as a [OrmTaskException]. * 简体中文:等待直到所有排队的操作完成。如果线程被中断,任何 [InterruptedException] 都会被重新抛出为 * [OrmTaskException]。 */ @Synchronized @Throws(OrmTaskException::class) fun waitForCompletion() { lock.lock() try { while (!isCompleted) { try { condition.await() } catch (e: InterruptedException) { throw OrmTaskException("Interrupted while waiting for all tasks to complete.\n$e", e) } } } finally { lock.unlock() } } /** * Waits until all enqueued operations are complete, but at most the given amount of milliseconds. * If the thread gets interrupted, any [InterruptedException] will be rethrown as a [OrmTaskException]. * 简体中文:等待直到所有排队的操作完成,但最多等待指定的毫秒数。如果线程被中断,任何 [InterruptedException] * 都会被重新抛出为 [OrmTaskException]。 * * @return true if operations completed in the given time frame. */ @Synchronized @Throws(OrmTaskException::class) fun waitForCompletion(maxMillis: Int = 0): Boolean { lock.withLock { val deadline = System.currentTimeMillis() + maxMillis while (!isCompleted) { val remainingTime = deadline - System.currentTimeMillis() if (remainingTime <= 0 || maxMillis == 0) { break } try { condition.await(remainingTime, TimeUnit.MILLISECONDS) } catch (e: InterruptedException) { throw OrmTaskException("Interrupted while waiting: ${e.message}", e) } } return isCompleted } } override fun run() { try { try { while (true) { var task = queue.poll(1, TimeUnit.SECONDS) try { if (task == null) { synchronized(this) { task = queue.poll() if (task == null) { executorRunning = false return } } } if (task.isMergeTx) { val task2 = queue.poll(waitForMergeMillis.toLong(), TimeUnit.MILLISECONDS) if (task2 != null) { if (task.isMergeableWith(task2)) { mergeTxAndExecute(task, task2) } else { executeTaskAndPostCompleted(task) executeTaskAndPostCompleted(task2) } continue } } executeTaskAndPostCompleted(task) } catch (e: Exception) { listener?.onFailed(task, e) } } } catch (e: InterruptedException) { OrmLog.w(Thread.currentThread().name + " was interrupted.\n" + e) } catch (e: OrmTaskException) { throw RuntimeException(e) } } finally { executorRunning = false } } @Throws(OrmTaskException::class) private fun mergeTxAndExecute(task1: OrmTask<T>, task2: OrmTask<T>) { val mergedTasks = ArrayList>() mergedTasks.add(task1) mergedTasks.add(task2) var success = false Transaction.execute { for (i in mergedTasks.indices) { val task = mergedTasks[i] executeTask(task) if (task.isFailed) { break } if (i == mergedTasks.size - 1) { val peekedTask = queue.peek() if (i < maxTaskCountToMerge && task.isMergeableWith(peekedTask)) { val removedTask = queue.remove() if (removedTask !== peekedTask) { throw OrmTaskException("Internal error: peeked task did not match removed task") } mergedTasks.add(removedTask) } else { success = true break } } } } if (success) { val mergedCount = mergedTasks.size for (task in mergedTasks) { task.mergedTasksCount = mergedCount handleTaskCompleted(task) } } else { OrmLog.i( "Reverted merged transaction because one of the tasks failed. Executing tasks one by " + "one instead..." ) for (task in mergedTasks) { task.reset() executeTaskAndPostCompleted(task) } } } private fun handleTaskCompleted(task: OrmTask<T>) { task.setCompleted() listener?.onCompleted(task) listenerMainThread?.let { getMainThreadHandler().obtainMessage(1, task).sendToTarget() } lock.withLock { countTasksCompleted++ if (countTasksCompleted == countTasksEnqueued) { condition.signalAll() } } } private fun getMainThreadHandler(): Handler { return handlerMainThread ?: synchronized(this) { handlerMainThread ?: Handler(Looper.getMainLooper(), this).also { handlerMainThread = it } } } private fun executeTaskAndPostCompleted(task: OrmTask<T>) { executeTask(task) handleTaskCompleted(task) } private fun executeTask(task: OrmTask<T>) { if (stopQueue) { OrmLog.w("Task queue stopped due to previous exception.") return } task.timeStarted = System.currentTimeMillis() try { when (task.type) { OrmTask.Type.Insert -> task.result = task.dao.insert(task.parameter as T) OrmTask.Type.InsertList -> task.result = task.dao.insert(task.parameter as List) OrmTask.Type.Delete -> task.result = task.dao.delete((task.parameter as WhereBuilder)) OrmTask.Type.DeleteByKey -> task.result = task.dao.delete(task.parameter as T) OrmTask.Type.DeleteAll -> task.result = task.dao.deleteAll() OrmTask.Type.InsertOrReplace -> task.result = task.dao.insertOrUpdate(task.parameter as T) OrmTask.Type.UpdateByKey -> task.result = task.dao.update(task.parameter as T) OrmTask.Type.WhereList -> task.result = task.dao.select((task.parameter as WhereBuilder)) OrmTask.Type.QueryList -> task.result = task.dao.select((task.parameter as QueryBuilder)) OrmTask.Type.QueryAll -> task.result = task.dao.selectAll() OrmTask.Type.WhereUnique -> task.result = task.dao.selectOne((task.parameter as WhereBuilder)) OrmTask.Type.QueryUnique -> task.result = task.dao.selectOne((task.parameter as QueryBuilder)) OrmTask.Type.IndexUnique -> task.result = task.dao.selectOne() OrmTask.Type.Count -> task.result = task.dao.count() OrmTask.Type.WhereCount -> task.result = task.dao.count((task.parameter as WhereBuilder)) OrmTask.Type.QueryCount -> task.result = task.dao.count((task.parameter as QueryBuilder)) OrmTask.Type.AddColumn -> task.result = task.dao.addColumn((task.parameter as String)) OrmTask.Type.RenameTable -> task.result = task.dao.renameTable((task.parameter as String)) OrmTask.Type.Drop -> task.result = task.dao.drop() OrmTask.Type.WhereInsertOrReplace, OrmTask.Type.WhereUpdate, OrmTask.Type.RenameColumn -> { task.result = (task.parameter as Callable<*>).call() } OrmTask.Type.TransactionRunnable -> executeTransactionRunnable(task) OrmTask.Type.TransactionCallable -> executeTransactionCallable(task) else -> throw OrmTaskException("Unsupported operation: " + task.type) } } catch (th: Throwable) { task.throwable = th if ((task.flags and OrmTask.FLAG_STOP_QUEUE_ON_EXCEPTION) != 0) { stopQueue = true } task.creatorStacktrace?.let { stacktrace -> OrmLog.e( "Task failed: ${task.type}, Sequence: ${task.sequenceNumber}. Created at:" + stacktrace ) } } finally { task.timeCompleted = System.currentTimeMillis() } } private fun executeTransactionRunnable(task: OrmTask<T>) { Transaction.execute { (task.parameter as Runnable).run() } } @Throws(Exception::class) private fun executeTransactionCallable(task: OrmTask<T>) { Transaction.execute { task.result = (task.parameter as Callable<*>).call() } } override fun handleMessage(msg: Message): Boolean { val listenerToCall = listenerMainThread listenerToCall?.onCompleted(msg.obj as OrmTask) return false } companion object { private val executor: ExecutorService = Executors.newCachedThreadPool() } }

OrmExecutor是对ORM线程池封装的核心类。里面用到了一些并发编程的东西,BlockingQueue(阻塞队列)、ExecutorService(线程池执行器)、ReentrantLock(重入锁)和Condition(条件变量)等。在run()方法中,我们可以看到有一个for循环,不断的从阻塞队列拿消息去执行。通过调用enqueue()方法,将新的ORM任务添加到线程池的阻塞队列。执行任务的过程中会不断去调用executeTask()方法,这里将所有的ORM操作都枚举出来了,如果dora.db.dao.Dao中的方法只有一个参数,则parameter就传入这个参数。如果不止一个参数,parameter就传入一个Callable,在Callable中自己去调用原来的同步ORM操作方法。最后在OrmTaskListener中的回调方法中调用task.result(clazz)方法获取返回值,可以是布尔值,也可以是查询出来的数据对象。

kotlin
代码解读
复制代码
package dora.db.async import android.database.sqlite.SQLiteDatabase import dora.db.dao.OrmDao import dora.db.exception.OrmTaskException import dora.db.table.OrmTable import java.util.concurrent.TimeUnit import java.util.concurrent.locks.ReentrantLock open class OrmTask<T : OrmTable> internal constructor( val type: Type, val dao: OrmDao, val parameter: Any? = null, val flags: Int ) { private val lock = ReentrantLock() private val condition = lock.newCondition() /** * @see OrmExecutor.executeTask */ enum class Type { Insert, InsertList, InsertOrReplace, WhereInsertOrReplace, Delete, DeleteAll, UpdateByKey, WhereUpdate, DeleteByKey, WhereList, WhereUnique, QueryList, QueryAll, QueryUnique, IndexUnique, Count, WhereCount, QueryCount, AddColumn, RenameColumn, RenameTable, Drop, TransactionRunnable, TransactionCallable } @Volatile var timeStarted: Long = 0 @Volatile var timeCompleted: Long = 0 @Volatile var isCompleted: Boolean = false private set @Volatile var throwable: Throwable? = null /** * The stacktrace is captured using an exception if [.FLAG_TRACK_CREATOR_STACKTRACE] was used (null * otherwise). 简体中文:如果使用了 [.FLAG_TRACK_CREATOR_STACKTRACE],则使用异常捕获堆栈跟踪(否则为 null)。 */ val creatorStacktrace: Exception? = if ((flags and FLAG_TRACK_CREATOR_STACKTRACE) != 0) Exception("OrmTask was created here") else null @Volatile var result: Any? = null /** * If this operation was successfully merged with other operation into a single TX, this will give the count of * merged operations. If the operation was not merged, it will be 0. * 简体中文:如果此操作已成功与其他操作合并为一个事务(TX),则返回合并操作的数量。如果操作没有合并,则返回 0。 */ @Volatile var mergedTasksCount: Int = 0 /** * Each operation get a unique sequence number when the operation is enqueued. Can be used for efficiently * identifying/mapping operations. 简体中文:每个操作在排队时都会获得一个唯一的序列号。可以用于高效地识别/映射操作。 */ var sequenceNumber: Int = 0 /** * The operation's result after it has completed. Waits until a result is available. * 简体中文:操作完成后返回结果。等待直到结果可用。 * * @return The operation's result or null if the operation type does not produce any result. * 简体中文:操作完成后的结果。等待直到结果可用。操作的结果,如果操作类型没有产生结果,则返回null。 * @throws [OrmTaskException] * @see .waitForCompletion */ @Synchronized @Throws(OrmTaskException::class) fun result(): Any { if (!isCompleted) { waitForCompletion() } throwable?.let { throw OrmTaskException(this, it) } // all orm operations have return value. // 简体中文:所有ORM操作都有返回值 return result!! } /** * The operation's result after it has completed. Waits until a result is available. * 简体中文:操作完成后返回结果。等待直到结果可用。 * * @return The operation's result or null if the operation type does not produce any result. * 简体中文:操作完成后的结果。等待直到结果可用。操作的结果,如果操作类型没有产生结果,则返回null。 * @throws [OrmTaskException] * @see .waitForCompletion */ @Synchronized @Throws(OrmTaskException::class) fun result(clazz: Class<R>): R { if (!isCompleted) { waitForCompletion() } if (throwable != null) { throw OrmTaskException(this, throwable!!) } return result?.takeIf { clazz.isInstance(it) } as? R ?: throw OrmTaskException("The result type does not match the expected type: ${clazz.name}") } val isMergeTx: Boolean get() = (flags and FLAG_MERGE_TX) != 0 fun getDatabase(): SQLiteDatabase { return dao.getDB() } /** * @return true if this operation is mergeable with the given operation. Checks for null, * [.FLAG_MERGE_TX], and if the database instances match. 简体中文:判断此操作是否可以与指定的操作合并。 * 会检查 null、[.FLAG_MERGE_TX] 以及数据库实例是否匹配。 */ fun isMergeableWith(other: OrmTask<T>?): Boolean { return other != null && isMergeTx && other.isMergeTx && getDatabase() == other.getDatabase() } @get:Throws(OrmTaskException::class) val duration: Long get() { if (timeCompleted == 0L) { throw OrmTaskException("This operation did not yet complete") } else { return timeCompleted - timeStarted } } val isFailed: Boolean get() = throwable != null /** * Waits until the operation is complete. If the thread gets interrupted, any * [InterruptedException] will be rethrown as a [OrmTaskException]. * 简体中文:等待操作完成。如果线程被中断,任何 [InterruptedException] 都将被重新抛出为 [OrmTaskException]。 * * @return Result if any, see [.getResult] 简体中文:结果(如果有),请参阅 [.getResult]。 */ @Synchronized @Throws(OrmTaskException::class) fun waitForCompletion(): Any? { lock.lock() try { while (!isCompleted) { try { condition.await() } catch (e: InterruptedException) { throw OrmTaskException("Interrupted while waiting for operation to complete.\n${e.message}") } } if (throwable != null) { throw OrmTaskException(this, throwable!!) } return result } finally { lock.unlock() } } /** * Waits until the operation is complete, but at most the given amount of milliseconds.If the * thread gets interrupted, any [InterruptedException] will be rethrown as a [OrmTaskException]. * 简体中文:等待操作完成,但最多等待指定的毫秒数。如果线程被中断,任何 [InterruptedException] 都会被重新抛出 * 为 [OrmTaskException]。 * * @return true if the operation completed in the given time frame. 简体中文:如果操作在指定的时间范 * 围内完成,则返回 true。 */ @Synchronized @Throws(OrmTaskException::class) fun waitForCompletion(maxMillis: Int): Boolean { lock.lock() try { if (!isCompleted) { try { val completedInTime = condition.await(maxMillis.toLong(), TimeUnit.MILLISECONDS) if (!completedInTime && !isCompleted) { return false } } catch (e: InterruptedException) { throw OrmTaskException("Interrupted while waiting for operation to complete.\n${e.message}") } } return isCompleted } finally { lock.unlock() } } /** * Called when the operation is done. Notifies any threads waiting for this operation's completion. * 简体中文:在操作完成时调用,通知所有等待该操作完成的线程。 */ fun setCompleted() { lock.lock() // 获取锁 try { isCompleted = true condition.signalAll() } finally { lock.unlock() } } val isCompletedSuccessfully: Boolean get() = isCompleted && throwable == null /** * Reset to prepare another execution run. * 简体中文:重置以准备另一次执行运行。 */ fun reset() { timeStarted = 0 timeCompleted = 0 isCompleted = false throwable = null result = null mergedTasksCount = 0 } companion object { const val FLAG_MERGE_TX: Int = 1 const val FLAG_STOP_QUEUE_ON_EXCEPTION: Int = 1 shl 1 const val FLAG_TRACK_CREATOR_STACKTRACE: Int = 1 shl 2 } }

OrmTask重点讲一下flag,FLAG_TRACK_CREATOR_STACKTRACE为框架实现的默认标志位,即执行异步ORM操作的时候,如果抛出了异常,框架会try catch掉,并记录到OrmTaskException中,在OrmTaskListener的onFailed()回调方法中传递给调用层。OrmDao类中都是采用的这种实现方式,要不然onFailed()就没用了。FLAG_STOP_QUEUE_ON_EXCEPTION这个标志位保留,异常会直接让app崩溃。

dcache的异步ORM使用范例

kotlin
代码解读
复制代码
DaoFactory.getDao(Tutorial::class.java).selectOneAsync(object : OrmTaskListener { override fun onCompleted(task: OrmTask<Tutorial>) { runOnUiThread { // 获取返回值 val tutorial = task.result(Tutorial::class.java) tvTutorial.text = tutorial.content } } override fun onFailed(task: OrmTask<Tutorial>, e: Exception) { LogUtils.e(e.toString()) } })

异步操作只要使用OrmDao中以Async结尾的方法即可。 另外github.com/dora4/DoraC… 可供参考。支持异步ORM操作的稳定版本为3.0.15,如果不需要异步功能,直接使用上一个大版本的稳定版本2.5.20就OK!

注:本文转载自juejin.cn的dora的文章"https://juejin.cn/post/7443652378069647410"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

140
Android
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top