android,如何在Fragment被销毁从中启动协程时保持ViewModel中的暂停功能运行

问题描述

具有使用viewmodel从存储库获取数据的片段。

viewmodel:

class Myviewmodel:  viewmodel() {

    private var data: Article? = null

    // a suspend function actually behaviors as blocking call with withContext
    suspend fun getDataByUUID(uuid: String) : Data {
        return data ?: withContext(viewmodelScope.coroutineContext + dispatchers.IO) {
            (Repository.getDataByUUID(uuid)
                .also { data = it }
        }
    }
}

在Fragment中,它使用viewLifecycleOwner.lifecycleScope.launch{}调用viewmodel的暂挂函数getDataByUUID(uuid: String)

fun fetchData() {
    myviewmodel?.let {
        viewLifecycleOwner.lifecycleScope.launch(dispatchers.Main) {
            val data = it.getArticleByUUID(strUUID)
            article?.let {
                updateUIWithData(it)
            }
        }
    }
}

在Fragment中,它具有viewLifecycleOwner.lifecycleScope.launch {}, 在启动{}中,它将等待viewmodel的getArticleByUUID()和do update ui返回的数据。

它可以工作,但是对协程的范围和工作取消有疑问。

此处的片段中有viewLifecycleOwner.lifecycleScop。并在viewmodel中具有viewmodelScope

viewmodel的寿命可能更长(如果进行配置(即更改方向),并且片段可能会被破坏-由os重新创建,但viewmodel未被破坏

在那种情况下,如果碎片被破坏而viewmodel没有被破坏,我想viewLifecycleOwner.lifecycleScope.launch{}碎片中的作业将被取消,这就是我们想要的,以取消从碎片中启动的作业。 / p>

但是,如果viewmodel仍然存在,我们确实希望viewmodel的getArticleByUUID()在后​​台继续运行(因此数据可能会从远程获取并准备在下次使用)。

但是,当Fragment的启动作业被取消时,viewmodel中的suspend fun getDataByUUID()也将被取消吗?

viewLifecycleOwner.lifecycleScop.launch{}启动的片段作业被取消时,是否有一种方法可以让viewmodel中的suspend函数继续而不被取消?

解决方法

但是,当Fragment的启动作业被取消时,ViewModel中的悬挂乐趣getDataByUUID()也将被取消吗?

只要在视图模型中继续使用viewmodelscope,只有在销毁视图模型后,才会取消视图模型上的作业。

package sammysrentalprice;

import javax.swing.JOptionPane;

public class SammysRentalPrice
{

   
    public static void main(String[] args) 
    {
       final int RENT_PER_HOUR = 40;
       final int RENT_PER_ADDITIONAL_MINUTE = 1;
       final int MINUTES_IN_AN_HOUR = 60;
        
        int minutesRented;
        int hoursRented;
        int additionalMinutes;
        int total;
        
        
       JOptionPane.showMessageDialog(null,"SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS\n"
               + "SS                                                                        SS \n"
               + "SS    Sammy's makes it fun in the sun.      SS \n"
                + "SS                                                                        SS \n"
                       + "SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS\n");
        
       
    }
   
    
}

Example of what we should use (This was the lab before the one we are on)
 
package chap2.carlyseventprice;

import javax.swing.JOptionPane;

public class Chap2CarlysEventPrice 
{
    public static void main(String[] args) 
    {
        final int PRICE_PER_PERSON = 35;
        final int LARGE_EVENT = 50;
        
        String strNumOfGuests;
        int numOfGuests;
        int totalPrice;
                
        strNumOfGuests = JOptionPane.showInputDialog(null,"Enter the number of guests","Guest Entry",JOptionPane.INFORMATION_MESSAGE);
        numOfGuests = Integer.parseInt(strNumOfGuests);
        
        totalPrice = numOfGuests * PRICE_PER_PERSON; 
        
       JOptionPane.showMessageDialog(null,"*****************************************************\n"
              + "* Carly's makes the food that makes it a party! *\n"
              + "*****************************************************");
       JOptionPane.showMessageDialog(null,"Number Of Guests: " + numOfGuests
                + "\nPrice per Guest: " + PRICE_PER_PERSON
                +"\nTotal Price:      $" + totalPrice
                + "\nLarge event? " + (numOfGuests >= 50));
    }
   

如果每当破坏片段或取消片段中的作业时都删除 viewModelScope.coroutineContext ,您的 getDataByUUID 将被取消。

如果需要,您可以轻松地自己进行测试。您可以像这样延迟创建for:

withContext(viewModelScope.coroutineContext + Dispatchers.IO)