Android WorkManager冻结UI

Android WorkManager冻结UI,android,kotlin,worker,android-workmanager,Android,Kotlin,Worker,Android Workmanager,我有一个自定义工作人员,负责从API获取一些联系人,然后将这些联系人存储在手机的联系人列表中。此工作人员仍在冻结UI。任何帮助都将不胜感激 这是工人的嫁妆方法: override fun doWork(): Result { return try { makeStatusNotification("Saving Contacts", applicationContext, "WorkRequest Starting") //MAIN ME

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

这是工人的嫁妆方法:

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())
        }
    })


}
fun connectAndGetApiData(){
val BASE_URL=“HTTP_URL”
val res=Data.Builder()
allNames=object:ArrayList(){}
allNumbers=object:ArrayList(){}
日志d(“进入”、“连接”)
如果(改装==null){
改装=改装.Builder()
.baseUrl(基本URL)
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(ScalarsConverterFactory.create())
.build()
}
val contactsApiService:RestApi?=改装?.create(RestApi::class.java)
val call:call?=ContactsAspiService?.getAllContactDetails()
call?.enqueue(对象:Callback){
覆盖响应(
呼叫:呼叫,,
答复:答复
) {
Log.d(“所有联系人”,response.message())
val contactList:contactList=response.body()
如果(联系人列表!=null){
Log.d(“AllContacts”,contactList.AllContacts.size.toString())
用于(联系人列表中的x。所有联系人){
addContact(x.name,x.phoneNo)
线程。睡眠(50)
} 
}否则{
Log.d(“所有联系人”,“联系人为空”)
}
}
覆盖故障(
呼叫:呼叫,,
可以扔掉的
) {
val TAG=“所有联系人”
Log.e(标记,throwable.toString())
}
})
}
removeAllContacts()是删除所有联系人的标准函数

Api产生了大约22000个联系人

编辑:

这是addContact()方法

private fun addContact(姓名:String?,号码:String?){
var finalName=“”
val finalNumber=数字
if(name?.isEmpty()==true){
val tsLong=System.currentTimeMillis()/1000
val ts=tsLong.toString()
finalName=“非名称$ts”
}否则{
finalName=name.toString()
finalName=finalName.substring(1,(finalName.length-2))
}
val ops=ArrayList()
val rawContactID:Int=ops.size
补充行动(
ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT\u URI)
.withValue(contacts contract.raw contacts.ACCOUNT_TYPE,null)
.withValue(contacts contract.raw contacts.ACCOUNT\u NAME,null)
.build()
)
补充行动(
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT\u URI)
.带ValueBackReference(contacts contract.Data.RAW\u CONTACT\u ID,RAW contactId)
.withValue(contacts contract.Data.MIMETYPE、contacts contract.commonDataTypes.StructuredName.CONTENT\u ITEM\u TYPE)
.withValue(contacts contract.CommonDataTypes.StructuredName.DISPLAY\u NAME,finalName)
.build()
)
补充行动(
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT\u URI)
.带ValueBackReference(contacts contract.Data.RAW\u CONTACT\u ID,RAW contactId)
.withValue(contacts contract.Data.MIMETYPE、contacts contract.commondatatypes.Phone.CONTENT\u ITEM\u TYPE)
.带值(contacts contract.commondatatypes.Phone.NUMBER,finalNumber)
.withValue(contacts contract.commondatatypes.Phone.TYPE,contacts contract.commondatatypes.Phone.TYPE\u MOBILE)
.build()
//
)
尝试{//将所有插入操作作为单个数据库事务执行
对数d(
“添加联系人”,“姓名:$finalName号码:$finalNumber”
)
applicationContext.contentResolver.applyBatch(contacts contract.AUTHORITY,ops)
线程。睡眠(50)
Log.d(“已保存联系人”、“已保存”)
}catch(e:RemoteException){
e、 printStackTrace()
}捕获(e:操作应用程序异常){
e、 printStackTrace()
}
}

当此改装调用在主线程之外完成时,回调在主线程上

i、 e.
call?.enqueue(对象:Callback{

在此回调中执行的任何操作都将在UI线程上执行

您可以执行以下代码:

          for(x in contactList.allContacts){
                addContact(x.name,x.phoneNo)
                Thread.sleep(50)
            } 
对于列表中的每个联系人,它都会让UI线程休眠50毫秒。评论中说哪个有22000个项目

如果要处理如此大的数据集,需要使用后台线程


一个快速而肮脏的解决方案是:

使用协同程序:

 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>
}
将改装更改为使用协同程序:

 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>
}
接口接触器{
@获取(“无论您的端点是什么”)
suspend fun GetAllapDetails():响应
}
在后台线程上运行这一切:

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")
        }

}
GlobalScope.launch{
val response:response=contactsApiService?.getAllContactDetails()
Log.d(“所有联系人”,response.message())
val contactList:contactList=response.body()
如果(联系人列表!=null){
Log.d(“AllContacts”,contactList.AllContacts.size.toString())
用于(联系人列表中的x。所有联系人){
addContact(x.name,x.phoneNo)
延迟(50)
} 
}否则{
Log.d(“所有联系人”,“联系人为空”)
}
}

哪个函数挂起UI connectAndGetApiData()或removeAllContacts()?connecAndGetApiData()方法冻结UI您的
addContact
函数是否在后台线程上运行?似乎是在获取22000个联系人的列表后(在后台线程上使用改型队列)您正在迭代22000个项目,并在
addContact
函数中执行一些工作(我不知道它是做什么的)。addContact函数也在worker类中定义,并在那里调用,因此是的,addContact函数在后台运行