0
votes

Comment puis-je attendre qu'une fonction soit faite en cours d'exécution avant de renvoyer une valeur?

J'ai un problème avec ce code dans lequel la relève retourne code> est déclenchée avant que la fonction OngetstatsCompleted code> fonctionne et renvoie 0 au lieu de la bonne valeur. Existe-t-il une façon de forcer ongetstatatsCompletd code> pour terminer avant de retourner packages sur code>? Je sais que c'est un problème logique parce que si je supprimais le commentaire à // thread.sleep code> Ça fonctionne bien.

Comment puis-je résoudre ce problème sans utiliser thread.sleep code> ou toute autre sorte de temps dans l'application? code d'origine: strong> p> xxx pré>


code edit: strong> p>

Ceci est la classe de stockage p> xxx pré>

appelant stockage d'une interface p> xxx pré>


J'ai également essayé la solution de r2rek et obtenir le même résultat P>

    try {
        GlobalScope.launch(Dispatchers.Main){
            var getPackageSizeInfo = withContext(coroutineContext) {
                pm.javaClass.getMethod(
                        "getPackageSizeInfo", String::class.java, IPackageStatsObserver::class.java)
            }
            getPackageSizeInfo.invoke(pm, context.packageName,
                    object : CachePackState() {//Call inner class
                    })
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}
return packageSize


0 commentaires

4 Réponses :


0
votes

Je vous recommande vivement de faire ce travail sur le fil d'arrière-plan en utilisant Rxjava, Coroutines ou AsyncCTTK. Mais vous pouvez utiliser un contextdownlatch pour faire une solution rapide.

//Ugly global variable
val countdownLatch = CountdownLatch(1) //-------CHANGE HERE--------

/**
Get the size of the app for API < 26
*/
@Throws(InterruptedException::class)
fun getPackageSize(): Long {

    val pm = context.packageManager
    try {
        val getPackageSizeInfo = pm.javaClass.getMethod(
                "getPackageSizeInfo", String::class.java, IPackageStatsObserver::class.java)
        getPackageSizeInfo.invoke(pm, context.packageName,
                object : CachePackState() {//Call inner class
                })
    } catch (e: Exception) {
        e.printStackTrace()
    }
    countDownLatch.await(1_000, TimeUnit.MILLISECONDS) //-------CHANGE HERE--------
    return packageSize
}

/**
  Inner class which will get the data size for the application
 */
open inner class CachePackState : IPackageStatsObserver.Stub() {

    override fun onGetStatsCompleted(pStats: PackageStats, succeeded: Boolean) {
        //here the pStats has all the details of the package
        dataSize = pStats.dataSize
        cacheSize = pStats.cacheSize
        apkSize = pStats.codeSize
        packageSize = cacheSize + apkSize
        countDownLatch.countDown() //-------CHANGE HERE--------
    }
}


1 commentaires

Je ne veux pas utiliser un compte à rebours non plus, mais je vais essayer d'utiliser l'asyncaptage



0
votes

Utilisation du thread.sleep (..) n'est pas seulement non seulement recommandé, il peut également verrouiller l'interface utilisateur et ne pas produire le résultat que vous souhaitez (si la méthode GetPackagesizeInfo fonctionne de plus de 1 seconde). Je suggère fortement d'obtenir des informations sur le fil d'arrière-plan, à l'aide de l'asyncaptage ou de la Corouté, comme @ Luciano-Ferruzzi suggéré. Puisque vous utilisez déjà Kotlin, j'irais une solution natale et utilisez des coroutines, ce qui pourrait ressembler à quelque chose comme ceci: xxx

Comme vous pouvez le constater, cela ne fait pas de modification de votre code. , à l'exception de manière explicitement indiquant les threads que vous utiliseriez pour des parties spécifiques du code.

* Désolé pour toutes les erreurs de code, je ne l'ai pas vraiment compilé.


1 commentaires

Cela retourne toujours 0, j'ai mis à jour la question pour montrer ce que j'ai fait



4
votes

Le moyen le plus simple consiste à utiliser Kotlin Coroutines A > et leurs fonctions de suspension.

Démarrer par Ajout eux à votre projet P>

    //wherever you want to get size
    ....
    getPackageSize(::handlePackageSize)
    ....

fun handlePackageSize(size: Long) {
    //do whatever you want with size
    launch(Dispatchers.Main) {
        findViewById<TextView>(R.id.textView).text = "APP SIZE= $size"
    }
}


16 commentaires

Cela semble être une solution possible. Je reçois des répartiteurs de référence non résolus et je ne trouve pas l'importation. J'ai aussi kotlin.coroutines = activer dans gradle.properties. Est-ce que tu sais pourquoi?


@ Phil652 Avez-vous ajouté Coroutines à votre projet? Github.com/kotlin/kotlinx.coroutines#gradle Partie principale et Android


Vous devriez être capable d'accéder à kotlinx.coroutines.dispatchers si vous avez ajouté une dépendance correctement


@ Phil652 Yep, je viens de vérifier la combinaison de la kotlinversion = 1.2.61 et de Coroutintinesversion = 1.2.1 fonctionne bien. Pouvez-vous montrer quelle dépendance kotlin utilisez-vous?


J'ai ajouté la mise en œuvre 2 pour les Coroutines de ma build.Gradle. Les répartiteurs sont résolus mais je reçois référence non résolue. Aucun des candidats suivants n'est applicable en raison du type de récepteur Mismatch: Fun Public Fun Coroutinescope.Launch (Contexte: COROUTINECONTEXT = ..., Démarrer: COROUTINESTART = ..., Bloc: Suspendez Coroutinescope. () → Unité): Job défini à Kotlinx .Coroutine et 'withContext (COROUTINECONTEXT, Suspend Coroutinescope. () -> T): T' n'est disponible que depuis Kotlin 1.3 et ne peut pas être utilisé dans Kotlin 1.2


@ Phil652 met à jour à Kotlin 1.3 quelque chose que vous ne pouvez pas faire? Parce que ce que j'ai proposé suit le guide fourni par l'équipe de Kotlin. Par exemple, ici Medium.com/@elizarov/coroutine-Context-and-scope- C8B255D5905 5


Je travaille actuellement sur cela sur une autre succursale, mais ce n'est pas encore prêt. Donc non pas pour le moment, mais je me mettrai à la mise à jour de Kotlin 1.3 dans un proche avenir


@ Phil652 J'ai découvert de savoir quel était votre problème si vous ne voulez pas mettre à niveau la version de Kotlin, vous devez utiliser une version très ancienne Version Coroutin Signification 0.30.2 pour le noyau et l'Android. Ensuite, cela fonctionnera comme décrit


J'ai déjà eu api "org.jetbrains.kotlinx: kotlinx-coroutines-android: 0.22.5" dans mon build.gadle comme une dépendance, est-il possible que cela provoque des problèmes lors de l'ajout de noyau de coroutine et Android


J'ai réussi à mettre en œuvre des coroutines de mon projet, j'ai mis à jour ma question avec le code actuel. J'ai toujours 0. Qu'est-ce que je fais mal?


Dans votre fonction de non-suspension, vous retournez 0, c'est la raison. Vous affectez la taille: long = 0; Ensuite, vous passez à un fil différent (à l'intérieur est exécuté sur un fil différent), puis vous retournez 0 car cela n'attend pas le résultat et vous ne voulez pas que cela attend. Vous pouvez soit marquer cette fonction comme suspension, puis quand vous avez besoin de résultat, appelez-le à l'intérieur E.g lancement . En vous case, vous pouvez simplement déplacer val appsifiés = formatfilesize (getApplicationContextex (), getPackagesize ()) à l'intérieur du globalscope.launch (Dispatchers.io) { et avez-vous l'action là.


Merci pour votre aide, il est utilisé dans un modèle de messagerie afin que je ne puisse pas vraiment mettre à jour l'interface utilisateur à l'intérieur du globalscope.launch (Dispatchers.io) { Y a-t-il un moyen de le faire en modifiant simplement une variable à l'intérieur du coroutinécope. Je peux ajouter plus de mon code si nécessaire


Je met à jour ma question avec quelque chose d'autre que j'ai essayé, je n'ai toujours aucune valeur


@ phil652 j'ai mis à jour la réponse montrant comment le gérer différemment


Avec ce module, je reçois avec le répartiteur principal est manquant . Cela pourrait être parce que j'utilise une version plus ancienne


@ Phil652 Avez-vous des corouts Android Dépendances?



0
votes

C'est une école assez ancienne mais que diriez-vous:

while(packageSize < 0) {
    Thread.sleep(100)
}


4 commentaires

Jusqu'à présent, c'est la seule solution de travail. Je ne sais tout simplement pas si c'est une bonne solution, WHIP.Sleep bloque un fil et de ce que j'ai appris que la meilleure pratique consiste à rester loin d'eux. Je pourrais avoir tort, je suis toujours très nouveau à Kotlin. Aussi, cela pourrait devenir une boucle infinie si pour une raison quelconque des paquets est toujours <0


1) thread.sleep est une fonctionnalité de base Java de base, donc je suis curieux de vos "meilleures pratiques". Vous rencontrez une condition de course si une sorte de coordination de fil est requise. 2) Si packages sur peut toujours rester négatif, c'est absolument une préoccupation que vous devrez aborder. Vous pouvez utiliser l'approche CountownTownLatch qui est essentiellement la même chose avec un peu plus de machines et vous permet d'attendre de manière conditionnelle avec attendre (délai d'attente longue, unité TimeUnit)


@Davidsoroko Vous recommandez-vous sérieusement de bloquer l'interface utilisateur pour 100ms ?!


Je ne recommande pas de valeur particulière pour le sommeil, le code sera correct de la durée ou sans sommeil si la filature de la CPU n'est pas une préoccupation.