লাইফসাইকেল-সচেতন কম্পোনেন্ট (ভিউ) ব্যবহার করে লাইফসাইকেল পরিচালনা করা

ধারণা এবং জেটপ্যাক কম্পোজ বাস্তবায়ন

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

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

androidx.lifecycle প্যাকেজটি এমন ক্লাস এবং ইন্টারফেস সরবরাহ করে যা আপনাকে লাইফসাইকেল-সচেতন কম্পোনেন্ট তৈরি করতে দেয়—অর্থাৎ এমন কম্পোনেন্ট যা কোনো অ্যাক্টিভিটি বা ফ্র্যাগমেন্টের বর্তমান লাইফসাইকেল অবস্থার উপর ভিত্তি করে স্বয়ংক্রিয়ভাবে তাদের আচরণ সামঞ্জস্য করতে পারে।

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

ধরুন, আমাদের এমন একটি অ্যাক্টিভিটি আছে যা স্ক্রিনে ডিভাইসের অবস্থান দেখায়। এর একটি সাধারণ বাস্তবায়ন নিচের মতো হতে পারে:

কোটলিন

internal class MyLocationListener(
        private val context: Context,
        private val callback: (Location) -> Unit
) {

    fun start() {
        // connect to system location service
    }

    fun stop() {
        // disconnect from system location service
    }
}

class MyActivity : AppCompatActivity() {
    private lateinit var myLocationListener: MyLocationListener

    override fun onCreate(...) {
        myLocationListener = MyLocationListener(this) { location ->
            // update UI
        }
    }

    public override fun onStart() {
        super.onStart()
        myLocationListener.start()
        // manage other components that need to respond
        // to the activity lifecycle
    }

    public override fun onStop() {
        super.onStop()
        myLocationListener.stop()
        // manage other components that need to respond
        // to the activity lifecycle
    }
}

জাভা

class MyLocationListener {
    public MyLocationListener(Context context, Callback callback) {
        // ...
    }

    void start() {
        // connect to system location service
    }

    void stop() {
        // disconnect from system location service
    }
}

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    @Override
    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, (location) -> {
            // update UI
        });
    }

    @Override
    public void onStart() {
        super.onStart();
        myLocationListener.start();
        // manage other components that need to respond
        // to the activity lifecycle
    }

    @Override
    public void onStop() {
        super.onStop();
        myLocationListener.stop();
        // manage other components that need to respond
        // to the activity lifecycle
    }
}

যদিও এই নমুনাটি দেখতে ঠিকঠাক মনে হচ্ছে, একটি বাস্তব অ্যাপে লাইফসাইকেলের বর্তমান অবস্থার প্রতিক্রিয়ায় UI এবং অন্যান্য কম্পোনেন্টগুলো পরিচালনা করার জন্য অনেক বেশি কল ব্যবহৃত হয়। একাধিক কম্পোনেন্ট পরিচালনা করার ফলে onStart() এবং onStop এর মতো লাইফসাইকেল মেথডগুলোতে প্রচুর পরিমাণে কোড জমা হয়, যা সেগুলোর রক্ষণাবেক্ষণকে কঠিন করে তোলে।

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

কোটলিন

class MyActivity : AppCompatActivity() {
    private lateinit var myLocationListener: MyLocationListener

    override fun onCreate(...) {
        myLocationListener = MyLocationListener(this) { location ->
            // update UI
        }
    }

    public override fun onStart() {
        super.onStart()
        Util.checkUserStatus { result ->
            // what if this callback is invoked AFTER activity is stopped?
            if (result) {
                myLocationListener.start()
            }
        }
    }

    public override fun onStop() {
        super.onStop()
        myLocationListener.stop()
    }

}

জাভা

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, location -> {
            // update UI
        });
    }

    @Override
    public void onStart() {
        super.onStart();
        Util.checkUserStatus(result -> {
            // what if this callback is invoked AFTER activity is stopped?
            if (result) {
                myLocationListener.start();
            }
        });
    }

    @Override
    public void onStop() {
        super.onStop();
        myLocationListener.stop();
    }
}

androidx.lifecycle প্যাকেজটি এমন ক্লাস ও ইন্টারফেস প্রদান করে যা আপনাকে এই সমস্যাগুলো একটি স্থিতিস্থাপক ও বিচ্ছিন্ন উপায়ে মোকাবেলা করতে সাহায্য করে।

জীবনচক্র

Lifecycle হলো এমন একটি ক্লাস যা কোনো কম্পোনেন্টের (যেমন অ্যাক্টিভিটি বা ফ্র্যাগমেন্ট) লাইফসাইকেল স্টেট সম্পর্কিত তথ্য ধারণ করে এবং অন্যান্য অবজেক্টকে এই স্টেট পর্যবেক্ষণ করার সুযোগ দেয়।

Lifecycle তার সংশ্লিষ্ট কম্পোনেন্টের লাইফসাইকেল স্ট্যাটাস ট্র্যাক করতে দুটি প্রধান এনুমারেশন ব্যবহার করে:

অনুষ্ঠান

ফ্রেমওয়ার্ক এবং Lifecycle ক্লাস থেকে যে লাইফসাইকেল ইভেন্টগুলো ডিসপ্যাচ করা হয়। এই ইভেন্টগুলো অ্যাক্টিভিটি এবং ফ্র্যাগমেন্টের কলব্যাক ইভেন্টগুলোর সাথে ম্যাপ করা থাকে।

রাজ্য

Lifecycle অবজেক্ট দ্বারা ট্র্যাক করা কম্পোনেন্টটির বর্তমান অবস্থা।

চিত্র ১. অ্যান্ড্রয়েড অ্যাক্টিভিটি লাইফসাইকেলের অবস্থা ও ঘটনাসমূহ।

রাজ্যগুলোকে একটি গ্রাফের নোড এবং ঘটনাগুলোকে এই নোডগুলোর মধ্যকার এজ হিসেবে ভাবুন।

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

কোটলিন

class MyObserver : DefaultLifecycleObserver {
    override fun onResume(owner: LifecycleOwner) {
        connect()
    }

    override fun onPause(owner: LifecycleOwner) {
        disconnect()
    }
}

myLifecycleOwner.getLifecycle().addObserver(MyObserver())

জাভা

public class MyObserver implements DefaultLifecycleObserver {
    @Override
    public void onResume(LifecycleOwner owner) {
        connect()
    }

    @Override
    public void onPause(LifecycleOwner owner) {
        disconnect()
    }
}

myLifecycleOwner.getLifecycle().addObserver(new MyObserver());

উপরের উদাহরণে, myLifecycleOwner অবজেক্টটি LifecycleOwner ইন্টারফেসটি ইমপ্লিমেন্ট করে, যা পরবর্তী বিভাগে ব্যাখ্যা করা হয়েছে।

লাইফসাইকেলওনার

LifecycleOwner হলো একটি একক মেথড ইন্টারফেস যা নির্দেশ করে যে ক্লাসটির একটি Lifecycle আছে। এর একটি মাত্র মেথড আছে, getLifecycle , যা ক্লাসটিকে অবশ্যই ইমপ্লিমেন্ট করতে হবে। এর পরিবর্তে আপনি যদি একটি সম্পূর্ণ অ্যাপ্লিকেশন প্রসেসের লাইফসাইকেল পরিচালনা করতে চান, তবে ProcessLifecycleOwner দেখুন।

এই ইন্টারফেসটি Fragment এবং AppCompatActivity মতো স্বতন্ত্র ক্লাসগুলো থেকে একটি Lifecycle মালিকানাকে আড়াল করে এবং সেগুলোর সাথে কাজ করার জন্য কম্পোনেন্ট লেখার সুযোগ দেয়। যেকোনো কাস্টম অ্যাপ্লিকেশন ক্লাস LifecycleOwner ইন্টারফেসটি ইমপ্লিমেন্ট করতে পারে।

যেসব কম্পোনেন্ট DefaultLifecycleObserver ইমপ্লিমেন্ট করে, সেগুলো LifecycleOwner ইমপ্লিমেন্টকারী কম্পোনেন্টগুলোর সাথে নির্বিঘ্নে কাজ করে, কারণ একজন ওনার একটি লাইফসাইকেল প্রদান করতে পারে, যা পর্যবেক্ষণ করার জন্য একজন অবজারভার রেজিস্টার করতে পারে।

লোকেশন ট্র্যাকিং উদাহরণের জন্য, আমরা MyLocationListener ক্লাসটিকে DefaultLifecycleObserver ইমপ্লিমেন্ট করাতে পারি এবং তারপর onCreate() মেথডে অ্যাক্টিভিটির Lifecycle দিয়ে এটিকে ইনিশিয়ালাইজ করতে পারি। এটি MyLocationListener ক্লাসটিকে স্বয়ংসম্পূর্ণ হতে সাহায্য করে, যার অর্থ হলো লাইফসাইকেল স্ট্যাটাসের পরিবর্তনে প্রতিক্রিয়া জানানোর লজিক অ্যাক্টিভিটির পরিবর্তে MyLocationListener এর মধ্যেই ডিক্লেয়ার করা থাকে। প্রতিটি কম্পোনেন্টের নিজস্ব লজিক সংরক্ষণ করার ফলে অ্যাক্টিভিটি এবং ফ্র্যাগমেন্টের লজিক পরিচালনা করা সহজ হয়ে যায়।

কোটলিন

class MyActivity : AppCompatActivity() {
    private lateinit var myLocationListener: MyLocationListener

    override fun onCreate(...) {
        myLocationListener = MyLocationListener(this, lifecycle) { location ->
            // update UI
        }
        Util.checkUserStatus { result ->
            if (result) {
                myLocationListener.enable()
            }
        }
    }
}

জাভা

class MyActivity extends AppCompatActivity {
    private MyLocationListener myLocationListener;

    public void onCreate(...) {
        myLocationListener = new MyLocationListener(this, getLifecycle(), location -> {
            // update UI
        });
        Util.checkUserStatus(result -> {
            if (result) {
                myLocationListener.enable();
            }
        });
  }
}

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

এই ব্যবহারের ক্ষেত্রটি সহজ করার জন্য, Lifecycle ক্লাসটি অন্যান্য অবজেক্টকে বর্তমান অবস্থা জিজ্ঞাসা করার অনুমতি দেয়।

কোটলিন

internal class MyLocationListener(
        private val context: Context,
        private val lifecycle: Lifecycle,
        private val callback: (Location) -> Unit
): DefaultLifecycleObserver {

    private var enabled = false

    override fun onStart(owner: LifecycleOwner) {
        if (enabled) {
            // connect
        }
    }

    fun enable() {
        enabled = true
        if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
            // connect if not connected
        }
    }

    override fun onStop(owner: LifecycleOwner) {
        // disconnect if connected
    }
}

জাভা

class MyLocationListener implements DefaultLifecycleObserver {
    private boolean enabled = false;
    public MyLocationListener(Context context, Lifecycle lifecycle, Callback callback) {
       ...
    }

    @Override
    public void onStart(LifecycleOwner owner) {
        if (enabled) {
           // connect
        }
    }

    public void enable() {
        enabled = true;
        if (lifecycle.getCurrentState().isAtLeast(STARTED)) {
            // connect if not connected
        }
    }

    @Override
    public void onStop(LifecycleOwner owner) {
        // disconnect if connected
    }
}

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

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

একটি কাস্টম লাইফসাইকেলওনার বাস্তবায়ন করা

সাপোর্ট লাইব্রেরি ২৬.১.০ এবং পরবর্তী সংস্করণগুলিতে ফ্র্যাগমেন্ট ও অ্যাক্টিভিটিগুলো ইতিমধ্যেই LifecycleOwner ইন্টারফেসটি প্রয়োগ করে।

আপনার যদি কোনো কাস্টম ক্লাস থাকে যাকে আপনি LifecycleOwner বানাতে চান, তাহলে আপনি LifecycleRegistry ক্লাসটি ব্যবহার করতে পারেন, কিন্তু আপনাকে সেই ক্লাসে ইভেন্টগুলো ফরওয়ার্ড করতে হবে, যেমনটি নিম্নলিখিত কোড উদাহরণে দেখানো হয়েছে:

কোটলিন

class MyActivity : Activity(), LifecycleOwner {

    private lateinit var lifecycleRegistry: LifecycleRegistry

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        lifecycleRegistry = LifecycleRegistry(this)
        lifecycleRegistry.markState(Lifecycle.State.CREATED)
    }

    public override fun onStart() {
        super.onStart()
        lifecycleRegistry.markState(Lifecycle.State.STARTED)
    }

    override fun getLifecycle(): Lifecycle {
        return lifecycleRegistry
    }
}

জাভা

public class MyActivity extends Activity implements LifecycleOwner {
    private LifecycleRegistry lifecycleRegistry;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        lifecycleRegistry = new LifecycleRegistry(this);
        lifecycleRegistry.markState(Lifecycle.State.CREATED);
    }

    @Override
    public void onStart() {
        super.onStart();
        lifecycleRegistry.markState(Lifecycle.State.STARTED);
    }

    @NonNull
    @Override
    public Lifecycle getLifecycle() {
        return lifecycleRegistry;
    }
}

লাইফসাইকেল-সচেতন উপাদানগুলির জন্য সর্বোত্তম অনুশীলন

  • আপনার UI কন্ট্রোলারগুলোকে (অ্যাক্টিভিটি এবং ফ্র্যাগমেন্ট) যথাসম্ভব হালকা রাখুন। এগুলোর নিজেরা ডেটা সংগ্রহ করার চেষ্টা করা উচিত নয়; এর পরিবর্তে, একটি ViewModel ব্যবহার করুন এবং ভিউগুলোতে পরিবর্তনগুলো প্রতিফলিত করার জন্য একটি LiveData অবজেক্ট পর্যবেক্ষণ করুন।
  • ডেটা-চালিত UI লেখার চেষ্টা করুন, যেখানে আপনার UI কন্ট্রোলারের দায়িত্ব হলো ডেটা পরিবর্তনের সাথে সাথে ভিউগুলো আপডেট করা, অথবা ব্যবহারকারীর কার্যকলাপ সম্পর্কে ViewModel কে অবহিত করা।
  • আপনার ডেটা লজিক ViewModel ক্লাসে রাখুন। ViewModel আপনার UI কন্ট্রোলার এবং অ্যাপের বাকি অংশের মধ্যে সংযোগকারী হিসেবে কাজ করবে। তবে সতর্ক থাকবেন, ডেটা আনা (যেমন, নেটওয়ার্ক থেকে) ViewModel এর দায়িত্ব নয়। এর পরিবর্তে, ViewModel ডেটা আনার জন্য উপযুক্ত কম্পোনেন্টকে কল করবে এবং তারপর ফলাফলটি UI কন্ট্রোলারে ফেরত পাঠাবে।
  • আপনার ভিউ এবং UI কন্ট্রোলারের মধ্যে একটি পরিচ্ছন্ন ইন্টারফেস বজায় রাখতে ডেটা বাইন্ডিং ব্যবহার করুন। এটি আপনার ভিউগুলোকে আরও ডিক্লারেটিভ করে তোলে এবং আপনার অ্যাক্টিভিটি ও ফ্র্যাগমেন্টে প্রয়োজনীয় আপডেট কোডের পরিমাণ কমিয়ে আনে। আপনি যদি জাভা প্রোগ্রামিং ভাষায় এটি করতে পছন্দ করেন, তবে বয়লারপ্লেট কোড এড়াতে এবং আরও ভালো অ্যাবস্ট্রাকশন পেতে বাটার নাইফের মতো একটি লাইব্রেরি ব্যবহার করুন।
  • আপনার UI জটিল হলে, UI পরিবর্তনগুলো পরিচালনা করার জন্য একটি প্রেজেন্টার ক্লাস তৈরি করার কথা ভাবতে পারেন। এটি একটি শ্রমসাধ্য কাজ হতে পারে, কিন্তু এর ফলে আপনার UI কম্পোনেন্টগুলো পরীক্ষা করা সহজ হয়ে যাবে।
  • আপনার ViewModel এ কোনো View বা Activity কনটেক্সট রেফারেন্স করা থেকে বিরত থাকুন। যদি কনফিগারেশন পরিবর্তনের কারণে ViewModel Activity-র চেয়ে বেশি সময় ধরে চালু থাকে, তাহলে আপনার Activity-র মেমরি লিক হয় এবং গার্বেজ কালেক্টর দ্বারা তা সঠিকভাবে ডিসপোজ হয় না।
  • দীর্ঘ সময় ধরে চলা কাজ এবং অন্যান্য অ্যাসিঙ্ক্রোনাসভাবে চলতে পারে এমন অপারেশনগুলো পরিচালনা করতে কোটলিন কো-রুটিন ব্যবহার করুন।

জীবনচক্র-সচেতন উপাদানগুলির ব্যবহারের ক্ষেত্র

লাইফসাইকেল-সচেতন কম্পোনেন্টগুলো বিভিন্ন ক্ষেত্রে আপনার জন্য লাইফসাইকেল পরিচালনা করা অনেক সহজ করে তুলতে পারে। এর কয়েকটি উদাহরণ হলো:

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

স্টপ ইভেন্ট পরিচালনা

যখন কোনো Lifecycle একটি AppCompatActivity বা Fragment অন্তর্গত হয়, তখন উক্ত AppCompatActivity বা Fragment এর onSaveInstanceState() কল করা হলে Lifecycle স্টেট CREATED এ পরিবর্তিত হয় এবং ON_STOP ইভেন্টটি ডিসপ্যাচ করা হয়।

যখন onSaveInstanceState ব্যবহার করে কোনো Fragment বা AppCompatActivity এর স্টেট সেভ করা হয়, তখন ON_START কল না করা পর্যন্ত এর UI অপরিবর্তনীয় (immutable) বলে গণ্য করা হয়। স্টেট সেভ করার পর UI পরিবর্তন করার চেষ্টা করলে আপনার অ্যাপ্লিকেশনের নেভিগেশন স্টেটে অসামঞ্জস্য দেখা দেওয়ার সম্ভাবনা থাকে, যে কারণে স্টেট সেভ করার পর অ্যাপটি কোনো FragmentTransaction চালালে FragmentManager একটি এক্সেপশন (exception) থ্রো করে। বিস্তারিত জানতে commit() দেখুন।

LiveData স্বয়ংক্রিয়ভাবে এই বিশেষ পরিস্থিতিটি প্রতিরোধ করে, যদি অবজারভারের সংশ্লিষ্ট Lifecycle অন্তত STARTED না হয়, তবে এটি তার অবজারভারকে কল করা থেকে বিরত থাকে। নেপথ্যে, এটি তার অবজারভারকে আহ্বান করার সিদ্ধান্ত নেওয়ার আগে isAtLeast() কল করে।

দুর্ভাগ্যবশত, AppCompatActivity এর onStop() মেথডটি onSaveInstanceState পরে কল করা হয়, যার ফলে একটি ফাঁক তৈরি হয় যেখানে UI স্টেটের পরিবর্তন অনুমোদিত নয়, কিন্তু Lifecycle তখনও CREATED স্টেটে স্থানান্তরিত হয়নি।

এই সমস্যাটি এড়ানোর জন্য, beta2 এবং তার পূর্ববর্তী সংস্করণগুলিতে Lifecycle ক্লাস ইভেন্ট ডিসপ্যাচ না করেই স্টেটকে CREATED হিসেবে চিহ্নিত করে, যাতে সিস্টেম দ্বারা onStop() কল না হওয়া পর্যন্ত ইভেন্টটি ডিসপ্যাচ না হলেও, বর্তমান স্টেট পরীক্ষা করে এমন যেকোনো কোড আসল মানটি পেয়ে যায়।

দুর্ভাগ্যবশত, এই সমাধানটির দুটি প্রধান সমস্যা রয়েছে:

  • এপিআই লেভেল ২৩ এবং তার নিচের সংস্করণগুলোতে, অ্যান্ড্রয়েড সিস্টেম একটি অ্যাক্টিভিটির স্টেট সংরক্ষণ করে রাখে, এমনকি যদি সেটি অন্য কোনো অ্যাক্টিভিটি দ্বারা আংশিকভাবে আবৃতও থাকে। অন্য কথায়, অ্যান্ড্রয়েড সিস্টেম onSaveInstanceState() কল করলেও, এটি onStop কল নাও করতে পারে। এর ফলে একটি সম্ভাব্য দীর্ঘ বিরতি তৈরি হয়, যেখানে অবজারভার তখনও মনে করে যে লাইফসাইকেলটি সক্রিয় আছে, যদিও এর UI স্টেট পরিবর্তন করা যায় না।
  • যে কোনো ক্লাস যা LiveData ক্লাসের অনুরূপ আচরণ প্রকাশ করতে চায়, তাকে Lifecycle সংস্করণ beta 2 এবং তার নিম্নতর সংস্করণে প্রদত্ত সমাধানটি প্রয়োগ করতে হবে।

অতিরিক্ত সম্পদ

লাইফসাইকেল-অ্যাওয়ার কম্পোনেন্ট ব্যবহার করে লাইফসাইকেল পরিচালনা সম্পর্কে আরও জানতে, নিম্নলিখিত অতিরিক্ত রিসোর্সগুলো দেখুন।

নমুনা

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

কোডল্যাবস

ব্লগ