স্থিতিশীলতার সমস্যাগুলি ঠিক করুন

কর্মক্ষমতা সমস্যা সৃষ্টিকারী একটি অস্থির শ্রেণীর মুখোমুখি হলে, আপনার এটিকে স্থিতিশীল করা উচিত। এই নথিতে আপনি এটি করতে ব্যবহার করতে পারেন এমন কয়েকটি কৌশলের রূপরেখা দেয়।

শক্তিশালী স্কিপিং সক্ষম করুন

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

আরও তথ্যের জন্য শক্তিশালী স্কিপিং দেখুন।

ক্লাস অপরিবর্তনীয় করুন

আপনি একটি অস্থির শ্রেণীকে সম্পূর্ণ অপরিবর্তনীয় করার চেষ্টা করতে পারেন।

  • অপরিবর্তনীয় : এমন একটি টাইপ নির্দেশ করে যেখানে কোনো বৈশিষ্ট্যের মান সেই প্রকারের একটি উদাহরণ তৈরি হওয়ার পরে কখনই পরিবর্তিত হতে পারে না এবং সমস্ত পদ্ধতি রেফারেন্সিয়ালভাবে স্বচ্ছ।
    • নিশ্চিত করুন যে সমস্ত শ্রেণীর বৈশিষ্ট্যগুলি var পরিবর্তে val এবং অপরিবর্তনীয় প্রকারের।
    • আদিম প্রকারগুলি যেমন String, Int এবং Float সর্বদা অপরিবর্তনীয়।
    • যদি এটি অসম্ভব হয়, তাহলে আপনাকে অবশ্যই কোনো পরিবর্তনযোগ্য বৈশিষ্ট্যের জন্য রচনা অবস্থা ব্যবহার করতে হবে।
  • স্থিতিশীল : পরিবর্তনযোগ্য একটি প্রকার নির্দেশ করে। কম্পোজ রানটাইম সচেতন হয় না যদি এবং কখন কোন ধরনের পাবলিক প্রপার্টি বা পদ্ধতি আচরণ পূর্ববর্তী আহ্বান থেকে ভিন্ন ফলাফল দেয়।

অপরিবর্তনীয় সংগ্রহ

কম্পোজ একটি ক্লাসকে অস্থির মনে করার একটি সাধারণ কারণ হল সংগ্রহ। ডায়াগনেস স্থায়িত্ব সমস্যা পৃষ্ঠায় উল্লেখ করা হয়েছে, কম্পোজ কম্পাইলার সম্পূর্ণরূপে নিশ্চিত হতে পারে না যে List, Map এবং Set মতো সংগ্রহগুলি সত্যিই অপরিবর্তনীয় এবং তাই সেগুলিকে অস্থির হিসাবে চিহ্নিত করে৷

এটি সমাধান করতে, আপনি অপরিবর্তনীয় সংগ্রহ ব্যবহার করতে পারেন। কম্পোজ কম্পাইলার Kotlinx অপরিবর্তনীয় সংগ্রহের জন্য সমর্থন অন্তর্ভুক্ত করে। এই সংগ্রহগুলি অপরিবর্তনীয় হওয়ার গ্যারান্টিযুক্ত, এবং কম্পোজ কম্পাইলার সেগুলিকে এমনভাবে বিবেচনা করে। এই লাইব্রেরিটি এখনও আলফাতে রয়েছে, তাই এর API-তে সম্ভাব্য পরিবর্তনগুলি আশা করুন৷

নির্ণয় স্থিতিশীলতা সমস্যা নির্দেশিকা থেকে এই অস্থির শ্রেণীটি আবার বিবেচনা করুন:

unstable class Snack {
  …
  unstable val tags: Set<String>
  …
}

আপনি একটি অপরিবর্তনীয় সংগ্রহ ব্যবহার করে tags স্থিতিশীল করতে পারেন। ক্লাসে, tags ধরন পরিবর্তন করুন ImmutableSet<String> :

data class Snack{
    …
    val tags: ImmutableSet<String> = persistentSetOf()
    …
}

এটি করার পরে, ক্লাসের সমস্ত প্যারামিটার অপরিবর্তনীয়, এবং কম্পোজ কম্পাইলার ক্লাসটিকে স্থিতিশীল হিসাবে চিহ্নিত করে।

Stable বা Immutable সহ টীকা

স্থিতিশীলতার সমস্যাগুলি সমাধানের একটি সম্ভাব্য পথ হল অস্থির ক্লাসগুলি @Stable বা @Immutable এর সাথে টীকা করা।

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

যদি কোনো টীকা ছাড়াই আপনার শ্রেণীকে স্থিতিশীল করা সম্ভব হয়, তাহলে আপনার সেইভাবে স্থিতিশীলতা অর্জনের চেষ্টা করা উচিত।

নিম্নলিখিত স্নিপেটটি অপরিবর্তনীয় হিসাবে টীকাযুক্ত ডেটা ক্লাসের একটি ন্যূনতম উদাহরণ প্রদান করে:

@Immutable
data class Snack(
…
)

আপনি @Immutable বা @Stable টীকা ব্যবহার করুন না কেন, কম্পোজ কম্পাইলার Snack ক্লাসটিকে স্থিতিশীল হিসাবে চিহ্নিত করে।

সংগ্রহে টীকা ক্লাস

একটি কম্পোজেবল বিবেচনা করুন যা List<Snack> প্রকারের একটি প্যারামিটার অন্তর্ভুক্ত করে :

restartable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
  …
  unstable snacks: List<Snack>
  …
)

এমনকি যদি আপনি @Immutable এর সাথে Snack টীকা করেন, তবুও কম্পোজ কম্পাইলার HighlightedSnacks -এ snacks প্যারামিটারটিকে অস্থির হিসেবে চিহ্নিত করে।

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

আপনি একটি পৃথক প্যারামিটারকে স্থিতিশীল হিসাবে চিহ্নিত করতে পারবেন না, বা আপনি সর্বদা এড়িয়ে যাওয়ার জন্য একটি কম্পোজেবল টীকা করতে পারবেন না। সামনে একাধিক পথ আছে।

অস্থির সংগ্রহের সমস্যা থেকে আপনি পেতে পারেন বিভিন্ন উপায় আছে. নিম্নলিখিত উপধারাগুলি এই বিভিন্ন পদ্ধতির রূপরেখা দেয়।

কনফিগারেশন ফাইল

আপনি যদি আপনার কোডবেসে স্থিতিশীলতা চুক্তি মেনে চলতে খুশি হন, তাহলে আপনি আপনার স্থিতিশীলতা কনফিগারেশন ফাইলে kotlin.collections.* যোগ করে Kotlin সংগ্রহগুলিকে স্থিতিশীল হিসাবে বিবেচনা করতে বেছে নিতে পারেন।

অপরিবর্তনীয় সংগ্রহ

অপরিবর্তনীয়তার কম্পাইল সময় নিরাপত্তার জন্য, আপনি List এর পরিবর্তে একটি kotlinx অপরিবর্তনীয় সংগ্রহ ব্যবহার করতে পারেন।

@Composable
private fun HighlightedSnacks(
    …
    snacks: ImmutableList<Snack>,
    …
)

মোড়ক

আপনি যদি একটি অপরিবর্তনীয় সংগ্রহ ব্যবহার করতে না পারেন তবে আপনি নিজের তৈরি করতে পারেন। এটি করার জন্য, একটি টীকাযুক্ত স্থিতিশীল ক্লাসে List মোড়ানো। আপনার প্রয়োজনীয়তার উপর নির্ভর করে একটি জেনেরিক মোড়ক সম্ভবত এটির জন্য সেরা পছন্দ।

@Immutable
data class SnackCollection(
   val snacks: List<Snack>
)

তারপরে আপনি এটিকে আপনার কম্পোজেবলের প্যারামিটারের ধরণ হিসাবে ব্যবহার করতে পারেন।

@Composable
private fun HighlightedSnacks(
    index: Int,
    snacks: SnackCollection,
    onSnackClick: (Long) -> Unit,
    modifier: Modifier = Modifier
)

সমাধান

এই পদ্ধতির যেকোনো একটি গ্রহণ করার পর, কম্পোজ কম্পাইলার এখন HighlightedSnacks কম্পোজেবলকে skippable এবং restartable উভয় হিসাবে চিহ্নিত করে।

restartable skippable scheme("[androidx.compose.ui.UiComposable]") fun HighlightedSnacks(
  stable index: Int
  stable snacks: ImmutableList<Snack>
  stable onSnackClick: Function1<Long, Unit>
  stable modifier: Modifier? = @static Companion
)

পুনর্গঠনের সময়, কম্পোজ এখন HighlightedSnacks এড়িয়ে যেতে পারে যদি এর কোনো ইনপুট পরিবর্তিত না হয়।

স্থিতিশীলতা কনফিগারেশন ফাইল

কম্পোজ কম্পাইলার 1.5.5 দিয়ে শুরু করে, স্থিতিশীল বিবেচনা করার জন্য ক্লাসগুলির একটি কনফিগারেশন ফাইল কম্পাইলের সময় প্রদান করা যেতে পারে। এটি এমন ক্লাসগুলি বিবেচনা করার অনুমতি দেয় যা আপনি নিয়ন্ত্রণ করেন না, যেমন LocalDateTime এর মতো স্ট্যান্ডার্ড লাইব্রেরি ক্লাসগুলি স্থিতিশীল হিসাবে।

কনফিগারেশন ফাইলটি একটি প্লেইন টেক্সট ফাইল যার প্রতি সারিতে একটি ক্লাস রয়েছে। মন্তব্য, একক এবং ডবল ওয়াইল্ডকার্ড সমর্থিত। একটি উদাহরণ কনফিগারেশন:

// Consider LocalDateTime stable
java.time.LocalDateTime
// Consider my datalayer stable
com.datalayer.*
// Consider my datalayer and all submodules stable
com.datalayer.**
// Consider my generic type stable based off it's first type parameter only
com.example.GenericClass<*,_>

এই বৈশিষ্ট্যটি সক্ষম করতে, কম্পোজ কম্পাইলার গ্রেডল প্লাগইন কনফিগারেশনের composeCompiler অপশন ব্লকে কনফিগারেশন ফাইলের পাথ পাস করুন।

  composeCompiler {
    stabilityConfigurationFile = rootProject.layout.projectDirectory.file("stability_config.conf")
  }
```

As the Compose compiler runs on each module in your project separately, you can
provide different configurations to different modules if needed. Alternatively,
have one configuration at the root level of your project and pass that path to
each module.

## Multiple modules {:#multiple-modules}

Another common issue involves multi-module architecture. The Compose compiler
can only infer whether a class is stable if all of the non-primitive types that
it references are either explicitly marked as stable or in a module that was
also built with the Compose compiler.

If your data layer is in a separate module to your UI layer, which is the
recommended approach, this may be an issue you encounter.

### Solution {:#modules-solution}

To solve this issue you can take one of the following approaches:

1.  Add the classes to your [Compiler configuration file](#configuration-file).
1.  Enable the Compose compiler on your data layer modules, or tag your classes
    with `@Stable` or `@Immutable` where appropriate.
    -   This involves adding a Compose dependency to your data layer. However,
        it is just the dependency for the Compose runtime and not for
        `Compose-UI`.
1.  Within your UI module, wrap your data layer classes in UI-specific wrapper
    classes.

The same issue also occurs when using external libraries if they don't use the
Compose compiler.

## Not every composable should be skippable {:#not-composable}

When working to fix issues with stability, you shouldn't attempt to make every
composable skippable. Attempting to do so can lead to premature optimisation
that introduces more issues than it fixes.

There are many situations where being skippable doesn't have any real benefit
and can lead to hard to maintain code. For example:

-   A composable that is not recomposed often, or at all.
-   A composable that in itself just calls skippable composables.
-   A composable with a large number of parameters with expensive equals
    implementations. In this case, the cost of checking if any parameter has
    changed could outweigh the cost of a cheap recomposition.

When a composable is skippable it adds a small overhead which may not be worth
it. You can even annotate your composable to be [non-restartable][9] in cases
where you determine that being restartable is more overhead than it's worth.