ExerciseClient এর সাথে একটি ব্যায়াম রেকর্ড করুন

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

GitHub-এ ব্যায়ামের নমুনা দেখুন।

নির্ভরতা যোগ করুন

স্বাস্থ্য পরিষেবার উপর নির্ভরতা যোগ করতে, আপনাকে অবশ্যই আপনার প্রকল্পে Google Maven সংগ্রহস্থল যোগ করতে হবে। আরও তথ্যের জন্য, Google এর Maven সংগ্রহস্থল দেখুন।

তারপর, আপনার মডিউল-স্তরের build.gradle ফাইলে, নিম্নলিখিত নির্ভরতা যোগ করুন:

গ্রোভি

dependencies {
    implementation "androidx.health:health-services-client:1.1.0-alpha03"
}

কোটলিন

dependencies {
    implementation("androidx.health:health-services-client:1.1.0-alpha03")
}

অ্যাপের গঠন

স্বাস্থ্য পরিষেবাগুলির সাথে একটি ব্যায়াম অ্যাপ তৈরি করার সময় নিম্নলিখিত অ্যাপ কাঠামো ব্যবহার করুন:

  • আপনার স্ক্রিন এবং নেভিগেশন একটি প্রধান কার্যকলাপের মধ্যে রাখুন।
  • ওয়ার্কআউট স্টেট, সেন্সর ডেটা, চলমান কার্যকলাপ এবং ফোরগ্রাউন্ড পরিষেবার মাধ্যমে ডেটা পরিচালনা করুন।
  • Room এর সাথে ডেটা সঞ্চয় করুন এবং ডেটা আপলোড করতে WorkManager ব্যবহার করুন৷

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

একটি ForegroundService ব্যবহার করা আপনাকে আপনার ঘড়ির পৃষ্ঠে একটি সূচক দেখানোর জন্য চলমান কার্যকলাপ API ব্যবহার করতে দেয়, ব্যবহারকারীকে দ্রুত ওয়ার্কআউটে ফিরে যেতে দেয়।

এটি অপরিহার্য যে আপনি আপনার ফোরগ্রাউন্ড পরিষেবাতে যথাযথভাবে অবস্থানের ডেটার অনুরোধ করুন৷ আপনার ম্যানিফেস্ট ফাইলে, foregroundServiceType="location" উল্লেখ করুন এবং উপযুক্ত অনুমতিগুলি নির্দিষ্ট করুন।

আপনার প্রি-ওয়ার্কআউট কার্যকলাপের জন্য AmbientLifecycleObserver ব্যবহার করুন, যেটিতে prepareExercise() কল রয়েছে এবং আপনার ওয়ার্কআউট কার্যকলাপের জন্য। যাইহোক, অ্যাম্বিয়েন্ট মোড চলাকালীন ওয়ার্কআউটের সময় ডিসপ্লে আপডেট করবেন না: এর কারণ হল যখন ডিভাইসের স্ক্রীন অ্যাম্বিয়েন্ট মোডে থাকে তখন পাওয়ার সঞ্চয় করার জন্য স্বাস্থ্য পরিষেবা ব্যাকআউট ডেটা ব্যাচ করে, তাই প্রদর্শিত তথ্য সাম্প্রতিক নাও হতে পারে। ওয়ার্কআউটের সময়, এমন ডেটা দেখান যা ব্যবহারকারীর কাছে বোধগম্য হয়, হয় আপ-টু-ডেট তথ্য বা ফাঁকা স্ক্রীন প্রদর্শন করে।

ক্ষমতা পরীক্ষা করুন

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

অ্যাপ স্টার্টআপে, ডিভাইসের ক্ষমতাগুলি জিজ্ঞাসা করুন এবং নিম্নলিখিতগুলি সংরক্ষণ এবং প্রক্রিয়া করুন:

  • প্ল্যাটফর্ম সমর্থন করে যে অনুশীলন.
  • প্রতিটি ব্যায়ামের জন্য সমর্থিত বৈশিষ্ট্য.
  • প্রতিটি ব্যায়ামের জন্য সমর্থিত ডেটা প্রকার।
  • প্রতিটি ডেটা প্রকারের জন্য প্রয়োজনীয় অনুমতি।

আপনার পছন্দসই ব্যায়ামের ধরন সহ ExerciseCapabilities.getExerciseTypeCapabilities() ব্যবহার করুন আপনি কি ধরণের মেট্রিক্সের জন্য অনুরোধ করতে পারেন, আপনি কোন ব্যায়ামের লক্ষ্যগুলি কনফিগার করতে পারেন এবং সেই ধরণের জন্য অন্য কোন বৈশিষ্ট্যগুলি উপলব্ধ রয়েছে। এটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

val healthClient = HealthServices.getClient(this /*context*/)
val exerciseClient = healthClient.exerciseClient
lifecycleScope.launch {
    val capabilities = exerciseClient.getCapabilitiesAsync().await()
    if (ExerciseType.RUNNING in capabilities.supportedExerciseTypes) {
        runningCapabilities =
            capabilities.getExerciseTypeCapabilities(ExerciseType.RUNNING)
    }
}

ফিরে আসা ExerciseTypeCapabilities এর ভিতরে, supportedDataTypes সেই ডেটা প্রকারগুলি তালিকাভুক্ত করে যার জন্য আপনি ডেটার জন্য অনুরোধ করতে পারেন৷ এটি ডিভাইস অনুসারে পরিবর্তিত হয়, তাই সতর্ক থাকুন যাতে সমর্থিত নয় এমন DataType অনুরোধ না করা যায় বা আপনার অনুরোধ ব্যর্থ হতে পারে।

supportedGoals এবং supportedMilestones ক্ষেত্রগুলি ব্যবহার করুন ব্যায়ামটি আপনি তৈরি করতে চান এমন একটি অনুশীলন লক্ষ্য সমর্থন করতে পারে কিনা তা নির্ধারণ করতে।

যদি আপনার অ্যাপ ব্যবহারকারীকে স্বয়ংক্রিয় বিরতি ব্যবহার করতে দেয়, তাহলে আপনাকে অবশ্যই পরীক্ষা করতে হবে যে এই কার্যকারিতাটি supportsAutoPauseAndResume ব্যবহার করে ডিভাইস দ্বারা সমর্থিত। ExerciseClient অনুরোধগুলি প্রত্যাখ্যান করে যা ডিভাইসে সমর্থিত নয়।

নিম্নলিখিত উদাহরণটি HEART_RATE_BPM ডেটা টাইপ, STEPS_TOTAL লক্ষ্য ক্ষমতা এবং স্বয়ং-বিরাম কার্যকারিতার জন্য সমর্থন পরীক্ষা করে:

// Whether we can request heart rate metrics.
supportsHeartRate = DataType.HEART_RATE_BPM in runningCapabilities.supportedDataTypes

// Whether we can make a one-time goal for aggregate steps.
val stepGoals = runningCapabilities.supportedGoals[DataType.STEPS_TOTAL]
supportsStepGoals = 
    (stepGoals != null && ComparisonType.GREATER_THAN_OR_EQUAL in stepGoals)

// Whether auto-pause is supported.
val supportsAutoPause = runningCapabilities.supportsAutoPauseAndResume

ব্যায়াম রাষ্ট্র আপডেটের জন্য নিবন্ধন করুন

ব্যায়াম আপডেট একটি শ্রোতা বিতরণ করা হয়. আপনার অ্যাপটি একবারে শুধুমাত্র একজন শ্রোতাকে নিবন্ধন করতে পারে। ওয়ার্কআউট শুরু করার আগে আপনার শ্রোতা সেট আপ করুন, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে। আপনার শ্রোতা শুধুমাত্র আপনার অ্যাপের মালিকানাধীন ব্যায়াম সম্পর্কে আপডেট পাবেন।

val callback = object : ExerciseUpdateCallback {
    override fun onExerciseUpdateReceived(update: ExerciseUpdate) {
        val exerciseStateInfo = update.exerciseStateInfo
        val activeDuration = update.activeDurationCheckpoint
        val latestMetrics = update.latestMetrics
        val latestGoals = update.latestAchievedGoals
    }

    override fun onLapSummaryReceived(lapSummary: ExerciseLapSummary) {
        // For ExerciseTypes that support laps, this is called when a lap is marked.
    }

    override fun onAvailabilityChanged(
        dataType: DataType<*, *>,
        availability: Availability
    ) {
        // Called when the availability of a particular DataType changes.
        when {
            availability is LocationAvailability -> // Relates to Location/GPS.
            availability is DataTypeAvailability -> // Relates to another DataType.
        }
    }
}
exerciseClient.setUpdateCallback(callback)

ব্যায়াম জীবনকাল পরিচালনা করুন

স্বাস্থ্য পরিষেবাগুলি ডিভাইসের সমস্ত অ্যাপ জুড়ে একটি সময়ে সর্বাধিক একটি ব্যায়াম সমর্থন করে৷ যদি একটি ব্যায়াম ট্র্যাক করা হয় এবং একটি ভিন্ন অ্যাপ একটি নতুন ব্যায়াম ট্র্যাক করা শুরু করে, প্রথম ব্যায়ামটি বন্ধ হয়ে যায়।

আপনার ব্যায়াম শুরু করার আগে, নিম্নলিখিতগুলি করুন:

  • একটি অনুশীলন ইতিমধ্যে ট্র্যাক করা হচ্ছে কিনা তা পরীক্ষা করুন এবং সেই অনুযায়ী প্রতিক্রিয়া জানান। উদাহরণস্বরূপ, পূর্ববর্তী অনুশীলনকে ওভাররাইড করার আগে এবং একটি নতুন ট্র্যাক করা শুরু করার আগে ব্যবহারকারীকে নিশ্চিতকরণের জন্য জিজ্ঞাসা করুন।

নিম্নলিখিত উদাহরণটি দেখায় কিভাবে getCurrentExerciseInfoAsync এর সাথে বিদ্যমান ব্যায়াম পরীক্ষা করতে হয়:

lifecycleScope.launch {
    val exerciseInfo = exerciseClient.getCurrentExerciseInfoAsync().await()
    when (exerciseInfo.exerciseTrackedStatus) {
        OTHER_APP_IN_PROGRESS -> // Warn user before continuing, will stop the existing workout.
        OWNED_EXERCISE_IN_PROGRESS -> // This app has an existing workout.
        NO_EXERCISE_IN_PROGRESS -> // Start a fresh workout.
    }
}

অনুমতি

ExerciseClient ব্যবহার করার সময়, নিশ্চিত করুন যে আপনার অ্যাপটি প্রয়োজনীয় অনুমতির অনুরোধ করে এবং বজায় রাখে। আপনার অ্যাপ যদি LOCATION ডেটা ব্যবহার করে, তাহলে নিশ্চিত করুন যে আপনার অ্যাপ অনুরোধ করছে এবং সেইসাথে উপযুক্ত অনুমতি বজায় রাখছে।

সমস্ত ডেটা প্রকারের জন্য, prepareExercise() বা startExercise() কল করার আগে, নিম্নলিখিতগুলি করুন:

  • আপনার AndroidManifest.xml ফাইলে অনুরোধ করা ডেটাটাইপগুলির জন্য উপযুক্ত অনুমতিগুলি নির্দিষ্ট করুন৷
  • ব্যবহারকারী প্রয়োজনীয় অনুমতি প্রদান করেছে তা যাচাই করুন। আরও তথ্যের জন্য, অ্যাপের অনুমতির অনুরোধ দেখুন। প্রয়োজনীয় অনুমতি ইতিমধ্যে মঞ্জুর না হলে স্বাস্থ্য পরিষেবাগুলি অনুরোধ প্রত্যাখ্যান করে৷

অবস্থান ডেটার জন্য, নিম্নলিখিত অতিরিক্ত পদক্ষেপগুলি করুন:

  • isProviderEnabled(LocationManager.GPS_PROVIDER) ব্যবহার করে ডিভাইসে GPS সক্ষম করা আছে কিনা তা পরীক্ষা করুন। প্রয়োজনে ব্যবহারকারীকে অবস্থান সেটিংস খুলতে অনুরোধ করুন।
  • ওয়ার্কআউট জুড়ে যথাযথ foregroundServiceType সহ একটি ForegroundService বজায় রাখা হয়েছে তা নিশ্চিত করুন।

একটি ওয়ার্কআউট জন্য প্রস্তুত

কিছু সেন্সর, যেমন GPS বা হার্ট রেট, গরম হতে অল্প সময় নিতে পারে, অথবা ব্যবহারকারী তাদের ওয়ার্কআউট শুরু করার আগে তাদের ডেটা দেখতে চাইতে পারে। ঐচ্ছিক prepareExerciseAsync() পদ্ধতি এই সেন্সরগুলিকে ওয়ার্ম আপ করতে দেয় এবং ওয়ার্কআউটের জন্য টাইমার শুরু না করেই ডেটা গ্রহণ করতে দেয়। activeDuration এই প্রস্তুতির সময় দ্বারা প্রভাবিত হয় না।

prepareExerciseAsync() এ কল করার আগে, নিম্নলিখিতগুলি পরীক্ষা করুন:

  • প্ল্যাটফর্ম-ব্যাপী অবস্থান সেটিং পরীক্ষা করুন। ব্যবহারকারী প্রধান সেটিংস মেনুতে এই সেটিং নিয়ন্ত্রণ করে; এটি অ্যাপ-লেভেল পারমিশন চেক থেকে আলাদা।

    সেটিংটি বন্ধ থাকলে, ব্যবহারকারীকে জানান যে তারা অবস্থানে অ্যাক্সেস অস্বীকার করেছে এবং আপনার অ্যাপের লোকেশনের প্রয়োজন হলে এটি সক্ষম করার জন্য তাদের অনুরোধ করুন।

  • নিশ্চিত করুন যে আপনার অ্যাপে বডি সেন্সর, অ্যাক্টিভিটি রিকগনিশন এবং সূক্ষ্ম অবস্থানের জন্য রানটাইম অনুমতি রয়েছে। অনুপস্থিত অনুমতিগুলির জন্য, পর্যাপ্ত প্রসঙ্গ প্রদান করে রানটাইম অনুমতির জন্য ব্যবহারকারীকে অনুরোধ করুন। যদি ব্যবহারকারী একটি নির্দিষ্ট অনুমতি না দেয়, তাহলে prepareExerciseAsync() কল থেকে সেই অনুমতির সাথে যুক্ত ডেটা প্রকারগুলি সরিয়ে দিন। যদি বডি সেন্সর বা অবস্থানের অনুমতি না দেওয়া হয়, prepareExerciseAsync() এ কল করবেন না, কারণ প্রস্তুতি কলটি বিশেষভাবে একটি ব্যায়াম শুরু করার আগে একটি স্থিতিশীল হার্ট রেট বা GPS ফিক্স করার জন্য। অ্যাপটি এখনও ধাপ-ভিত্তিক দূরত্ব, গতি, গতি এবং অন্যান্য মেট্রিক্স পেতে পারে যার জন্য সেই অনুমতিগুলির প্রয়োজন নেই।

prepareExerciseAsync() এ আপনার কল সফল হতে পারে তা নিশ্চিত করতে নিম্নলিখিতগুলি করুন:

  • প্রি-ওয়ার্কআউট ক্রিয়াকলাপের জন্য AmbientLifecycleObserver ব্যবহার করুন যাতে প্রস্তুত কল রয়েছে।
  • আপনার ফোরগ্রাউন্ড পরিষেবা থেকে prepareExerciseAsync() কল করুন। যদি এটি একটি পরিষেবাতে না থাকে এবং কার্যকলাপের জীবনচক্রের সাথে আবদ্ধ থাকে, তাহলে সেন্সর প্রস্তুতি অপ্রয়োজনীয়ভাবে নিহত হতে পারে।
  • ব্যবহারকারী যদি প্রি-ওয়ার্কআউট কার্যকলাপ থেকে দূরে সরে যান তাহলে সেন্সর বন্ধ করতে এবং পাওয়ার ব্যবহার কমাতে endExercise() এ কল করুন।

নিচের উদাহরণটি দেখায় কিভাবে prepareExerciseAsync() কল করতে হয়:

val warmUpConfig = WarmUpConfig(
    ExerciseType.RUNNING,
    setOf(
        DataType.HEART_RATE_BPM,
        DataType.LOCATION
    )
)
// Only necessary to call prepareExerciseAsync if body sensor or location
//permissions are given
exerciseClient.prepareExerciseAsync(warmUpConfig).await()

// Data and availability updates are delivered to the registered listener.

একবার অ্যাপটি PREPARING অবস্থায় চলে গেলে, সেন্সর উপলব্ধতা আপডেটগুলি ExerciseUpdateCallback onAvailabilityChanged() মাধ্যমে বিতরণ করা হয়। এই তথ্যটি ব্যবহারকারীর কাছে উপস্থাপন করা যেতে পারে যাতে তারা তাদের ওয়ার্কআউট শুরু করবেন কিনা তা সিদ্ধান্ত নিতে পারে।

ওয়ার্কআউট শুরু করুন

আপনি যখন একটি ব্যায়াম শুরু করতে চান, তখন ব্যায়ামের ধরন কনফিগার করার জন্য একটি ExerciseConfig তৈরি করুন, যে ডেটা টাইপগুলির জন্য আপনি মেট্রিক্স পেতে চান এবং যে কোনো ব্যায়ামের লক্ষ্য বা মাইলফলক।

ব্যায়াম লক্ষ্য একটি DataType এবং একটি শর্ত গঠিত. ব্যায়াম লক্ষ্য হল একটি এককালীন লক্ষ্য যা একটি শর্ত পূরণ করার সময় ট্রিগার হয়, যেমন ব্যবহারকারী যখন একটি নির্দিষ্ট দূরত্ব চালায়। একটি ব্যায়াম মাইলফলক সেট করা যেতে পারে. ব্যায়ামের মাইলফলকগুলি একাধিকবার ট্রিগার করা যেতে পারে, যেমন প্রতিবার ব্যবহারকারী তাদের নির্দিষ্ট দূরত্ব অতিক্রম করে একটি নির্দিষ্ট বিন্দু চালান।

নিম্নলিখিত নমুনা দেখায় কিভাবে প্রতিটি ধরনের একটি লক্ষ্য তৈরি করতে হয়:

const val CALORIES_THRESHOLD = 250.0
const val DISTANCE_THRESHOLD = 1_000.0 // meters

suspend fun startExercise() {
    // Types for which we want to receive metrics.
    val dataTypes = setOf(
        DataType.HEART_RATE_BPM,
        DataType.CALORIES_TOTAL,
        DataType.DISTANCE
    )

    // Create a one-time goal.
    val calorieGoal = ExerciseGoal.createOneTimeGoal(
        DataTypeCondition(
            dataType = DataType.CALORIES_TOTAL,
            threshold = CALORIES_THRESHOLD,
            comparisonType = ComparisonType.GREATER_THAN_OR_EQUAL
        )
    )

    // Create a milestone goal. To make a milestone for every kilometer, set the initial
    // threshold to 1km and the period to 1km.
    val distanceGoal = ExerciseGoal.createMilestone(
        condition = DataTypeCondition(
            dataType = DataType.DISTANCE_TOTAL,
            threshold = DISTANCE_THRESHOLD,
            comparisonType = ComparisonType.GREATER_THAN_OR_EQUAL
        ),
        period = DISTANCE_THRESHOLD
    )

    val config = ExerciseConfig(
        exerciseType = ExerciseType.RUNNING,
        dataTypes = dataTypes,
        isAutoPauseAndResumeEnabled = false,
        isGpsEnabled = true,
        exerciseGoals = mutableListOf<ExerciseGoal<Double>>(calorieGoal, distanceGoal)
    )
    exerciseClient.startExerciseAsync(config).await()
}

আপনি সমস্ত ব্যায়ামের জন্য ল্যাপ চিহ্নিত করতে পারেন। স্বাস্থ্য পরিষেবা ল্যাপ পিরিয়ডের সাথে একত্রিত মেট্রিক্স সহ একটি ExerciseLapSummary প্রদান করে।

পূর্ববর্তী উদাহরণটি isGpsEnabled এর ব্যবহার দেখায়, যা অবস্থান ডেটার অনুরোধ করার সময় সত্য হতে হবে। যাইহোক, জিপিএস ব্যবহার করা অন্যান্য মেট্রিক্সের সাথেও সহায়তা করতে পারে। যদি ExerciseConfig একটি DataType হিসাবে দূরত্ব নির্দিষ্ট করে, তবে এটি দূরত্ব অনুমান করার পদক্ষেপগুলি ব্যবহার করার জন্য ডিফল্ট হয়। ঐচ্ছিকভাবে GPS সক্ষম করে, দূরত্ব অনুমান করার পরিবর্তে অবস্থানের তথ্য ব্যবহার করা যেতে পারে।

বিরতি, পুনরায় শুরু করুন এবং একটি ওয়ার্কআউট শেষ করুন

আপনি বিরতি, পুনরায় শুরু করতে এবং যথাযথ পদ্ধতি ব্যবহার করে ওয়ার্কআউট শেষ করতে পারেন, যেমন pauseExerciseAsync() বা endExerciseAsync()

ExerciseUpdate থেকে রাজ্যটিকে সত্যের উৎস হিসেবে ব্যবহার করুন। ওয়ার্কআউটটিকে বিরতি দেওয়া বলে বিবেচিত হয় না যখন pauseExerciseAsync() করার কলটি ফিরে আসে, তবে পরিবর্তে যখন সেই অবস্থাটি ExerciseUpdate বার্তায় প্রতিফলিত হয়। UI রাজ্যের ক্ষেত্রে এটি বিবেচনা করা বিশেষভাবে গুরুত্বপূর্ণ। ব্যবহারকারী যদি বিরতি চাপেন, তাহলে বিরতি বোতামটি অক্ষম করুন এবং স্বাস্থ্য পরিষেবাগুলিতে pauseExerciseAsync() কল করুন৷ ExerciseUpdate.exerciseStateInfo.state ব্যবহার করে স্বাস্থ্য পরিষেবাগুলি বিরাম দেওয়া অবস্থায় পৌঁছানোর জন্য অপেক্ষা করুন এবং তারপরে পুনরায় শুরু করার জন্য বোতামটি স্যুইচ করুন৷ এর কারণ হল স্বাস্থ্য পরিষেবাগুলির রাজ্য আপডেটগুলি বিলি করতে বোতাম প্রেসের চেয়ে বেশি সময় নিতে পারে, তাই আপনি যদি সমস্ত UI পরিবর্তনগুলি বোতাম টিপে টাই করেন, তাহলে UI স্বাস্থ্য পরিষেবাগুলির রাজ্যের সাথে সিঙ্ক থেকে বেরিয়ে যেতে পারে৷

নিম্নলিখিত পরিস্থিতিতে এটি মনে রাখবেন:

  • স্বয়ংক্রিয়-বিরতি সক্ষম করা হয়েছে: ওয়ার্কআউটটি ব্যবহারকারীর ইন্টারঅ্যাকশন ছাড়াই বিরতি বা শুরু করতে পারে।
  • অন্য একটি অ্যাপ ওয়ার্কআউট শুরু করে: ব্যবহারকারীর ইন্টারঅ্যাকশন ছাড়াই আপনার ওয়ার্কআউট বন্ধ হয়ে যেতে পারে।

যদি আপনার অ্যাপের ওয়ার্কআউট অন্য অ্যাপের দ্বারা বন্ধ করা হয়, তাহলে আপনার অ্যাপটিকে অবশ্যই সমাপ্তিটি ভালোভাবে পরিচালনা করতে হবে:

  • আংশিক ওয়ার্কআউট অবস্থা সংরক্ষণ করুন যাতে ব্যবহারকারীর অগ্রগতি মুছে না যায়।
  • চলমান ক্রিয়াকলাপ আইকনটি সরান এবং ব্যবহারকারীকে একটি বিজ্ঞপ্তি পাঠান যাতে তারা জানায় যে তাদের ওয়ার্কআউট অন্য অ্যাপ দ্বারা শেষ হয়েছে।

এছাড়াও, চলমান অনুশীলনের সময় অনুমতি প্রত্যাহার করা হয় এমন ক্ষেত্রে পরিচালনা করুন। এটি AUTO_END_PERMISSION_LOST এর একটি ExerciseEndReason সহ isEnded অবস্থা ব্যবহার করে পাঠানো হয়। এই কেসটি সমাপ্তির ক্ষেত্রে একইভাবে পরিচালনা করুন: আংশিক অবস্থা সংরক্ষণ করুন, চলমান কার্যকলাপ আইকনটি সরান এবং ব্যবহারকারীর সাথে কী ঘটেছে সে সম্পর্কে একটি বিজ্ঞপ্তি পাঠান।

নিম্নলিখিত উদাহরণ দেখায় কিভাবে সঠিকভাবে সমাপ্তির জন্য পরীক্ষা করতে হয়:

val callback = object : ExerciseUpdateCallback {
    override fun onExerciseUpdateReceived(update: ExerciseUpdate) {
        if (update.exerciseStateInfo.state.isEnded) {
            // Workout has either been ended by the user, or otherwise terminated
        }
        ...
    }
    ...
}

সক্রিয় সময়কাল পরিচালনা করুন

ব্যায়ামের সময়, একটি অ্যাপ ওয়ার্কআউটের সক্রিয় সময়কাল প্রদর্শন করতে পারে। অ্যাপ, স্বাস্থ্য পরিষেবা, এবং ডিভাইস মাইক্রো কন্ট্রোলার ইউনিট (MCU)- ব্যায়াম ট্র্যাকিংয়ের জন্য দায়ী কম-পাওয়ার প্রসেসর—সমস্তকে একই বর্তমান সক্রিয় সময়কালের সাথে সিঙ্কে থাকতে হবে। এটি পরিচালনা করতে সহায়তা করার জন্য, স্বাস্থ্য পরিষেবাগুলি একটি ActiveDurationCheckpoint পাঠায় যা একটি অ্যাঙ্কর পয়েন্ট সরবরাহ করে যেখান থেকে অ্যাপটি তার টাইমার শুরু করতে পারে।

যেহেতু সক্রিয় সময়কাল MCU থেকে পাঠানো হয় এবং অ্যাপে পৌঁছাতে অল্প সময় নিতে পারে, ActiveDurationCheckpoint দুটি বৈশিষ্ট্য রয়েছে:

  • activeDuration : ব্যায়াম কতক্ষণ ধরে সক্রিয় হয়েছে
  • time : যখন সক্রিয় সময়কাল গণনা করা হয়েছিল

অতএব, অ্যাপে একটি অনুশীলনের সক্রিয় সময়কাল নিম্নলিখিত সমীকরণ ব্যবহার করে ActiveDurationCheckpoint থেকে গণনা করা যেতে পারে:

(now() - checkpoint.time) + checkpoint.activeDuration

এটি এমসিইউতে গণনা করা এবং অ্যাপে পৌঁছানোর মধ্যে সক্রিয় সময়কালের ছোট ডেল্টার জন্য দায়ী। এটি অ্যাপে একটি ক্রোনোমিটার সিড করার জন্য ব্যবহার করা যেতে পারে এবং অ্যাপের টাইমারটি স্বাস্থ্য পরিষেবা এবং MCU-এর সময়ের সাথে পুরোপুরি সামঞ্জস্যপূর্ণ কিনা তা নিশ্চিত করতে সাহায্য করতে পারে।

অনুশীলনটি বিরতি দেওয়া হলে, অ্যাপটি UI-তে টাইমারটি পুনরায় চালু করার জন্য অপেক্ষা করে যতক্ষণ না গণনা করা সময়টি UI বর্তমানে যা প্রদর্শন করে তা অতিক্রম করে। এর কারণ হল বিরতি সংকেত স্বাস্থ্য পরিষেবা এবং MCU-তে সামান্য বিলম্বে পৌঁছায়। উদাহরণস্বরূপ, যদি অ্যাপটি t=10 সেকেন্ডে বিরতি দেওয়া হয়, তাহলে স্বাস্থ্য পরিষেবাগুলি t=10.2 সেকেন্ড পর্যন্ত অ্যাপে PAUSED আপডেট নাও দিতে পারে।

ExerciseClient থেকে ডেটা নিয়ে কাজ করুন

আপনার অ্যাপের জন্য নিবন্ধিত ডেটা প্রকারের মেট্রিক্স ExerciseUpdate বার্তাগুলিতে বিতরণ করা হয়।

প্রসেসর শুধুমাত্র যখন জাগ্রত থাকে বা যখন সর্বোচ্চ রিপোর্টিং সময়সীমা পৌঁছে যায়, যেমন প্রতি 150 সেকেন্ডে বার্তা প্রদান করে। activeDuration এর সাথে একটি ক্রোনোমিটার অগ্রসর করতে ExerciseUpdate ফ্রিকোয়েন্সির উপর নির্ভর করবেন না। কিভাবে একটি স্বাধীন ক্রোনোমিটার বাস্তবায়ন করতে হয় তার উদাহরণের জন্য GitHub-এ ব্যায়ামের নমুনা দেখুন।

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

ব্যাচিং হার নিয়ন্ত্রণ করুন

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

ব্যাচিং রেট কনফিগার করতে, নিম্নলিখিত পদক্ষেপগুলি সম্পূর্ণ করুন:

  1. নির্দিষ্ট BatchingMode সংজ্ঞা ডিভাইস দ্বারা সমর্থিত কিনা তা পরীক্ষা করুন:

    // Confirm BatchingMode support to control heart rate stream to phone.
    suspend fun supportsHrWorkoutCompanionMode(): Boolean {
        val capabilities = exerciseClient.getCapabilities()
        return BatchingMode.HEART_RATE_5_SECONDS in
                capabilities.supportedBatchingModeOverrides
    }
    
  2. নির্দিষ্ট করুন যে ExerciseConfig অবজেক্টের একটি নির্দিষ্ট BatchingMode ব্যবহার করা উচিত, যেমনটি নিম্নলিখিত কোড স্নিপেটে দেখানো হয়েছে।

    val config = ExerciseConfig(
        exerciseType = ExerciseType.WORKOUT,
        dataTypes = setOf(
            DataType.HEART_RATE_BPM,
            DataType.TOTAL_CALORIES
        ),
        // ...
        batchingModeOverrides = setOf(BatchingMode.HEART_RATE_5_SECONDS)
    )
    
  3. ঐচ্ছিকভাবে, আপনি ওয়ার্কআউটের সময় BatchingMode গতিশীলভাবে কনফিগার করতে পারেন, একটি নির্দিষ্ট ব্যাচিং আচরণ ওয়ার্কআউটের সময়কাল জুড়ে থাকার পরিবর্তে:

    val desiredModes = setOf(BatchingMode.HEART_RATE_5_SECONDS)
    exerciseClient.overrideBatchingModesForActiveExercise(desiredModes)
    
  4. কাস্টমাইজ করা BatchingMode সাফ করতে এবং ডিফল্ট আচরণে ফিরে যেতে, exerciseClient.overrideBatchingModesForActiveExercise() এ একটি খালি সেট পাস করুন।

টাইমস্ট্যাম্প

প্রতিটি ডেটা পয়েন্টের পয়েন্ট-ইন-টাইম ডিভাইসটি বুট হওয়ার সময়কালকে উপস্থাপন করে। এটিকে একটি টাইমস্ট্যাম্পে রূপান্তর করতে, নিম্নলিখিতগুলি করুন:

val bootInstant =
    Instant.ofEpochMilli(System.currentTimeMillis() - SystemClock.elapsedRealtime())

এই মান তারপর প্রতিটি ডেটা পয়েন্টের জন্য getStartInstant() বা getEndInstant() এর সাথে ব্যবহার করা যেতে পারে।

ডেটা নির্ভুলতা

কিছু ডেটা প্রকারের প্রতিটি ডেটা পয়েন্টের সাথে সম্পর্কিত সঠিক তথ্য থাকতে পারে। এই accuracy সম্পত্তি প্রতিনিধিত্ব করা হয়.

HrAccuracy এবং LocationAccuracy ক্লাসগুলি যথাক্রমে HEART_RATE_BPM এবং LOCATION ডেটা প্রকারের জন্য তৈরি করা যেতে পারে। যেখানে উপস্থিত, প্রতিটি ডেটা পয়েন্ট আপনার অ্যাপ্লিকেশনের জন্য যথেষ্ট নির্ভুলতা কিনা তা নির্ধারণ করতে accuracy বৈশিষ্ট্য ব্যবহার করুন।

সঞ্চয় করুন এবং ডেটা আপলোড করুন

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

ইন্টিগ্রেশন চেকলিস্ট

স্বাস্থ্য পরিষেবার ExerciseClient ব্যবহার করে এমন আপনার অ্যাপ প্রকাশ করার আগে, আপনার ব্যবহারকারীর অভিজ্ঞতা কিছু সাধারণ সমস্যা এড়ায় তা নিশ্চিত করতে নিম্নলিখিত চেকলিস্টটি দেখুন। ওটা নিশ্চিত করুন:

  • প্রতিবার অ্যাপ চালানোর সময় আপনার অ্যাপ ব্যায়ামের ধরন এবং ডিভাইসের ক্ষমতা পরীক্ষা করে । এইভাবে, আপনি শনাক্ত করতে পারেন যখন একটি নির্দিষ্ট ডিভাইস বা ব্যায়াম আপনার অ্যাপের প্রয়োজনীয় ডেটা প্রকারগুলির একটিকে সমর্থন করে না।
  • আপনি প্রয়োজনীয় অনুমতিগুলির অনুরোধ এবং বজায় রাখুন এবং আপনার ম্যানিফেস্ট ফাইলে এগুলি নির্দিষ্ট করুন৷ prepareExerciseAsync() কল করার আগে, আপনার অ্যাপ নিশ্চিত করে যে রানটাইম অনুমতি দেওয়া হয়েছে।
  • আপনার অ্যাপ ব্যবহার করে getCurrentExerciseInfoAsync() কেসগুলি পরিচালনা করতে যেখানে :
    • একটি ব্যায়াম ইতিমধ্যেই ট্র্যাক করা হচ্ছে, এবং আপনার অ্যাপটি আগের অনুশীলনকে ওভাররাইড করে।
    • অন্য একটি অ্যাপ আপনার ব্যায়াম বন্ধ করে দিয়েছে। এটি ঘটতে পারে যখন ব্যবহারকারী অ্যাপটি পুনরায় খোলে, তাদের কাছে একটি বার্তার সাথে দেখা করা হয় যাতে ব্যাখ্যা করা হয় যে অনুশীলনটি বন্ধ হয়ে গেছে কারণ অন্য একটি অ্যাপ দখল করেছে।
  • আপনি যদি LOCATION ডেটা ব্যবহার করেন:
    • আপনার অ্যাপ অনুশীলনের পুরো সময়কাল (প্রস্তুত কল সহ) সংশ্লিষ্ট foregroundServiceType সহ একটি ForegroundService বজায় রাখে।
    • isProviderEnabled(LocationManager.GPS_PROVIDER) ব্যবহার করে ডিভাইসে GPS সক্ষম আছে কিনা পরীক্ষা করুন এবং প্রয়োজনে ব্যবহারকারীকে অবস্থান সেটিংস খুলতে অনুরোধ করে৷
    • ডিমান্ডিং ইউজ কেসগুলির জন্য, যেখানে কম লেটেন্সি সহ লোকেশন ডেটা প্রাপ্তি অত্যন্ত গুরুত্বপূর্ণ, ফিউজড লোকেশন প্রোভাইডার (এফএলপি) একীভূত করার এবং প্রাথমিক অবস্থান ফিক্স হিসাবে এর ডেটা ব্যবহার করার কথা বিবেচনা করুন৷ স্বাস্থ্য পরিষেবাগুলি থেকে যখন আরও স্থিতিশীল অবস্থানের তথ্য পাওয়া যায়, তখন FLP এর পরিবর্তে এটি ব্যবহার করুন৷
  • যদি আপনার অ্যাপের ডেটা আপলোডের প্রয়োজন হয়, তাহলে অনুশীলন শেষ না হওয়া পর্যন্ত ডেটা আপলোড করার জন্য যেকোনো নেটওয়ার্ক কল স্থগিত করা হয়। অন্যথায়, পুরো ব্যায়াম জুড়ে, আপনার অ্যাপ যেকোন প্রয়োজনীয় নেটওয়ার্ক কল কম করে।
{% শব্দার্থে %} {% endverbatim %} {% শব্দার্থে %} {% endverbatim %}