I'm developing an application that monitors customer's sales calls and uploads them to the server. I'm using following periodic method in a service to auto-upload calls that were not synced. It runs after every 0.5Hr delay.
After reducing the delay to 5s I noticed that the memory heap keeps on increasing every 5s. I quickly figured out that setting up callLogInfo
is causing the memory issue which on long run leads to lags, memory leaks, slow phones.
GlobalScope.launch(Dispatchers.IO) {
val projection = arrayOf(
"_id",
CallLog.Calls.NUMBER,
CallLog.Calls.DATE,
CallLog.Calls.DURATION,
CallLog.Calls.TYPE,
CallLog.Calls.CACHED_NAME,
CallLog.Calls.PHONE_ACCOUNT_ID
)
val contentResolver = App.getContext().applicationContext.contentResolver
val helper: DatabaseHelper = DatabaseHelper.getInstance(App.getContext())
val callLogInfo = CallLogInfo()
while (true) {
Log.d("CallMonitorService", "Scanner loop")
try {
contentResolver.query(
CallLog.Calls.CONTENT_URI,
projection,
null,
null,
CallLog.Calls.DEFAULT_SORT_ORDER
)?.also { cursor ->
cursor.moveToFirst()
while (!cursor.isAfterLast) {
// Following 6 lines were the main cause of increasing memory heap
callLogInfo.name = cursor.getString(cursor.getColumnIndex(CallLog.Calls.CACHED_NAME))
callLogInfo.number = cursor.getString(cursor.getColumnIndex(CallLog.Calls.NUMBER))
callLogInfo.callType = cursor.getString(cursor.getColumnIndex(CallLog.Calls.TYPE))
callLogInfo.date = cursor.getLong(cursor.getColumnIndex(CallLog.Calls.DATE))
callLogInfo.duration = cursor.getLong(cursor.getColumnIndex(CallLog.Calls.DURATION))
callLogInfo.simId = cursor.getStringOrNull(cursor.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_ID))
// If Call is not marked as "SYNCED" in Database, post the call for upload on a different handler
// It also marks the call as "SYNCED" after successful upload
// This is rarely called because most of the calls are synced from a BroadcastReceiver
if (helper.getStatus(callLogInfo.getUID()) != "SYNCED") {
UploadUtil().uploadCallLogAsync(App.getContext(), callLogInfo)
}
cursor.moveToNext()
}
cursor.close()
}
} catch (e: Exception) {
Log.d("CallMonitorService","Exception in scanner loop: $e")
}
delay(5000) // (In ms) Actually it is 1800 * 1000 but for testing I use 5 * 1000
}
}
callLogInfo
class
class CallLogInfo {
var name: String? = null
var number: String? = null
var callType: String? = null
var date: Long = 0
var duration: Long = 0
var simId: String? = null
fun getUID(): String {
return "${this.number}_${this.callType}_${this.date}"
}
}
- Increasing memory heap
I know that for periodic tasks it is recommended to use either Handler
+ postDelayed
or ScheduledExecutorService
. I tried both the methods but faced the same issue so decided to post the original code.
Can anyone suggest a better and efficient approach to this or suggest some refactoring?
Thank you!!