2
votes

Android WorkManager lance trop de tâches simultanément

J'implémente la fonctionnalité de téléchargement / téléchargement en arrière-plan parallèle dans mon application à l'aide de workmanager. Tout fonctionne très bien, sauf que WorkManager exécute trop de tâches simultanément et que le téléphone ne répond plus jusqu'à ce que les choses se terminent. Je voudrais mettre 10 tâches en file d'attente et demander à WM d'exécuter 2 en parallèle jusqu'à ce que les 10 soient terminées. WorkManager semble exécuter 5-10 en parallèle. Je ne peux pas comprendre comment faire cela. J'ai essayé ma propre configuration avec un seul exécuteur threadé et cela ne fait aucune différence. Comment puis-je limiter le nombre de tâches exécutées à la fois? J'utilise 1.0.0-rc01.


0 commentaires

3 Réponses :


2
votes

Vous pouvez utiliser une Configuration personnalisée pour définir le nombre de Worker que vous souhaitez exécuter simultanément. Quelque chose comme ça dans votre Application.onCreate () . Pour plus d'informations, lisez comment initialiser WorkManager avec une configuration personnalisée.

val config = Configuration.Builder()
  .setExecutor(yourExecutor)
  .build()

WorkManager.initialize(context, config)


5 commentaires

J'ai essayé cela avec un seul exécuteur threadé, cela ne fait aucune différence


Assurez-vous que vous avez correctement initialisé WorkManager. Vous devez désactiver l'initialiseur par défaut sinon le second appel à initialize n'aura aucun effet. Vous ne verrez qu'un avertissement indiquant qu'il a déjà été initialisé.


J'ai toujours ce problème avec 2.1.0-beta02. J'utilise ListenableWorker si cela fait une différence. Peu importe si je remplace la configuration, cela lance toujours beaucoup plus de travaux que Executors.newFixedThreadPool (2) ne devrait le permettre. 10-20 vs 2. L'initialiseur par défaut est désactivé.


J'ai la même expérience que @ 2fours. J'ai essayé .setExecutor (Executors.newFixedThreadPool (5)) mais cela ne le limite pas à 5 ouvriers en cours d'exécution à un moment donné, cela dépasse certainement cela dans mes tests.


J'ai ouvert un problème sur leur outil de suivi des bogues issuetracker.google.com/issues/155370056



0
votes

Si vous utilisez ListenableWorker puis personnalisé Configuration avec setExecutor n'aidera pas. La raison étant que cet exécuteur est uniquement destiné à exécuter le Worker et non ListenableWorker. Ainsi, dans ce cas particulier, vous pouvez avoir votre propre pool de threads fixes, que vous pouvez utiliser lorsque démarrage du processus d'arrière-plan . Un des moyens d'y parvenir avec un pool de threads fixe dans ExecutorService -

public class MyExecutorService {
    private static ExecutorService executorService = null;

    public static ExecutorService getExecutorService() {
        if (executorService == null) {
            executorService = Executors.newFixedThreadPool(2);
        }
        return executorService;
    }
}


public class MyListenableWorker extends ListenableWorker {

    public MyListenableWorker(@NonNull Context appContext, @NonNull WorkerParameters workerParams) {
        super(appContext, workerParams);
    }

    @NonNull
    @Override
    public ListenableFuture<Result> startWork() {
        MyExecutorService.getExecutorService().execute(new Runnable() {
            @Override
            public void run() {
                doBackgroundWork();
            }
        });

        return future; // see note below
    }
}

Remarque : si vous utilisez votre ListenableWorker personnalisé, vous devez conserver l'état de ListenableFuture comme indiqué ici .


2 commentaires

À quoi cela ressemble-t-il lorsque vous avez affaire à un RxWorker et non à un ListenableWorker . Le RxWorker que j'ai créé implémente actuellement toute la logique de override fun createWork (): Single {} alors comment cela changerait-il dans le cas d'un RxWorker ?


Dans ce cas, vous pouvez fournir à l'exécuteur un pool de threads fixe dans la configuration. Mais je vois que ça ne marche pas pour toi. Ainsi, vous pouvez remplacer la méthode getBackgroundScheduler () dans votre classe RxWorker et renvoyer le planificateur avec un pool de threads fixe. Comme ceci - Scheduler protégé getBackgroundScheduler () {return Schedulers.from (MyExecutorService.getExecutorService ()); }



0
votes

Je teste cet exemple de code et travaille pour moi sans aucun bug, 10 nœuds d'exécution parallèles ( .setExecutor (Executors.newFixedThreadPool (10)) ) pour télécharger le fichier sans aucun décalage et geler le fil de l'interface utilisateur: J'utilise implementation 'android.arch.work:work-runtime:1.0.0-beta02' . sur votre AndroidManifest.xml:

public class MyWorkA extends Worker {

    private static final String TAB = MyWorkA.class.getSimpleName();

    public MyWorkA(@NonNull Context context, @NonNull WorkerParameters workerParams) {
        super(context, workerParams);
    }

    @NonNull
    @Override
    public Result doWork() {

        Log.e(TAB,"My WorkA");

        InputStream input = null;
        OutputStream output = null;
        HttpURLConnection connection = null;
        try {
            URL url = new URL("http://ipv4.download.thinkbroadband.com/20MB.zip");
            connection = (HttpURLConnection) url.openConnection();
            connection.connect();

            if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
            }

            int fileLength = connection.getContentLength();

            input = connection.getInputStream();
            output = new FileOutputStream("/sdcard/file_nameA.zip");

            byte data[] = new byte[4096];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {

                total += count;
                if (fileLength > 0)
                output.write(data, 0, count);
            }
        } catch (Exception e) {
            Log.i("test", e.getMessage());
        } finally {
            try {
                if (output != null)
                    output.close();
                if (input != null)
                    input.close();
            } catch (IOException ignored) {
            }

            if (connection != null)
                connection.disconnect();
        }

        return Result.success();
    }
}

dans App.java:

OneTimeWorkRequest MyWorkA = new OneTimeWorkRequest.Builder(MyWorkA.class)
        .build();
OneTimeWorkRequest MyWorkB = new OneTimeWorkRequest.Builder(MyWorkB.class)
        .build();
OneTimeWorkRequest MyWorkC = new OneTimeWorkRequest.Builder(MyWorkC.class)
        .build();
OneTimeWorkRequest MyWorkD = new OneTimeWorkRequest.Builder(MyWorkD.class)
        .build();
OneTimeWorkRequest MyWorkE = new OneTimeWorkRequest.Builder(MyWorkE.class)
        .build();
OneTimeWorkRequest MyWorkF = new OneTimeWorkRequest.Builder(MyWorkF.class)
        .build();
OneTimeWorkRequest MyWorkG = new OneTimeWorkRequest.Builder(MyWorkG.class)
        .build();
OneTimeWorkRequest MyWorkH = new OneTimeWorkRequest.Builder(MyWorkH.class)
        .build();
OneTimeWorkRequest MyWorkI = new OneTimeWorkRequest.Builder(MyWorkI.class)
        .build();
OneTimeWorkRequest MyWorkJ = new OneTimeWorkRequest.Builder(MyWorkJ.class)
        .build();
OneTimeWorkRequest MyWorkK = new OneTimeWorkRequest.Builder(MyWork.class)
        .build();
OneTimeWorkRequest MyWorkL = new OneTimeWorkRequest.Builder(MyWorkL.class)
        .build();
List<OneTimeWorkRequest> allWorker = new ArrayList<>();
allWorker.add(MyWorkA);
allWorker.add(MyWorkB);
allWorker.add(MyWorkC);
allWorker.add(MyWorkD);
allWorker.add(MyWorkE);
allWorker.add(MyWorkF);
allWorker.add(MyWorkG);
allWorker.add(MyWorkH);
allWorker.add(MyWorkI);
allWorker.add(MyWorkJ);
WorkManager.getInstance()
        .enqueue(allWorker);

dans MainActivity.java:

Configuration configuration = new Configuration.Builder()
            .setExecutor(Executors.newFixedThreadPool(10))
            .build();
WorkManager.initialize(getApplicationContext(), configuration);

et pour MyWorkA.java vers MyWorkJ.java code > utilisez ce code (fichier de téléchargement factice):

<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

<application        
    android:name=".App"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:usesCleartextTraffic="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <provider
        android:name="androidx.work.impl.WorkManagerInitializer"
        android:authorities="de.stocard.stocard.workmanager-init"
        android:enabled="false"
        tools:replace="android:authorities"/>

</application>


0 commentaires