কম্পোজেবলের জীবনচক্র

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

জীবনচক্রের ওভারভিউ

Managing state documentation -এ উল্লেখ করা হয়েছে, একটি Composition আপনার অ্যাপের UI বর্ণনা করে এবং composables চালানোর মাধ্যমে তৈরি করা হয়। একটি Composition হল composables এর একটি ট্রি-স্ট্রাকচার যা আপনার UI বর্ণনা করে।

যখন Jetpack Compose প্রথমবারের মতো আপনার composables চালায়, তখন প্রাথমিক composition এর সময়, এটি আপনার UI বর্ণনা করার জন্য আপনি যে composables কল করেন তার ট্র্যাক রাখবে। তারপর, যখন আপনার অ্যাপের অবস্থা পরিবর্তন হয়, তখন Jetpack Compose একটি recomposition নির্ধারণ করে। Recomposition হল যখন Jetpack Compose state পরিবর্তনের প্রতিক্রিয়ায় পরিবর্তিত composables পুনরায় কার্যকর করে এবং তারপর যেকোনো পরিবর্তন প্রতিফলিত করার জন্য Composition আপডেট করে।

একটি রচনা শুধুমাত্র একটি প্রাথমিক রচনা দ্বারা তৈরি করা যেতে পারে এবং পুনর্গঠনের মাধ্যমে আপডেট করা যেতে পারে। একটি রচনা সংশোধন করার একমাত্র উপায় হল পুনর্গঠনের মাধ্যমে।

একটি কম্পোজেবলের জীবনচক্র দেখানো চিত্র
চিত্র ১. রচনায় একটি যৌগের জীবনচক্র। এটি রচনায় প্রবেশ করে, ০ বা তার বেশি বার পুনর্গঠিত হয় এবং রচনা থেকে বেরিয়ে যায়।

রিকম্পোজিশন সাধারণত State<T> অবজেক্টে পরিবর্তনের মাধ্যমে শুরু হয়। Compose এগুলো ট্র্যাক করে এবং Composition-এর সমস্ত composables চালায় যা সেই নির্দিষ্ট State<T> পড়ে, এবং যে কোনও composables যা তারা বলে তা বাদ দেওয়া যাবে না।

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

@Composable
fun MyComposable() {
    Column {
        Text("Hello")
        Text("World")
    }
}

পূর্ববর্তী কোড স্নিপেটের উপাদানগুলির শ্রেণিবদ্ধ বিন্যাস দেখানো চিত্র
চিত্র ২. কম্পোজিশনে MyComposable এর প্রতিনিধিত্ব। যদি একটি কম্পোজিশনকে একাধিকবার ডাকা হয়, তাহলে কম্পোজিশনে একাধিক উদাহরণ স্থাপন করা হয়। একটি ভিন্ন রঙের উপাদান নির্দেশ করে যে এটি একটি পৃথক উদাহরণ।

রচনায় একটি কম্পোজেবলের অ্যানাটমি

কম্পোজিশনে কম্পোজেবলের উদাহরণ তার কল সাইট দ্বারা চিহ্নিত করা হয়। কম্পোজিশন কম্পাইলার প্রতিটি কল সাইটকে স্বতন্ত্র হিসেবে বিবেচনা করে। একাধিক কল সাইট থেকে কম্পোজেবল কল করলে কম্পোজিশনে কম্পোজেবলের একাধিক উদাহরণ তৈরি হবে।

যদি রিকম্পোজিশনের সময় কোন কম্পোজেবল আগের কম্পোজিশনের চেয়ে ভিন্ন কম্পোজিশবল কল করে, তাহলে Compose কোন কম্পোজিশবল কল করা হয়েছিল বা কল করা হয়নি তা সনাক্ত করবে এবং উভয় কম্পোজিশনে কল করা কম্পোজিশবলের ক্ষেত্রে, Compose যদি তাদের ইনপুট পরিবর্তন না করে থাকে তবে সেগুলি পুনরায় কম্পোজ করা এড়িয়ে চলবে

পার্শ্বপ্রতিক্রিয়াগুলিকে তাদের কম্পোজেবলের সাথে সংযুক্ত করার জন্য পরিচয় সংরক্ষণ করা অত্যন্ত গুরুত্বপূর্ণ, যাতে প্রতিটি পুনর্গঠনের জন্য পুনরায় শুরু করার পরিবর্তে তারা সফলভাবে সম্পূর্ণ করতে পারে।

নিম্নলিখিত উদাহরণটি বিবেচনা করুন:

@Composable
fun LoginScreen(showError: Boolean) {
    if (showError) {
        LoginError()
    }
    LoginInput() // This call site affects where LoginInput is placed in Composition
}

@Composable
fun LoginInput() { /* ... */ }

@Composable
fun LoginError() { /* ... */ }

উপরের কোড স্নিপেটে, LoginScreen শর্তসাপেক্ষে LoginError composable বলবে এবং সর্বদা LoginInput composable বলবে। প্রতিটি কলের একটি অনন্য কল সাইট এবং সোর্স পজিশন থাকবে, যা কম্পাইলার অনন্যভাবে সনাক্ত করতে ব্যবহার করবে।

showError ফ্ল্যাগটি সত্যে পরিবর্তন করা হলে পূর্ববর্তী কোডটি কীভাবে পুনরায় কম্পোজ করা হবে তা চিত্রে দেখানো হয়েছে। LoginError কম্পোজেবল যোগ করা হয়েছে, কিন্তু অন্যান্য কম্পোজেবলগুলি পুনরায় কম্পোজ করা হয়নি।
চিত্র ৩. যখন অবস্থা পরিবর্তন হয় এবং পুনর্গঠন ঘটে তখন রচনায় LoginScreen এর প্রতিনিধিত্ব। একই রঙের অর্থ হল এটি পুনর্গঠিত হয়নি।

যদিও LoginInput প্রথম কল থেকে দ্বিতীয় কলে রূপান্তরিত হয়েছে, LoginInput ইনস্ট্যান্সটি রিকম্পোজিশন জুড়ে সংরক্ষিত থাকবে। উপরন্তু, যেহেতু LoginInput কোনও প্যারামিটার নেই যা রিকম্পোজিশন জুড়ে পরিবর্তিত হয়েছে, তাই Compose দ্বারা LoginInput এ কল এড়িয়ে যাবে।

স্মার্ট রিকম্পোজিশনে সাহায্য করার জন্য অতিরিক্ত তথ্য যোগ করুন

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

@Composable
fun MoviesScreen(movies: List<Movie>) {
    Column {
        for (movie in movies) {
            // MovieOverview composables are placed in Composition given its
            // index position in the for loop
            MovieOverview(movie)
        }
    }
}

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

তালিকার নীচে একটি নতুন উপাদান যোগ করা হলে পূর্ববর্তী কোডটি কীভাবে পুনর্গঠিত হবে তা দেখানো চিত্র। তালিকার অন্যান্য আইটেমগুলির অবস্থান পরিবর্তন হয়নি এবং পুনর্গঠিত হয়নি।
চিত্র ৪. তালিকার নীচে একটি নতুন উপাদান যোগ করা হলে কম্পোজিশনে MoviesScreen প্রতিনিধিত্ব। কম্পোজিশনে MovieOverview কম্পোজেবলগুলি পুনরায় ব্যবহার করা যেতে পারে। MovieOverview একই রঙের অর্থ হল কম্পোজেবলটি পুনরায় কম্পোজ করা হয়নি।

তবে, যদি তালিকার উপরে বা মাঝখানে কিছু যোগ করে, আইটেমগুলি সরিয়ে বা পুনঃক্রম করে movies তালিকা পরিবর্তন করা হয়, তাহলে এটি সমস্ত MovieOverview কলগুলিতে একটি পুনর্গঠন ঘটাবে যার ইনপুট প্যারামিটার তালিকার অবস্থান পরিবর্তন করেছে। উদাহরণস্বরূপ, MovieOverview যদি পার্শ্ব প্রতিক্রিয়া ব্যবহার করে একটি সিনেমার ছবি আনে তবে এটি অত্যন্ত গুরুত্বপূর্ণ। যদি প্রভাবটি চলাকালীন পুনর্গঠন ঘটে, তবে এটি বাতিল করা হবে এবং আবার শুরু হবে।

@Composable
fun MovieOverview(movie: Movie) {
    Column {
        // Side effect explained later in the docs. If MovieOverview
        // recomposes, while fetching the image is in progress,
        // it is cancelled and restarted.
        val image = loadNetworkImage(movie.url)
        MovieHeader(image)

        /* ... */
    }
}

তালিকার শীর্ষে একটি নতুন উপাদান যোগ করা হলে পূর্ববর্তী কোডটি কীভাবে পুনরায় তৈরি করা হয় তা দেখানো চিত্র। তালিকার অন্যান্য প্রতিটি আইটেমের অবস্থান পরিবর্তন হয় এবং পুনরায় তৈরি করতে হয়।
চিত্র ৫. তালিকায় একটি নতুন উপাদান যোগ করা হলে কম্পোজিশনে MoviesScreen প্রতিনিধিত্ব। MovieOverview কম্পোজেবলগুলি পুনরায় ব্যবহার করা যাবে না এবং সমস্ত পার্শ্ব প্রতিক্রিয়া পুনরায় শুরু হবে। MovieOverview একটি ভিন্ন রঙের অর্থ হল কম্পোজেবলটি পুনরায় কম্পোজ করা হয়েছে।

আদর্শভাবে, আমরা MovieOverview ইনস্ট্যান্সের পরিচয়টিকে movie পরিচয়ের সাথে যুক্ত হিসাবে ভাবতে চাই যা এটিতে প্রেরণ করা হয়। যদি আমরা মুভিগুলির তালিকা পুনর্বিন্যাস করি, তাহলে আদর্শভাবে আমরা প্রতিটি MovieOverview কম্পোজেবলকে একটি ভিন্ন মুভি ইনস্ট্যান্স দিয়ে পুনরায় কম্পোজ করার পরিবর্তে কম্পোজিশন ট্রিতে ইনস্ট্যান্সগুলিকে একইভাবে পুনর্বিন্যাস করব। কম্পোজ আপনাকে রানটাইমকে বলার একটি উপায় প্রদান করে যে আপনি গাছের একটি নির্দিষ্ট অংশ সনাক্ত করতে কোন মান ব্যবহার করতে চান: key কম্পোজেবল।

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

@Composable
fun MoviesScreenWithKey(movies: List<Movie>) {
    Column {
        for (movie in movies) {
            key(movie.id) { // Unique ID for this movie
                MovieOverview(movie)
            }
        }
    }
}

উপরের বিষয়গুলির সাথে, তালিকার উপাদানগুলি পরিবর্তিত হলেও, কম্পোজ MovieOverview পৃথক কলগুলি সনাক্ত করে এবং সেগুলি পুনরায় ব্যবহার করতে পারে।

তালিকার শীর্ষে একটি নতুন উপাদান যোগ করা হলে পূর্ববর্তী কোডটি কীভাবে পুনরায় কম্পোজ করা হয় তা দেখানো চিত্র। যেহেতু তালিকার আইটেমগুলি কী দ্বারা চিহ্নিত করা হয়, কম্পোজ জানে যে তাদের অবস্থান পরিবর্তিত হলেও সেগুলি পুনরায় কম্পোজ করতে হবে না।
চিত্র ৬. তালিকায় একটি নতুন উপাদান যোগ করা হলে কম্পোজিশনে MoviesScreen প্রতিনিধিত্ব। যেহেতু MovieOverview কম্পোজেবলগুলিতে অনন্য কী থাকে, তাই কম্পোজ কোন MovieOverview ইনস্ট্যান্সগুলি পরিবর্তিত হয়নি তা সনাক্ত করে এবং সেগুলি পুনরায় ব্যবহার করতে পারে; তাদের পার্শ্ব প্রতিক্রিয়াগুলি কার্যকর হতে থাকবে।

কিছু কম্পোজেবলে কম্পোজেবল key -এর জন্য অন্তর্নির্মিত সমর্থন থাকে। উদাহরণস্বরূপ, LazyColumn DSL items একটি কাস্টম key নির্দিষ্ট করার অনুমতি দেয়।

@Composable
fun MoviesScreenLazy(movies: List<Movie>) {
    LazyColumn {
        items(movies, key = { movie -> movie.id }) { movie ->
            MovieOverview(movie)
        }
    }
}

ইনপুট পরিবর্তন না হলে এড়িয়ে যাওয়া হচ্ছে

পুনর্গঠনের সময়, কিছু যোগ্য কম্পোজেবল ফাংশনের ইনপুট পূর্ববর্তী কম্পোজিশন থেকে পরিবর্তিত না হলে তাদের এক্সিকিউশন সম্পূর্ণরূপে বাদ দেওয়া যেতে পারে।

একটি কম্পোজেবল ফাংশন স্কিপ করার জন্য যোগ্য , যদি না :

  • ফাংশনটির একটি নন- Unit রিটার্ন টাইপ আছে
  • ফাংশনটি @NonRestartableComposable অথবা @NonSkippableComposable দিয়ে টীকাযুক্ত।
  • একটি প্রয়োজনীয় প্যারামিটার একটি অস্থির ধরণের

একটি পরীক্ষামূলক কম্পাইলার মোড আছে, স্ট্রং স্কিপিং , যা শেষ প্রয়োজনীয়তাটি শিথিল করে।

কোনও প্রকারকে স্থিতিশীল হিসেবে বিবেচনা করার জন্য এটিকে নিম্নলিখিত চুক্তি মেনে চলতে হবে:

  • দুটি উদাহরণের জন্য equals ফলাফল চিরকাল একই দুটি উদাহরণের জন্য একই থাকবে।
  • যদি এই ধরণের কোন পাবলিক সম্পত্তি পরিবর্তন হয়, তাহলে কম্পোজিশন সম্পর্কে অবহিত করা হবে।
  • সকল ধরণের সরকারি সম্পত্তিও স্থিতিশীল।

এই চুক্তির মধ্যে কিছু গুরুত্বপূর্ণ সাধারণ প্রকার রয়েছে যেগুলিকে কম্পোজ কম্পাইলার স্থিতিশীল হিসাবে বিবেচনা করবে, যদিও @Stable অ্যানোটেশন ব্যবহার করে স্পষ্টভাবে স্থিতিশীল হিসাবে চিহ্নিত করা হয়নি:

  • সকল আদিম মানের ধরণ: Boolean , Int , Long , Float , Char , ইত্যাদি।
  • স্ট্রিং
  • সকল ধরণের ফাংশন (ল্যাম্বডাস)

এই সকল প্রকারের স্থায়িত্ব চুক্তি অনুসরণ করতে সক্ষম কারণ তারা অপরিবর্তনীয়। যেহেতু অপরিবর্তনীয় প্রকারগুলি কখনও পরিবর্তিত হয় না, তাই তাদের কখনই পরিবর্তনের গঠন সম্পর্কে অবহিত করতে হয় না, তাই এই চুক্তি অনুসরণ করা অনেক সহজ।

একটি উল্লেখযোগ্য ধরণ যা স্থিতিশীল কিন্তু পরিবর্তনযোগ্য তা হল Compose এর MutableState ধরণ। যদি একটি মান MutableState এ রাখা হয়, তাহলে সামগ্রিকভাবে state অবজেক্টটি স্থিতিশীল বলে বিবেচিত হবে কারণ State এর .value সম্পত্তিতে যেকোনো পরিবর্তন সম্পর্কে Compose কে অবহিত করা হবে।

যখন কম্পোজেবলে প্যারামিটার হিসেবে পাস করা সকল প্রকার স্থিতিশীল থাকে, তখন UI ট্রিতে কম্পোজেবল অবস্থানের উপর ভিত্তি করে প্যারামিটার মানগুলি সমতার জন্য তুলনা করা হয়। পূর্ববর্তী কল থেকে সমস্ত মান অপরিবর্তিত থাকলে পুনর্গঠন বাদ দেওয়া হয়।

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

যদি Compose অনুমান করতে না পারে যে কোনও টাইপ স্থিতিশীল, কিন্তু আপনি Compose কে এটিকে স্থিতিশীল হিসাবে বিবেচনা করতে বাধ্য করতে চান, তাহলে @Stable টীকা দিয়ে এটি চিহ্নিত করুন।

// Marking the type as stable to favor skipping and smart recompositions.
@Stable
interface UiState<T : Result<T>> {
    val value: T?
    val exception: Throwable?

    val hasError: Boolean
        get() = exception != null
}

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

{% অক্ষরে অক্ষরে %} {% এন্ডভারব্যাটিম %} {% অক্ষরে অক্ষরে %} {% এন্ডভারব্যাটিম %}