কাজ ম্যানেজ করা

আপনি আপনার Worker এবং আপনার WorkRequest সংজ্ঞায়িত করার পরে, শেষ ধাপ হল আপনার কাজ এনকিউ করা। কাজ এনকিউ করার সবচেয়ে সহজ উপায় হল WorkManager enqueue() পদ্ধতি কল করা, আপনি যে WorkRequest রান করতে চান সেটি পাস করা।

Kotlin

val myWork: WorkRequest = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork)

জাভা

WorkRequest myWork = // ... OneTime or PeriodicWork
WorkManager.getInstance(requireContext()).enqueue(myWork);

ডুপ্লিকেট এড়াতে কাজ এনকিউ করার সময় সাবধানতা অবলম্বন করুন। যেমন, কোনও অ্যাপ প্রতি ২৪ ঘণ্টায় ব্যাকএন্ড পরিষেবায় তার লগ আপলোড করার চেষ্টা করতে পারে। আপনি সতর্ক না থাকলে, একই টাস্ক অনেকবার সারিবদ্ধ করে ফেলতে পারেন, যদিও কাজটি শুধুমাত্র একবার চালানোর প্রয়োজন হয়। এই লক্ষ্য পূরণ করতে, আপনি অনন্য কাজ হিসেবে কাজটি শিডিউল করতে পারেন।

অনন্য কাজ

অনন্য কাজ হল একটি শক্তিশালী ধারণা যা গ্যারেন্টি দেয় যে আপনার কাছে একটি নির্দিষ্ট নাম সহ একই সময়ে শুধুমাত্র একটি কাজের ইনস্ট্যান্স আছে। আইডির মতো নয়, অনন্য নাম মানুষের-পঠনযোগ্য এবং WorkManager-এর মাধ্যমে অটোমেটিক জেনারেট হওয়ার পরিবর্তে ডেভেলপারের মাধ্যমে নির্দিষ্ট করা হয়। ট্যাগ-এর মতো নয়, অনন্য নাম শুধুমাত্র কাজের একটি ইনস্ট্যান্সের সাথে যুক্ত থাকে।

একবার ও নির্দিষ্ট সময় অন্তর করা কাজের ক্ষেত্রে অনন্য কাজ প্রয়োগ করা যেতে পারে। আপনি পুনরাবৃত্তি করা কাজ বা এককালীন কাজের শিডিউল করছেন কিনা তার উপর নির্ভর করে, এই পদ্ধতিগুলির মধ্যে একটিতে কল করে আপনি একটি অনন্য কাজের ক্রম তৈরি করতে পারেন।

এই দুটি পদ্ধতিই ৩টি আর্গুমেন্ট গ্রহণ করে:

  • uniqueWorkName - একটি String যা কাজের অনুরোধ অনন্যভাবে শনাক্ত করতে ব্যবহার করা হয়।
  • existingWorkPolicy - একটি enum যা WorkManager-কে বলে দেয় যে কী করতে হবে যদি সেই অনন্য নামের সাথে ইতিমধ্যেই একটি অসমাপ্ত কাজের চেইন থাকে। আরও তথ্যের জন্য বিরোধ নিষ্পত্তি সংক্রান্ত নীতি দেখুন।
  • work - শিডিউল করার জন্য WorkRequest।

অনন্য কাজ ব্যবহার করে, আমরা আগে উল্লেখ করা ডুপ্লিকেট শিডিউলিং সংক্রান্ত সমস্যা সমাধান করতে পারি।

Kotlin

val sendLogsWorkRequest =
       PeriodicWorkRequestBuilder<SendLogsWorker>(24, TimeUnit.HOURS)
           .setConstraints(Constraints.Builder()
               .setRequiresCharging(true)
               .build()
            )
           .build()
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
           "sendLogs",
           ExistingPeriodicWorkPolicy.KEEP,
           sendLogsWorkRequest
)

জাভা

PeriodicWorkRequest sendLogsWorkRequest = new
      PeriodicWorkRequest.Builder(SendLogsWorker.class, 24, TimeUnit.HOURS)
              .setConstraints(new Constraints.Builder()
              .setRequiresCharging(true)
          .build()
      )
     .build();
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
     "sendLogs",
     ExistingPeriodicWorkPolicy.KEEP,
     sendLogsWorkRequest);

এখন, sendLogs জব আগে থেকেই সারিতে থাকাকালীন কোডটি রান করলে, আগে থেকে থাকা জবটি রেখে দেওয়া হয় এবং নতুন কোনও জব যোগ করা হয় না।

টাস্কের একটি দীর্ঘ চেইন ধীরে ধীরে তৈরি করার প্রয়োজন হলে, অনন্য কাজের ক্রমও কার্যকর হতে পারে। যেমন, কোনও ফটো এডিটিং অ্যাপ ব্যবহারকারীদের অনেক অ্যাকশন বাতিল করার সুবিধা দিতে পারে। এইসব অপারেশন আগের অবস্থায় ফেরাতে কিছুটা সময় লাগতে পারে, তবে সেগুলি সঠিক ক্রমে করতে হবে। এই ক্ষেত্রে, অ্যাপটি একটি "আগের অবস্থায় ফেরান" চেইন তৈরি করতে পারে এবং প্রয়োজন অনুযায়ী চেইনে প্রতিটি আগের অবস্থায় ফেরানোর অপারেশন যোগ করতে পারে। আরও বিবরণের জন্য চেনিং ওয়ার্ক দেখুন।

দ্বন্দ্ব সমাধান সংক্রান্ত নীতি

অনন্য কাজ শিডিউল করার সময়, কোনও দ্বন্দ্ব দেখা দিলে কী অ্যাকশন নিতে হবে তা আপনাকে অবশ্যই WorkManager-কে জানাতে হবে। কাজটি সারিবদ্ধ করার সময় একটি enum পাস করে আপনি এটি করেন।

একবার কাজ করার জন্য, আপনি একটি ExistingWorkPolicy প্রদান করেন, যা দ্বন্দ্ব সমাধানের জন্য ৪টি বিকল্পকে সমর্থন করে।

  • আগে থেকে থাকা REPLACE-এর সাথে নতুন কাজ যোগ করুন। এই বিকল্পটি বেছে নিলে, আগে থেকে থাকা কাজ বাতিল হয়ে যায়।
  • KEEP আগে থেকে থাকা কাজ এবং নতুন কাজ উপেক্ষা করুন।
  • আগে থেকে থাকা কাজের শেষে নতুন কাজ APPEND করুন। এই নীতির ফলে আপনার নতুন কাজ, আগে থেকে থাকা কাজের সাথে চেন করা হবে এবং আগে থেকে থাকা কাজ শেষ হওয়ার পরে রান করবে।

আগে থেকে থাকা কাজটি নতুন কাজের জন্য প্রয়োজনীয় হয়ে যায়। আগে থেকে থাকা কাজ CANCELLED বা FAILED হলে, নতুন কাজও CANCELLED বা FAILED হবে। আগে থেকে থাকা কাজের স্ট্যাটাস যাই হোক না কেন, আপনি যদি নতুন কাজ চালাতে চান, তাহলে পরিবর্তে APPEND_OR_REPLACE ব্যবহার করুন।

  • APPEND_OR_REPLACE APPEND-এর মতোই কাজ করে, তবে এটি পূর্বশর্ত কাজের স্ট্যাটাসের উপর নির্ভর করে না। আগে থেকে থাকা কাজটি CANCELLED বা FAILED হলে, নতুন কাজটি এখনও চলবে।

নির্দিষ্ট সময় অন্তর কাজ করার জন্য, আপনি একটি ExistingPeriodicWorkPolicy প্রদান করেন, যা ২টি বিকল্পকে সমর্থন করে, REPLACE এবং KEEP। এইসব বিকল্প ExistingWorkPolicy-এর মতোই কাজ করে।

আপনার কাজ পর্যবেক্ষণ করা হচ্ছে

কাজ সারিবদ্ধ করার পরে যেকোনও সময়, আপনি name, id বা এর সাথে যুক্ত tag-এর মাধ্যমে WorkManager কোয়েরি করে এর স্ট্যাটাস চেক করতে পারবেন।

Kotlin

// by id
workManager.getWorkInfoById(syncWorker.id) // ListenableFuture<WorkInfo>

// by name
workManager.getWorkInfosForUniqueWork("sync") // ListenableFuture<List<WorkInfo>>

// by tag
workManager.getWorkInfosByTag("syncTag") // ListenableFuture<List<WorkInfo>>

জাভা

// by id
workManager.getWorkInfoById(syncWorker.id); // ListenableFuture<WorkInfo>

// by name
workManager.getWorkInfosForUniqueWork("sync"); // ListenableFuture<List<WorkInfo>>

// by tag
workManager.getWorkInfosByTag("syncTag"); // ListenableFuture<List<WorkInfo>>

কোয়েরিটি একটি WorkInfo অবজেক্টের ListenableFuture ফিরিয়ে দেয়, যার মধ্যে কাজের id, এর ট্যাগ, এর বর্তমান State এবং Result.success(outputData) ব্যবহার করে যেকোনও আউটপুট ডেটাসেট অন্তর্ভুক্ত থাকে।

প্রতিটি পদ্ধতির LiveData এবং Flow ভেরিয়েন্ট আপনাকে একজন শ্রোতাকে রেজিস্টার করে WorkInfo-এ পরিবর্তন লক্ষ্য করতে দেয়। যেমন, কোনও কাজ সফলভাবে শেষ হওয়ার পরে আপনি যদি ব্যবহারকারীকে মেসেজ দেখাতে চান, তাহলে আপনি এটি নিম্নলিখিতভাবে সেট-আপ করতে পারেন:

Kotlin

workManager.getWorkInfoByIdFlow(syncWorker.id)
          .collect{ workInfo ->
              if(workInfo?.state == WorkInfo.State.SUCCEEDED) {
                  Snackbar.make(requireView(),
                      R.string.work_completed, Snackbar.LENGTH_SHORT)
                      .show()
              }
          }

জাভা

workManager.getWorkInfoByIdLiveData(syncWorker.id)
        .observe(getViewLifecycleOwner(), workInfo -> {
    if (workInfo.getState() != null &&
            workInfo.getState() == WorkInfo.State.SUCCEEDED) {
        Snackbar.make(requireView(),
                    R.string.work_completed, Snackbar.LENGTH_SHORT)
                .show();
   }
});

কাজ সংক্রান্ত জটিল কোয়েরি

WorkManager 2.4.0 এবং তার পরবর্তী ভার্সন WorkQuery অবজেক্ট ব্যবহার করে সারিবদ্ধ কাজের জন্য জটিল কোয়েরি সমর্থন করে। WorkQuery-এর মাধ্যমে ট্যাগ, স্ট্যাটাস ও কাজের অনন্য নামের কম্বিনেশন ব্যবহার করে কাজ কোয়েরি করা যায়।

নিচের উদাহরণে দেখানো হয়েছে যে "syncTag" ট্যাগ ব্যবহার করে আপনি কীভাবে সব কাজ খুঁজে পাবেন, যা FAILED বা CANCELLED অবস্থায় আছে এবং যার অনন্য কাজের নাম "preProcess" বা "sync"।

Kotlin

val workQuery = WorkQuery.Builder
       .fromTags(listOf("syncTag"))
       .addStates(listOf(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
       .addUniqueWorkNames(listOf("preProcess", "sync")
    )
   .build()

val workInfos: ListenableFuture<List<WorkInfo>> = workManager.getWorkInfos(workQuery)

জাভা

WorkQuery workQuery = WorkQuery.Builder
       .fromTags(Arrays.asList("syncTag"))
       .addStates(Arrays.asList(WorkInfo.State.FAILED, WorkInfo.State.CANCELLED))
       .addUniqueWorkNames(Arrays.asList("preProcess", "sync")
     )
    .build();

ListenableFuture<List<WorkInfo>> workInfos = workManager.getWorkInfos(workQuery);

WorkQuery-এর প্রতিটি কম্পোনেন্ট (ট্যাগ, স্টেট বা নাম) অন্যগুলির সাথে AND-ed করা আছে। কম্পোনেন্টের প্রতিটি ভ্যালু OR-ed। যেমন: (name1 OR name2 OR ...) AND (tag1 OR tag2 OR ...) AND (state1 OR state2 OR ...)।

WorkQuery LiveData-এর সমতুল্য, getWorkInfosLiveData(), এবং Flow-এর সমতুল্য, getWorkInfosFlow()-এর সাথেও কাজ করে।

কাজ বাতিল ও বন্ধ করা হচ্ছে

আগে থেকে সারিবদ্ধ করা কাজ আর চালানোর প্রয়োজন না হলে, আপনি সেটি বাতিল করার জন্য অনুরোধ করতে পারেন। কাজটি তার name, id বা এর সাথে যুক্ত tag দ্বারা বাতিল করা যেতে পারে।

Kotlin

// by id
workManager.cancelWorkById(syncWorker.id)

// by name
workManager.cancelUniqueWork("sync")

// by tag
workManager.cancelAllWorkByTag("syncTag")

জাভা

// by id
workManager.cancelWorkById(syncWorker.id);

// by name
workManager.cancelUniqueWork("sync");

// by tag
workManager.cancelAllWorkByTag("syncTag");

WorkManager ব্যাকগ্রাউন্ডে কাজের State চেক করে। কাজটি যদি আগে থেকেই শেষ হয়ে গিয়ে থাকে, তাহলে কিছুই হবে না। অন্যথায়, কাজের স্ট্যাটাস পরিবর্তন করে CANCELLED করা হবে এবং ভবিষ্যতে কাজটি আর রান করবে না। WorkRequest-এর যেকোনও কাজ যা এই কাজের উপর নির্ভরশীল, সেগুলিও CANCELLED হবে।

RUNNING অফিস ListenableWorker.onStopped()-এ কল রিসিভ করে। সম্ভাব্য ক্লিন-আপ ম্যানেজ করতে এই পদ্ধতি ওভাররাইড করুন। আরও তথ্যের জন্য চলমান ওয়ার্কার বন্ধ করুন দেখুন।

চলমান Worker বন্ধ করুন

WorkManager-এর মাধ্যমে আপনার চালু থাকা Worker বন্ধ হয়ে যাওয়ার কয়েকটি কারণ থাকতে পারে:

  • আপনি স্পষ্টভাবে এটি বাতিল করার জন্য অনুরোধ করেছেন (যেমন, WorkManager.cancelWorkById(UUID)-এ কল করে)।
  • অনন্য কাজের ক্ষেত্রে, আপনি স্পষ্টভাবে একটি নতুন WorkRequest-কে ExistingWorkPolicy-এর সাথে REPLACE-এ এনকিউ করেছেন। পুরনো WorkRequest অবিলম্বে বাতিল বলে গণ্য করা হয়।
  • আপনার কাজের সীমাবদ্ধতা আর পূরণ করা হয়নি।
  • কোনও কারণে সিস্টেম আপনার অ্যাপকে কাজ বন্ধ করার নির্দেশ দিয়েছে। ১০ মিনিটের মধ্যে টাস্ক সম্পূর্ণ না করলে এমন হতে পারে। কাজটি পরে আবার চেষ্টা করার জন্য শিডিউল করা হয়েছে।

এইসব পরিস্থিতিতে, আপনার Worker বন্ধ হয়ে যায়।

আপনার প্রসেসে থাকা যেকোনও কাজ আপনার সহযোগিতামূলকভাবে বাতিল করা উচিত এবং আপনার Worker-এর হোল্ড করা যেকোনও রিসোর্স রিলিজ করা উচিত। যেমন, এই মুহূর্তে আপনার ডেটাবেস ও ফাইলের খোলা হ্যান্ডেল বন্ধ করে দেওয়া উচিত। আপনার Worker কখন বন্ধ হচ্ছে তা বোঝার জন্য আপনার কাছে দুটি মেকানিজম আছে।

onStopped() কলব্যাক

আপনার Worker বন্ধ হয়ে যাওয়ার সাথে সাথেই WorkManager ListenableWorker.onStopped() ইনভোক করে। আপনার কাছে থাকা যেকোনও রিসোর্স বন্ধ করতে এই পদ্ধতি ওভাররাইড করুন।

isStopped() প্রপার্টি

আপনার ওয়ার্কার আগেই বন্ধ হয়ে গেছে কিনা তা চেক করতে আপনি ListenableWorker.isStopped() মেথড কল করতে পারেন। আপনি যদি আপনার Worker-এ দীর্ঘ-চলমান বা পুনরাবৃত্তিমূলক অপারেশন সম্পাদন করেন, তাহলে আপনার এই প্রপার্টিটি ঘন ঘন চেক করা উচিত এবং যত তাড়াতাড়ি সম্ভব কাজ বন্ধ করার জন্য একটি সংকেত হিসাবে এটি ব্যবহার করা উচিত।

মনে রাখবেন: WorkManager, onStop সিগন্যাল পাওয়া কোনও Worker-এর সেট করা Result উপেক্ষা করে, কারণ Worker-কে আগে থেকেই বন্ধ হিসেবে বিবেচনা করা হয়।