LiveData এক নজরে   Android Jetpack-এর অংশ।

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

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

আপনি এমন একটি অবজেক্টের সাথে পেয়ার করা অবজারভার রেজিস্টার করতে পারবেন যা LifecycleOwner ইন্টারফেস প্রয়োগ করে। এই সম্পর্ক, সংশ্লিষ্ট Lifecycle অবজেক্টের স্ট্যাটাস DESTROYED-এ পরিবর্তিত হলে, পর্যবেক্ষককে সরানোর অনুমতি দেয়। এটি অ্যাক্টিভিটি ও ফ্র্যাগমেন্টের জন্য বিশেষভাবে উপযোগী কারণ এগুলি নিরাপদে LiveData অবজেক্ট পর্যবেক্ষণ করতে পারে এবং লিক হওয়ার ব্যাপারে চিন্তা করতে হয় না—অ্যাক্টিভিটি ও ফ্র্যাগমেন্টের লাইফসাইকেল নষ্ট হয়ে গেলে সেগুলি সাথে সাথে আনসাবস্ক্রাইব হয়ে যায়।

LiveData কীভাবে ব্যবহার করতে হয় সেই সম্পর্কে আরও তথ্য পেতে, LiveData অবজেক্টের সাথে কাজ করা দেখুন।

LiveData ব্যবহার করার সুবিধা

LiveData ব্যবহার করলে নিম্নলিখিত সুবিধাগুলি পাওয়া যায়:

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

LiveData অবজেক্ট নিয়ে কাজ করা

LiveData অবজেক্ট নিয়ে কাজ করতে এইসব ধাপ অনুসরণ করুন:

  1. নির্দিষ্ট ধরনের ডেটা ধরে রাখতে LiveData-এর একটি ইনস্ট্যান্স তৈরি করুন। এটি সাধারণত আপনার ViewModel ক্লাসের মধ্যে করা হয়।
  2. একটি Observer অবজেক্ট তৈরি করুন যা onChanged() পদ্ধতিকে সংজ্ঞায়িত করে, যা LiveData অবজেক্টের হোল্ড করা ডেটা পরিবর্তিত হলে কী ঘটবে তা নিয়ন্ত্রণ করে। আপনি সাধারণত UI কন্ট্রোলারে Observer অবজেক্ট তৈরি করেন, যেমন অ্যাক্টিভিটি বা ফ্র্যাগমেন্ট।
  3. observe() পদ্ধতি ব্যবহার করে LiveData অবজেক্টের সাথে Observer অবজেক্ট অ্যাটাচ করুন। observe() পদ্ধতিতে একটি LifecycleOwner অবজেক্ট লাগে। এটি Observer অবজেক্টকে LiveData অবজেক্টে সাবস্ক্রাইব করে যাতে এটি পরিবর্তনের বিজ্ঞপ্তি পায়। আপনি সাধারণত Observer অবজেক্টকে UI কন্ট্রোলারে অ্যাটাচ করেন, যেমন অ্যাক্টিভিটি বা ফ্র্যাগমেন্ট।

আপনি LiveData অবজেক্টে স্টোর করা ভ্যালু আপডেট করলে, এটি সব রেজিস্টার করা অবজারভারকে ট্রিগার করে, যতক্ষণ না অ্যাটাচ করা LifecycleOwner অ্যাক্টিভ অবস্থায় থাকে।

LiveData, UI কন্ট্রোলার অবজারভারদের আপডেট সাবস্ক্রাইব করার অনুমতি দেয়। LiveData অবজেক্টের ডেটা পরিবর্তন হলে, UI অটোমেটিক আপডেট হয়ে যায়।

LiveData অবজেক্ট তৈরি করুন

LiveData হল একটি র‍্যাপার যা যেকোনও ডেটার সাথে ব্যবহার করা যেতে পারে, যার মধ্যে Collections প্রয়োগ করে এমন অবজেক্টও অন্তর্ভুক্ত, যেমন List। LiveData অবজেক্ট সাধারণত ViewModel অবজেক্টের মধ্যে স্টোর করা হয় এবং গেটার পদ্ধতির মাধ্যমে অ্যাক্সেস করা হয়, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

Kotlin

class NameViewModel : ViewModel() {

    // Create a LiveData with a String
    val currentName: MutableLiveData<String> by lazy {
        MutableLiveData<String>()
    }

    // Rest of the ViewModel...
}

জাভা

public class NameViewModel extends ViewModel {

    // Create a LiveData with a String
    private MutableLiveData<String> currentName;

    public MutableLiveData<String> getCurrentName() {
        if (currentName == null) {
            currentName = new MutableLiveData<String>();
        }
        return currentName;
    }

    // Rest of the ViewModel...
}

প্রাথমিকভাবে, LiveData অবজেক্টে ডেটা সেট করা থাকে না।

আপনি ViewModel নির্দেশিকা থেকে ViewModel ক্লাসের সুবিধা ও ব্যবহার সম্পর্কে আরও জানতে পারবেন।

LiveData অবজেক্ট পর্যবেক্ষণ করুন

বেশিরভাগ ক্ষেত্রে, নিম্নলিখিত কারণে LiveData অবজেক্ট পর্যবেক্ষণ শুরু করার জন্য অ্যাপ কম্পোনেন্টের onCreate() পদ্ধতি হল সঠিক জায়গা:

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

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

নিচের স্যাম্পেল কোড থেকে বোঝা যাবে যে কীভাবে LiveData অবজেক্ট পর্যবেক্ষণ করা শুরু করতে হয়:

Kotlin

class NameActivity : AppCompatActivity() {

    // Use the 'by viewModels()' Kotlin property delegate
    // from the activity-ktx artifact
    private val model: NameViewModel by viewModels()

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

        // Other code to setup the activity...

        // Create the observer which updates the UI.
        val nameObserver = Observer<String> { newName ->
            // Update the UI, in this case, a TextView.
            nameTextView.text = newName
        }

        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        model.currentName.observe(this, nameObserver)
    }
}

জাভা

public class NameActivity extends AppCompatActivity {

    private NameViewModel model;

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

        // Other code to setup the activity...

        // Get the ViewModel.
        model = new ViewModelProvider(this).get(NameViewModel.class);

        // Create the observer which updates the UI.
        final Observer<String> nameObserver = new Observer<String>() {
            @Override
            public void onChanged(@Nullable final String newName) {
                // Update the UI, in this case, a TextView.
                nameTextView.setText(newName);
            }
        };

        // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
        model.getCurrentName().observe(this, nameObserver);
    }
}

nameObserver-কে প্যারামিটার হিসেবে পাস করে observe() কল করার পরে, mCurrentName-এ স্টোর করা সবচেয়ে সাম্প্রতিক ভ্যালু প্রদান করে onChanged() অবিলম্বে ইনভোক করা হয়। LiveData অবজেক্ট mCurrentName-এ কোনও ভ্যালু সেট না করলে, onChanged() কল করা হয় না।

LiveData অবজেক্ট আপডেট করুন

সেভ করা ডেটা আপডেট করার জন্য LiveData-এর কাছে সর্বজনীনভাবে উপলভ্য কোনও পদ্ধতি নেই। MutableLiveData ক্লাসটি setValue(T) এবং postValue(T) পদ্ধতিগুলি সর্বজনীনভাবে প্রকাশ করে এবং আপনাকে অবশ্যই এগুলি ব্যবহার করতে হবে যদি আপনি একটি LiveData অবজেক্টে স্টোর করা ভ্যালু এডিট করতে চান। সাধারণত MutableLiveData-কে ViewModel-এ ব্যবহার করা হয় এবং তারপর ViewModel শুধুমাত্র অপরিবর্তনীয় LiveData অবজেক্টকে পর্যবেক্ষকদের কাছে প্রকাশ করে।

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

Kotlin

button.setOnClickListener {
    val anotherName = "John Doe"
    model.currentName.setValue(anotherName)
}

জাভা

button.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
        String anotherName = "John Doe";
        model.getCurrentName().setValue(anotherName);
    }
});

উদাহরণে setValue(T) কল করার ফলে পর্যবেক্ষকরা তাদের onChanged() পদ্ধতিকে John Doe ভ্যালু দিয়ে কল করে। উদাহরণে বোতাম প্রেস করার কথা বলা হয়েছে, তবে setValue() বা postValue()-কে কল করে বিভিন্ন কারণে mName আপডেট করা যেতে পারে, যার মধ্যে নেটওয়ার্ক অনুরোধের উত্তর দেওয়া বা ডেটাবেস লোড সম্পূর্ণ করাও অন্তর্ভুক্ত; সব ক্ষেত্রেই, setValue() বা postValue()-কে কল করলে অবজার্ভার ট্রিগার হয় এবং UI আপডেট হয়।

Room-এর মাধ্যমে LiveData ব্যবহার করা

রুম পারসিসটেন্স লাইব্রেরি অবজার্ভেবল কোয়েরি সাপোর্ট করে, যা LiveData অবজেক্ট রিটার্ন করে। পর্যবেক্ষণযোগ্য কোয়েরি ডেটাবেস অ্যাক্সেস অবজেক্টের (DAO) অংশ হিসেবে লেখা হয়।

ডেটাবেস আপডেট করা হলে, LiveData অবজেক্ট আপডেট করার জন্য প্রয়োজনীয় সব কোড Room জেনারেট করে। জেনারেট করা কোডটি প্রয়োজন হলে ব্যাকগ্রাউন্ড থ্রেডে অ্যাসিঙ্ক্রোনাসভাবে কোয়েরি রান করে। এই প্যাটার্নটি UI-তে দেখানো ডেটা, ডেটাবেসে স্টোর করা ডেটার সাথে সিঙ্ক করে রাখার জন্য উপযোগী। আপনি রুম পারসিসটেন্স লাইব্রেরি গাইড থেকে রুম ও DAO সম্পর্কে আরও পড়তে পারবেন।

LiveData-এর সাথে কোরুটিন ব্যবহার করা

LiveData-এ Kotlin coroutines-এর জন্য সহায়তা অন্তর্ভুক্ত। আরও তথ্যের জন্য, Android আর্কিটেকচার কম্পোনেন্টের সাথে Kotlin Coroutines ব্যবহার করা দেখুন।

অ্যাপের আর্কিটেকচারে LiveData

LiveData হল লাইফসাইকেল-অ্যাওয়ার, যা অ্যাক্টিভিটি ও ফ্র্যাগমেন্টের মতো এন্টিটির লাইফসাইকেল অনুসরণ করে। এইসব লাইফসাইকেল মালিক এবং ViewModel অবজেক্টের মতো আলাদা লাইফস্প্যান সহ অন্যান্য অবজেক্টের মধ্যে যোগাযোগ করতে LiveData ব্যবহার করুন। ViewModel-এর মূল দায়িত্ব হল UI-সম্পর্কিত ডেটা লোড ও ম্যানেজ করা, যার ফলে এটি LiveData অবজেক্ট ধরে রাখার জন্য উপযুক্ত। ViewModel-এ LiveData অবজেক্ট তৈরি করুন এবং UI লেয়ারে স্টেট এক্সপোজ করতে সেগুলি ব্যবহার করুন।

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

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

Kotlin

class UserRepository {

    // DON'T DO THIS! LiveData objects should not live in the repository.
    fun getUsers(): LiveData<List<User>> {
        ...
    }

    fun getNewPremiumUsers(): LiveData<List<User>> {
        return getUsers().map { users ->
            // This is an expensive call being made on the main thread and may
            // cause noticeable jank in the UI!
            users
                .filter { user ->
                  user.isPremium
                }
          .filter { user ->
              val lastSyncedTime = dao.getLastSyncedTime()
              user.timeCreated > lastSyncedTime
                }
    }
}

জাভা

class UserRepository {

    // DON'T DO THIS! LiveData objects should not live in the repository.
    LiveData<List<User>> getUsers() {
        ...
    }

    LiveData<List<User>> getNewPremiumUsers() {
    return Transformations.map(getUsers(),
        // This is an expensive call being made on the main thread and may cause
        // noticeable jank in the UI!
        users -> users.stream()
            .filter(User::isPremium)
            .filter(user ->
                user.getTimeCreated() > dao.getLastSyncedTime())
            .collect(Collectors.toList()));
    }
}

আপনার অ্যাপের অন্যান্য লেয়ারে ডেটার স্ট্রিম ব্যবহার করতে হলে, Kotlin Flows ব্যবহার করার কথা বিবেচনা করুন এবং তারপরে ViewModel-এ asLiveData() ব্যবহার করে সেগুলিকে LiveData-এ কনভার্ট করুন। এই কোডল্যাবে LiveData-এর সাথে Kotlin Flow ব্যবহার করা সম্পর্কে আরও জানুন। Java দিয়ে তৈরি কোডবেসের জন্য, কলব্যাক বা RxJava-এর সাথে Executors ব্যবহার করার কথা বিবেচনা করুন।

LiveData এক্সটেন্ড করুন

LiveData কোনও পর্যবেক্ষককে অ্যাক্টিভ অবস্থায় আছে বলে বিবেচনা করে যদি পর্যবেক্ষকের লাইফসাইকেল STARTED অথবা RESUMED অবস্থায় থাকে। নিচের স্যাম্পেল কোড থেকে বোঝা যাবে যে কীভাবে LiveData ক্লাস এক্সটেন্ড করতে হয়:

Kotlin

class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
    private val stockManager = StockManager(symbol)

    private val listener = { price: BigDecimal ->
        value = price
    }

    override fun onActive() {
        stockManager.requestPriceUpdates(listener)
    }

    override fun onInactive() {
        stockManager.removeUpdates(listener)
    }
}

জাভা

public class StockLiveData extends LiveData<BigDecimal> {
    private StockManager stockManager;

    private SimplePriceListener listener = new SimplePriceListener() {
        @Override
        public void onPriceChanged(BigDecimal price) {
            setValue(price);
        }
    };

    public StockLiveData(String symbol) {
        stockManager = new StockManager(symbol);
    }

    @Override
    protected void onActive() {
        stockManager.requestPriceUpdates(listener);
    }

    @Override
    protected void onInactive() {
        stockManager.removeUpdates(listener);
    }
}

এই উদাহরণে প্রাইস লিসনারের প্রয়োগে নিম্নলিখিত গুরুত্বপূর্ণ পদ্ধতিগুলি অন্তর্ভুক্ত রয়েছে:

  • LiveData অবজেক্টে কোনও অ্যাক্টিভ অবজারভার থাকলে, onActive() পদ্ধতি কল করা হয়। এর অর্থ হল আপনাকে এই পদ্ধতি থেকে স্টক প্রাইস আপডেট লক্ষ্য করা শুরু করতে হবে।
  • LiveData অবজেক্টের কোনও অ্যাক্টিভ অবজারভার না থাকলে, onInactive() পদ্ধতিকে কল করা হয়। যেহেতু কোনও পর্যবেক্ষক শুনছেন না, তাই StockManager পরিষেবার সাথে কানেক্টেড থাকার কোনও কারণ নেই।
  • setValue(T) মেথড LiveData ইনস্ট্যান্সের ভ্যালু আপডেট করে এবং কোনও অ্যাক্টিভ অবজার্ভারকে পরিবর্তন সম্পর্কে বিজ্ঞপ্তি পাঠায়।

আপনি নিম্নলিখিত উপায়ে StockLiveData ক্লাস ব্যবহার করতে পারবেন:

Kotlin

public class MyFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val myPriceListener: LiveData<BigDecimal> = ...
        myPriceListener.observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->
            // Update the UI.
        })
    }
}

জাভা

public class MyFragment extends Fragment {
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        LiveData<BigDecimal> myPriceListener = ...;
        myPriceListener.observe(getViewLifecycleOwner(), price -> {
            // Update the UI.
        });
    }
}

observe() মেথড প্রথম আর্গুমেন্ট হিসেবে ফ্র্যাগমেন্টের ভিউয়ের সাথে যুক্ত LifecycleOwner পাস করে। এটি করার অর্থ হল এই পর্যবেক্ষক মালিকের সাথে সম্পর্কিত Lifecycle অবজেক্টের সাথে আবদ্ধ, অর্থাৎ:

  • Lifecycle অবজেক্ট অ্যাক্টিভ অবস্থায় না থাকলে, মান পরিবর্তন হলেও অবজারভারকে কল করা হয় না।
  • Lifecycle অবজেক্ট ধ্বংস হওয়ার পরে, অবজারভার অটোমেটিক সরিয়ে দেওয়া হয়।

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

Kotlin

class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
    private val stockManager: StockManager = StockManager(symbol)

    private val listener = { price: BigDecimal ->
        value = price
    }

    override fun onActive() {
        stockManager.requestPriceUpdates(listener)
    }

    override fun onInactive() {
        stockManager.removeUpdates(listener)
    }

    companion object {
        private lateinit var sInstance: StockLiveData

        @MainThread
        fun get(symbol: String): StockLiveData {
            sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
            return sInstance
        }
    }
}

জাভা

public class StockLiveData extends LiveData<BigDecimal> {
    private static StockLiveData sInstance;
    private StockManager stockManager;

    private SimplePriceListener listener = new SimplePriceListener() {
        @Override
        public void onPriceChanged(BigDecimal price) {
            setValue(price);
        }
    };

    @MainThread
    public static StockLiveData get(String symbol) {
        if (sInstance == null) {
            sInstance = new StockLiveData(symbol);
        }
        return sInstance;
    }

    private StockLiveData(String symbol) {
        stockManager = new StockManager(symbol);
    }

    @Override
    protected void onActive() {
        stockManager.requestPriceUpdates(listener);
    }

    @Override
    protected void onInactive() {
        stockManager.removeUpdates(listener);
    }
}

এবং আপনি এটি ফ্র্যাগমেন্টে এইভাবে ব্যবহার করতে পারবেন:

Kotlin

class MyFragment : Fragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        StockLiveData.get(symbol).observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->
            // Update the UI.
        })

    }

জাভা

public class MyFragment extends Fragment {
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> {
            // Update the UI.
        });
    }
}

একাধিক ফ্র্যাগমেন্ট ও অ্যাক্টিভিটি MyPriceListener ইনস্ট্যান্স দেখতে পারে। LiveData শুধুমাত্র সিস্টেম পরিষেবার সাথে কানেক্ট করে যদি তাদের মধ্যে এক বা একাধিক দৃশ্যমান এবং সক্রিয় থাকে।

LiveData ট্রান্সফর্ম করুন

আপনি হয়ত পর্যবেক্ষকদের কাছে পাঠানোর আগে LiveData অবজেক্টে স্টোর করা ভ্যালুতে পরিবর্তন করতে চাইবেন অথবা অন্য একটির ভ্যালুর উপর ভিত্তি করে আপনাকে হয়ত অন্য একটি LiveData ইনস্ট্যান্স রিটার্ন করতে হবে। Lifecycle প্যাকেজ Transformations ক্লাস প্রদান করে যার মধ্যে এইসব পরিস্থিতিতে সাহায্যকারী পদ্ধতি অন্তর্ভুক্ত।

Transformations.map()
LiveData অবজেক্টে স্টোর করা ভ্যালুর উপর একটি ফাংশন প্রয়োগ করে এবং ফলাফলটি ডাউনস্ট্রিমে প্রোপাগেট করে।

Kotlin

val userLiveData: LiveData<User> = UserLiveData()
val userName: LiveData<String> = userLiveData.map {
    user -> "${user.name} ${user.lastName}"
}

জাভা

LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
    user.name + " " + user.lastName
});
Transformations.switchMap()
map()-এর মতো, LiveData অবজেক্টে স্টোর করা ভ্যালুতে একটি ফাংশন প্রয়োগ করে এবং ফলাফলটি আনর‍্যাপ করে ডাউনস্ট্রিমে পাঠায়। switchMap()-এ পাস করা ফাংশনটি অবশ্যই একটি LiveData অবজেক্ট রিটার্ন করবে, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

Kotlin

private fun getUser(id: String): LiveData<User> {
  ...
}
val userId: LiveData<String> = ...
val user = userId.switchMap { id -> getUser(id) }

জাভা

private LiveData<User> getUser(String id) {
  ...;
}

LiveData<String> userId = ...;
LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );

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

আপনি যদি মনে করেন যে Lifecycle অবজেক্টটি ViewModel অবজেক্টের মধ্যে থাকা প্রয়োজন, তাহলে ট্রান্সফর্মেশন সম্ভবত আরও ভালো সমাধান। যেমন, ধরুন আপনার কাছে এমন একটি UI কম্পোনেন্ট আছে যা ঠিকানা গ্রহণ করে এবং সেই ঠিকানার পোস্টাল কোড রিটার্ন করে। আপনি এই কম্পোনেন্টের জন্য সাধারণ ViewModel প্রয়োগ করতে পারেন, যেমনটি নিম্নলিখিত স্যাম্পেল কোডে দেখানো হয়েছে:

Kotlin

class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() {

    private fun getPostalCode(address: String): LiveData<String> {
        // DON'T DO THIS
        return repository.getPostCode(address)
    }
}

জাভা

class MyViewModel extends ViewModel {
    private final PostalCodeRepository repository;
    public MyViewModel(PostalCodeRepository repository) {
       this.repository = repository;
    }

    private LiveData<String> getPostalCode(String address) {
       // DON'T DO THIS
       return repository.getPostCode(address);
    }
}

UI কম্পোনেন্টকে আগের LiveData অবজেক্ট থেকে আনরেজিস্টার করতে হবে এবং প্রতিবার getPostalCode() কল করার সময় নতুন ইনস্ট্যান্সে রেজিস্টার করতে হবে। এছাড়াও, UI কম্পোনেন্ট আবার তৈরি করা হলে, এটি আগের কলের ফলাফল ব্যবহার করার পরিবর্তে repository.getPostCode() পদ্ধতিতে আরেকটি কল ট্রিগার করে।

পরিবর্তে, আপনি ঠিকানা ইনপুটের রূপান্তর হিসেবে পোস্টাল কোড লুকআপ প্রয়োগ করতে পারেন, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

Kotlin

class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() {
    private val addressInput = MutableLiveData<String>()
    val postalCode: LiveData<String> = addressInput.switchMap {
            address -> repository.getPostCode(address) }


    private fun setInput(address: String) {
        addressInput.value = address
    }
}

জাভা

class MyViewModel extends ViewModel {
    private final PostalCodeRepository repository;
    private final MutableLiveData<String> addressInput = new MutableLiveData();
    public final LiveData<String> postalCode =
            Transformations.switchMap(addressInput, (address) -> {
                return repository.getPostCode(address);
             });

  public MyViewModel(PostalCodeRepository repository) {
      this.repository = repository
  }

  private void setInput(String address) {
      addressInput.setValue(address);
  }
}

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

এই মেকানিজম অ্যাপের নিচের লেভেলকে LiveData অবজেক্ট তৈরি করার অনুমতি দেয় যা চাহিদা অনুযায়ী লেজি ক্যালকুলেট করা হয়। একটি ViewModel অবজেক্ট সহজেই LiveData অবজেক্টের রেফারেন্স পেতে পারে এবং তারপরে সেগুলির উপরে ট্রান্সফর্মেশন রুল সংজ্ঞায়িত করতে পারে।

নতুন ট্রান্সফর্মেশন তৈরি করুন

আপনার অ্যাপে কাজে লাগতে পারে এমন এক ডজন বিভিন্ন নির্দিষ্ট ট্রান্সফর্মেশন আছে, কিন্তু সেগুলি ডিফল্ট হিসেবে প্রদান করা হয় না। আপনার নিজস্ব ট্রান্সফর্মেশন প্রয়োগ করতে আপনি MediatorLiveData ক্লাস ব্যবহার করতে পারেন, যা অন্যান্য LiveData অবজেক্ট শোনে এবং তাদের দ্বারা নির্গত ইভেন্ট প্রসেস করে। MediatorLiveData সঠিকভাবে এর স্ট্যাটাস সোর্স LiveData অবজেক্টে প্রোপাগেট করে। এই প্যাটার্ন সম্পর্কে আরও জানতে, Transformations ক্লাসের রেফারেন্স ডকুমেন্টেশন দেখুন।

একাধিক LiveData সোর্স মার্জ করা

MediatorLiveData হল LiveData-এর সাবক্লাস যা আপনাকে একাধিক LiveData সোর্স মার্জ করার অনুমতি দেয়। MediatorLiveData অবজেক্টের অবজারভার তখন ট্রিগার হয় যখনই আসল LiveData সোর্স অবজেক্টের পরিবর্তন হয়।

যেমন, আপনার UI-তে যদি কোনও LiveData অবজেক্ট থাকে যা লোকাল ডেটাবেস বা নেটওয়ার্ক থেকে আপডেট করা যায়, তাহলে আপনি MediatorLiveData অবজেক্টে নিম্নলিখিত সোর্স যোগ করতে পারবেন:

  • ডেটাবেসে স্টোর করা ডেটার সাথে যুক্ত একটি LiveData অবজেক্ট।
  • নেটওয়ার্ক থেকে অ্যাক্সেস করা ডেটার সাথে যুক্ত একটি LiveData অবজেক্ট।

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

অতিরিক্ত রিসোর্স

LiveData ক্লাস সম্পর্কে আরও জানতে, নিম্নলিখিত রিসোর্সগুলি দেখুন।

নমুনা

  • Sunflower, একটি ডেমো অ্যাপ যা আর্কিটেকচার কম্পোনেন্টের সাথে পেশাদার পদ্ধতি প্রদর্শন করে

কোডল্যাবস

ব্লগ

ভিডিও