שרשור ב-ListenableWorker

במצבים מסוימים, יכול להיות שתצטרכו לספק אסטרטגיית שרשורים בהתאמה אישית. עבור למשל, ייתכן שתצטרכו לטפל בפעולה אסינכרונית שמבוססת על קריאה חוזרת. ב-WorkManager תומך בתרחיש לדוגמה הזה עם ListenableWorker ListenableWorker הוא ה-API הבסיסי ביותר של Worker; Worker, CoroutineWorker, וגם RxWorker נגזרות מהכיתה הזו. א' לפי ListenableWorker אפשר לסמן רק מתי העבודה צריכה להתחיל ולהפסיק, או לצאת ממנה אתם קובעים את השרשור. אות ההתחלה של העבודה מופעל לכן חשוב מאוד שתעברו לשרשור הרקע של בחירה ידנית.

השיטה המופשטת ListenableWorker.startWork() מחזירה ListenableFuture מתוך Result. א' ListenableFuture הוא ממשק קל: הוא Future שמספק פונקציונליות לצירוף מאזינים ולהפצת חריגים. ב השיטה startWork, צפויה להחזיר ListenableFuture, יוגדר כ-Result של הפעולה כאשר היא תסתיים. אפשר ליצור ListenableFuture מופעים באחת משתי הדרכים הבאות:

  1. אם משתמשים ב-Guava, צריך להשתמש ב-ListeningExecutorService.
  2. אחרת, צריך לכלול councurrent-futures בקובץ Gradle ולהשתמש CallbackToFutureAdapter

אם רצית לבצע עבודה מסוימת על סמך קריאה חוזרת אסינכרונית, עושים משהו כזה:

Kotlin

class CallbackWorker(
        context: Context,
        params: WorkerParameters
) : ListenableWorker(context, params) {
    override fun startWork(): ListenableFuture<Result> {
        return CallbackToFutureAdapter.getFuture { completer ->
            val callback = object : Callback {
                var successes = 0

                override fun onFailure(call: Call, e: IOException) {
                    completer.setException(e)
                }

                override fun onResponse(call: Call, response: Response) {
                    successes++
                    if (successes == 100) {
                        completer.set(Result.success())
                    }
                }
            }

            repeat(100) {
                downloadAsynchronously("https://example.com", callback)
            }

            callback
        }
    }
}

Java

public class CallbackWorker extends ListenableWorker {

    public CallbackWorker(Context context, WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public ListenableFuture<Result> startWork() {
        return CallbackToFutureAdapter.getFuture(completer -> {
            Callback callback = new Callback() {
                int successes = 0;

                @Override
                public void onFailure(Call call, IOException e) {
                    completer.setException(e);
                }

                @Override
                public void onResponse(Call call, Response response) {
                    successes++;
                    if (successes == 100) {
                        completer.set(Result.success());
                    }
                }
            };

            for (int i = 0; i < 100; i++) {
                downloadAsynchronously("https://www.example.com", callback);
            }
            return callback;
        });
    }
}

מה קורה אם העבודה שלכם נעצר? ListenableFuture של ListenableWorker תמיד מבוטל כשהעבודה צפוי להפסיק. באמצעות CallbackToFutureAdapter, צריך רק להוסיף מבטל את ה-listener, באופן הבא:

Kotlin

class CallbackWorker(
        context: Context,
        params: WorkerParameters
) : ListenableWorker(context, params) {
    override fun startWork(): ListenableFuture<Result> {
        return CallbackToFutureAdapter.getFuture { completer ->
            val callback = object : Callback {
                var successes = 0

                override fun onFailure(call: Call, e: IOException) {
                    completer.setException(e)
                }

                override fun onResponse(call: Call, response: Response) {
                    ++successes
                    if (successes == 100) {
                        completer.set(Result.success())
                    }
                }
            }

 completer.addCancellationListener(cancelDownloadsRunnable, executor)

            repeat(100) {
                downloadAsynchronously("https://example.com", callback)
            }

            callback
        }
    }
}

Java

public class CallbackWorker extends ListenableWorker {

    public CallbackWorker(Context context, WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public ListenableFuture<Result> startWork() {
        return CallbackToFutureAdapter.getFuture(completer -> {
            Callback callback = new Callback() {
                int successes = 0;

                @Override
                public void onFailure(Call call, IOException e) {
                    completer.setException(e);
                }

                @Override
                public void onResponse(Call call, Response response) {
                    ++successes;
                    if (successes == 100) {
                        completer.set(Result.success());
                    }
                }
            };

            completer.addCancellationListener(cancelDownloadsRunnable, executor);

            for (int i = 0; i < 100; ++i) {
                downloadAsynchronously("https://www.example.com", callback);
            }
            return callback;
        });
    }
}

הרצת ListenableWorker בתהליך אחר

אפשר גם לקשר עובד לתהליך ספציפי באמצעות RemoteListenableWorker יישום של ListenableWorker.

RemoteListenableWorker מקושר לתהליך ספציפי עם שני ארגומנטים נוספים שאתם מספקים כחלק מנתוני הקלט בתהליך היצירה של בקשת העבודה: ARGUMENT_CLASS_NAME וגם ARGUMENT_PACKAGE_NAME

הדוגמה הבאה ממחישה יצירה של בקשת עבודה שקשורה תהליך ספציפי:

Kotlin

val PACKAGE_NAME = "com.example.background.multiprocess"

val serviceName = RemoteWorkerService::class.java.name
val componentName = ComponentName(PACKAGE_NAME, serviceName)

val data: Data = Data.Builder()
   .putString(ARGUMENT_PACKAGE_NAME, componentName.packageName)
   .putString(ARGUMENT_CLASS_NAME, componentName.className)
   .build()

return OneTimeWorkRequest.Builder(ExampleRemoteListenableWorker::class.java)
   .setInputData(data)
   .build()

Java

String PACKAGE_NAME = "com.example.background.multiprocess";

String serviceName = RemoteWorkerService.class.getName();
ComponentName componentName = new ComponentName(PACKAGE_NAME, serviceName);

Data data = new Data.Builder()
        .putString(ARGUMENT_PACKAGE_NAME, componentName.getPackageName())
        .putString(ARGUMENT_CLASS_NAME, componentName.getClassName())
        .build();

return new OneTimeWorkRequest.Builder(ExampleRemoteListenableWorker.class)
        .setInputData(data)
        .build();

לכל RemoteWorkerService צריך להוסיף הגדרת שירות גם בקטע קובץ AndroidManifest.xml שלך:

<manifest ... >
    <service
            android:name="androidx.work.multiprocess.RemoteWorkerService"
            android:exported="false"
            android:process=":worker1" />

        <service
            android:name=".RemoteWorkerService2"
            android:exported="false"
            android:process=":worker2" />
    ...
</manifest>

דוגמיות