WorkManager冻结UI

问题描述 投票:0回答:1

我有一个自定义工作人员,负责从API提取一些联系人,然后将这些联系人存储在电话的联系人列表中。该工作人员仍在冻结UI。任何帮助,将不胜感激。

这是Worker的doWork方法:

override fun doWork(): Result {

    return try {


        makeStatusNotification("Saving Contacts", applicationContext, "WorkRequest Starting")


            //MAIN METHOD CALL

            if (!checkContactListEmpty()) {
                removeAllContacts()
            }
        connectAndGetApiData()


        val x = Data.Builder()
        Result.success(x.build())

    } catch (e: Exception) {
        Log.e("NoWork","Unable to save image to Gallery $e")
        Result.failure()
    }

}

这是connectAndGetApi方法:

fun connectAndGetApiData() {

    val BASE_URL = "HTTP_URL"

    val res = Data.Builder()

    allNames = object : ArrayList<String>(){}
    allNumbers = object : ArrayList<String>(){}
    Log.d("entering", "connecting")
    if (retrofit == null) {
        retrofit = Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .addConverterFactory(ScalarsConverterFactory.create())
            .build()
    }
    val contactsApiService: RestApi? = retrofit?.create(RestApi::class.java)
    val call: Call<ContactList>? = contactsApiService?.getAllContactDetails()
    call?.enqueue(object : Callback<ContactList> {
        override fun onResponse(
            call: Call<ContactList>,
            response: Response<ContactList>
        ) {
            Log.d("AllContacts",response.message())
            val contactList: ContactList = response.body()
            if(contactList!= null){
                Log.d("AllContacts", contactList.allContacts.size.toString())
                for(x in contactList.allContacts){
                    addContact(x.name,x.phoneNo)
                    Thread.sleep(50)
                } 

            }else{
                Log.d("AllContacts", "contacts null")
            }


        }
        override fun onFailure(
            call: Call<ContactList>,
            throwable: Throwable
        ) {
            val TAG = "AllContacts"
            Log.e(TAG, throwable.toString())
        }
    })


}

removeAllContacts()是删除所有联系人的标准功能

Api导致一组大约22000个联系人

编辑:

这是addContact()方法

 private fun addContact(name:String?, number: String?) {

    var finalName = ""
    val finalNumber = number



    if(name?.isEmpty() == true){
        val tsLong = System.currentTimeMillis() / 1000
        val ts = tsLong.toString()
        finalName = "NoName$ts"
    }else{
        finalName = name.toString()
        finalName = finalName.substring(1,(finalName.length - 2))
    }

    val ops = ArrayList<ContentProviderOperation>()

    val rawContactID: Int = ops.size
    ops.add(
        ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
            .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
            .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
            .build()
    )
    ops.add(
        ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactID)
            .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, finalName)
            .build()
    )
    ops.add(
        ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactID)
            .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
            .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, finalNumber)
            .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
            .build()

        //
    )
    try { // Executing all the insert operations as a single database transaction

        Log.d(
            "AddingContact", "Name: $finalName Number: $finalNumber"
        )
        applicationContext.contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)
        Thread.sleep(50)
        Log.d("Contact Saved","Saved")
    } catch (e: RemoteException) {
        e.printStackTrace()
    } catch (e: OperationApplicationException) {
        e.printStackTrace()
    }
}
android kotlin worker android-workmanager
1个回答
2
投票

虽然从MainThread进行了此Retrofit调用,但回调在MainThread上。

call?.enqueue(object : Callback<ContactList> {

您在此回调中所做的任何事情都将在UI线程上。

您执行此代码:

          for(x in contactList.allContacts){
                addContact(x.name,x.phoneNo)
                Thread.sleep(50)
            } 

对于您在该列表中的每个联系人,UI线程都会休眠50毫秒。评论中说有22,000项???

[如果要使用较大的数据集,则需要使用后台线程。


一种快速而肮脏的解决方案是这样做:

使用协程:

 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.2"
 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2"

更改改造以使用协程:

interface ContactsApiService {
    @GET("whateverYourEndPointIs")
    suspend fun getAllApiDetails(): Response<ContactList>
}

全部在后台线程上运行:

GlobalScope.launch {
        val response: Response<ContactList> = contactsApiService?.getAllContactDetails() 
        Log.d("AllContacts",response.message())
        val contactList: ContactList = response.body()
        if (contactList!= null) {
            Log.d("AllContacts", contactList.allContacts.size.toString())
            for(x in contactList.allContacts){
                addContact(x.name,x.phoneNo)
                delay(50)
            } 

        } else {
            Log.d("AllContacts", "contacts null")
        }

}
© www.soinside.com 2019 - 2024. All rights reserved.