במצבים מסוימים, יכול להיות שתצטרכו לספק אסטרטגיית שרשורים בהתאמה אישית. עבור
למשל, ייתכן שתצטרכו לטפל בפעולה אסינכרונית שמבוססת על קריאה חוזרת.
ב-WorkManager תומך בתרחיש לדוגמה הזה עם
ListenableWorker
ListenableWorker הוא ה-API הבסיסי ביותר של Worker;
Worker,
CoroutineWorker, וגם
RxWorker נגזרות מהכיתה הזו. א'
לפי ListenableWorker אפשר לסמן רק מתי העבודה צריכה להתחיל ולהפסיק, או לצאת ממנה
אתם קובעים את השרשור. אות ההתחלה של העבודה מופעל
לכן חשוב מאוד שתעברו לשרשור הרקע של
בחירה ידנית.
השיטה המופשטת
ListenableWorker.startWork()
מחזירה ListenableFuture מתוך
Result. א'
ListenableFuture הוא ממשק קל: הוא Future שמספק
פונקציונליות לצירוף מאזינים ולהפצת חריגים. ב
השיטה startWork, צפויה להחזיר ListenableFuture,
יוגדר כ-Result של הפעולה כאשר היא תסתיים. אפשר ליצור
ListenableFuture מופעים באחת משתי הדרכים הבאות:
- אם משתמשים ב-Guava, צריך להשתמש ב-
ListeningExecutorService. - אחרת, צריך לכלול
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>