Android Jetpack- এর ViewModel অংশের জন্য সংরক্ষিত স্টেট মডিউল।

সেভিং UI স্টেটসে উল্লিখিত হিসাবে, ViewModel অবজেক্টগুলি কনফিগারেশন পরিবর্তনগুলি পরিচালনা করতে পারে, তাই আপনাকে ঘূর্ণন বা অন্যান্য ক্ষেত্রে অবস্থা সম্পর্কে চিন্তা করতে হবে না। যাইহোক, যদি আপনাকে সিস্টেম-ইনিশিয়েটেড প্রসেস ডেথ পরিচালনা করতে হয়, আপনি ব্যাকআপ হিসাবে SavedStateHandle API ব্যবহার করতে চাইতে পারেন।

UI স্টেট সাধারণত ViewModel অবজেক্টে সংরক্ষিত বা রেফারেন্স করা হয় এবং ক্রিয়াকলাপ নয়, তাই onSaveInstanceState() বা rememberSaveable ব্যবহার করার জন্য কিছু বয়লারপ্লেট প্রয়োজন যা সংরক্ষিত স্টেট মডিউল আপনার জন্য পরিচালনা করতে পারে।

এই মডিউলটি ব্যবহার করার সময়, ViewModel অবজেক্টগুলি তার কন্সট্রাক্টরের মাধ্যমে একটি SavedStateHandle অবজেক্ট পায়। এই বস্তুটি একটি মূল-মান মানচিত্র যা আপনাকে সংরক্ষিত অবস্থায় এবং থেকে বস্তুগুলিকে লিখতে এবং পুনরুদ্ধার করতে দেয়। সিস্টেমের দ্বারা প্রক্রিয়াটি মারা যাওয়ার পরে এই মানগুলি বজায় থাকে এবং একই বস্তুর মাধ্যমে উপলব্ধ থাকে।

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

সেটআপ

ফ্র্যাগমেন্ট 1.2.0 বা এর ট্রানজিটিভ ডিপেন্ডেন্সি অ্যাক্টিভিটি 1.1.0 দিয়ে শুরু করে, আপনি আপনার ViewModel এর কনস্ট্রাক্টর আর্গুমেন্ট হিসেবে একটি SavedStateHandle গ্রহণ করতে পারেন।

কোটলিন

class SavedStateViewModel(private val state: SavedStateHandle) : ViewModel() { ... }

জাভা

public class SavedStateViewModel extends ViewModel {
    private SavedStateHandle state;

    public SavedStateViewModel(SavedStateHandle savedStateHandle) {
        state = savedStateHandle;
    }

    ...
}

তারপরে আপনি কোনও অতিরিক্ত কনফিগারেশন ছাড়াই আপনার ViewModel একটি উদাহরণ পুনরুদ্ধার করতে পারেন। ডিফল্ট ViewModel ফ্যাক্টরি আপনার ViewModel এ উপযুক্ত SavedStateHandle প্রদান করে।

কোটলিন

class MainFragment : Fragment() {
    val vm: SavedStateViewModel by viewModels()

    ...
}

জাভা

class MainFragment extends Fragment {
    private SavedStateViewModel vm;

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        vm = new ViewModelProvider(this).get(SavedStateViewModel.class);

        ...


    }

    ...
}

একটি কাস্টম ViewModelProvider.Factory উদাহরণ প্রদান করার সময়, আপনি AbstractSavedStateViewModelFactory প্রসারিত করে SavedStateHandle এর ব্যবহার সক্ষম করতে পারেন।

SavedStateHandle এর সাথে কাজ করা

SavedStateHandle ক্লাস হল একটি মূল-মান মানচিত্র যা আপনাকে set() এবং get() পদ্ধতির মাধ্যমে সংরক্ষিত অবস্থায় এবং থেকে ডেটা লিখতে এবং পুনরুদ্ধার করতে দেয়।

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

SavedStateHandle অন্যান্য পদ্ধতিও রয়েছে যা আপনি একটি মূল-মান মানচিত্রের সাথে ইন্টারঅ্যাক্ট করার সময় আশা করতে পারেন:

  • contains(String key) - প্রদত্ত কীটির জন্য একটি মান আছে কিনা তা পরীক্ষা করে।
  • remove(String key) - প্রদত্ত কীটির মান সরিয়ে দেয়।
  • keys() - SavedStateHandle মধ্যে থাকা সমস্ত কী ফেরত দেয়।

উপরন্তু, আপনি একটি পর্যবেক্ষণযোগ্য ডেটা ধারক ব্যবহার করে SavedStateHandle থেকে মান পুনরুদ্ধার করতে পারেন। সমর্থিত প্রকারের তালিকা হল:

লাইভডেটা

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

কোটলিন

class SavedStateViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
    val filteredData: LiveData<List<String>> =
        savedStateHandle.getLiveData<String>("query").switchMap { query ->
        repository.getFilteredData(query)
    }

    fun setQuery(query: String) {
        savedStateHandle["query"] = query
    }
}

জাভা

public class SavedStateViewModel extends ViewModel {
    private SavedStateHandle savedStateHandle;
    public LiveData<List<String>> filteredData;
    public SavedStateViewModel(SavedStateHandle savedStateHandle) {
        this.savedStateHandle = savedStateHandle;
        LiveData<String> queryLiveData = savedStateHandle.getLiveData("query");
        filteredData = Transformations.switchMap(queryLiveData, query -> {
            return repository.getFilteredData(query);
        });
    }

    public void setQuery(String query) {
        savedStateHandle.set("query", query);
    }
}

স্টেটফ্লো

getStateFlow() ব্যবহার করে পর্যবেক্ষণযোগ্য একটি StateFlow এ মোড়ানো SavedStateHandle থেকে মান পুনরুদ্ধার করুন। আপনি যখন কী এর মান আপডেট করেন, StateFlow নতুন মান পায়। প্রায়শই, আপনি ব্যবহারকারীর ইন্টারঅ্যাকশনের কারণে মান সেট করতে পারেন, যেমন ডেটার একটি তালিকা ফিল্টার করতে একটি ক্যোয়ারী প্রবেশ করান। তারপরে আপনি অন্যান্য ফ্লো অপারেটর ব্যবহার করে এই আপডেট করা মানটিকে রূপান্তর করতে পারেন।

কোটলিন

class SavedStateViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {
    val filteredData: StateFlow<List<String>> =
        savedStateHandle.getStateFlow<String>("query")
            .flatMapLatest { query ->
                repository.getFilteredData(query)
            }

    fun setQuery(query: String) {
        savedStateHandle["query"] = query
    }
}

পরীক্ষামূলক রচনার রাজ্য সমর্থন

lifecycle-viewmodel-compose আর্টিফ্যাক্ট পরীক্ষামূলক saveable API সরবরাহ করে যা SavedStateHandle এবং Compose's Saver মধ্যে আন্তঃকার্যযোগ্যতার অনুমতি দেয় যাতে আপনি একটি কাস্টম Saver সাথে rememberSaveable এর মাধ্যমে সংরক্ষণ করতে পারেন এমন যেকোন State SavedStateHandle এর মাধ্যমে সংরক্ষণ করা যেতে পারে।

কোটলিন

class SavedStateViewModel(private val savedStateHandle: SavedStateHandle) : ViewModel() {

    var filteredData: List<String> by savedStateHandle.saveable {
        mutableStateOf(emptyList())
    }

    fun setQuery(query: String) {
        withMutableSnapshot {
            filteredData += query
        }
    }
}

সমর্থিত প্রকার

একটি SavedStateHandle মধ্যে রাখা ডেটা অ্যাক্টিভিটি বা ফ্র্যাগমেন্টের জন্য বাকি savedInstanceState সহ একটি Bundle হিসাবে সংরক্ষণ এবং পুনরুদ্ধার করা হয়।

সরাসরি সমর্থিত প্রকার

ডিফল্টরূপে, আপনি একটি SavedStateHandle set() কল করতে পারেন এবং একটি Bundle মতো একই ডেটা প্রকারের জন্য get() , যেমনটি নীচে দেখানো হয়েছে:

টাইপ/ক্লাস সাপোর্ট অ্যারে সমর্থন
double double[]
int int[]
long long[]
String String[]
byte byte[]
char char[]
CharSequence CharSequence[]
float float[]
Parcelable Parcelable[]
Serializable Serializable[]
short short[]
SparseArray
Binder
Bundle
ArrayList
Size (only in API 21+)
SizeF (only in API 21+)

যদি ক্লাস উপরের তালিকার একটিকে প্রসারিত না করে, তাহলে @Parcelize Kotlin টীকা যোগ করে বা সরাসরি Parcelable প্রয়োগ করে ক্লাসটিকে পার্সেবল করার কথা বিবেচনা করুন।

অ-পার্সেলযোগ্য ক্লাস সংরক্ষণ করা হচ্ছে

যদি একটি ক্লাস Parcelable বা Serializable বাস্তবায়ন না করে এবং সেই ইন্টারফেসগুলির একটি বাস্তবায়নের জন্য সংশোধন করা না যায়, তাহলে সেই ক্লাসের একটি উদাহরণকে একটি SavedStateHandle এ সরাসরি সংরক্ষণ করা সম্ভব নয়।

লাইফসাইকেল 2.3.0-alpha03 দিয়ে শুরু করে, SavedStateHandle আপনাকে setSavedStateProvider() পদ্ধতি ব্যবহার করে Bundle হিসাবে আপনার অবজেক্টকে সংরক্ষণ এবং পুনরুদ্ধার করার জন্য আপনার নিজস্ব যুক্তি প্রদান করে যেকোনো বস্তু সংরক্ষণ করতে দেয়। SavedStateRegistry.SavedStateProvider হল একটি ইন্টারফেস যা একটি একক saveState() পদ্ধতি সংজ্ঞায়িত করে যা একটি Bundle প্রদান করে যেখানে আপনি যে রাজ্যটি সংরক্ষণ করতে চান। যখন SavedStateHandle তার অবস্থা সংরক্ষণ করার জন্য প্রস্তুত হয়, তখন এটি saveState() SavedStateProvider থেকে Bundle পুনরুদ্ধার করতে কল করে এবং সংশ্লিষ্ট কীটির জন্য Bundle সংরক্ষণ করে।

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

কোটলিন

class TempFileViewModel : ViewModel() {
    private var tempFile: File? = null

    fun createOrGetTempFile(): File {
        return tempFile ?: File.createTempFile("temp", null).also {
            tempFile = it
        }
    }
}

জাভা

class TempFileViewModel extends ViewModel {
    private File tempFile = null;

    public TempFileViewModel() {
    }


    @NonNull
    public File createOrGetTempFile() {
        if (tempFile == null) {
            tempFile = File.createTempFile("temp", null);
        }
        return tempFile;
    }
}

ক্রিয়াকলাপের প্রক্রিয়াটি মারা গেলে এবং পরে পুনরুদ্ধার করা হলে অস্থায়ী ফাইলটি হারিয়ে না যায় তা নিশ্চিত করতে, TempFileViewModel তার ডেটা বজায় রাখতে SavedStateHandle ব্যবহার করতে পারে। TempFileViewModel তার ডেটা সংরক্ষণ করার অনুমতি দিতে, SavedStateProvider প্রয়োগ করুন এবং ViewModel এর SavedStateHandle এ প্রদানকারী হিসেবে সেট করুন:

কোটলিন

private fun File.saveTempFile() = bundleOf("path", absolutePath)

class TempFileViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
    private var tempFile: File? = null
    init {
        savedStateHandle.setSavedStateProvider("temp_file") { // saveState()
            if (tempFile != null) {
                tempFile.saveTempFile()
            } else {
                Bundle()
            }
        }
    }

    fun createOrGetTempFile(): File {
        return tempFile ?: File.createTempFile("temp", null).also {
            tempFile = it
        }
    }
}

জাভা

class TempFileViewModel extends ViewModel {
    private File tempFile = null;

    public TempFileViewModel(SavedStateHandle savedStateHandle) {
        savedStateHandle.setSavedStateProvider("temp_file",
            new TempFileSavedStateProvider());
    }
    @NonNull
    public File createOrGetTempFile() {
        if (tempFile == null) {
            tempFile = File.createTempFile("temp", null);
        }
        return tempFile;
    }

    private class TempFileSavedStateProvider implements SavedStateRegistry.SavedStateProvider {
        @NonNull
        @Override
        public Bundle saveState() {
            Bundle bundle = new Bundle();
            if (tempFile != null) {
                bundle.putString("path", tempFile.getAbsolutePath());
            }
            return bundle;
        }
    }
}

যখন ব্যবহারকারী ফিরে আসে তখন File ডেটা পুনরুদ্ধার করতে, SavedStateHandle থেকে temp_file Bundle পুনরুদ্ধার করুন। এটি saveTempFile() দ্বারা প্রদত্ত একই Bundle যা পরম পাথ ধারণ করে। পরম পাথ তারপর একটি নতুন File ইনস্ট্যান্ট করতে ব্যবহার করা যেতে পারে।

কোটলিন

private fun File.saveTempFile() = bundleOf("path", absolutePath)

private fun Bundle.restoreTempFile() = if (containsKey("path")) {
    File(getString("path"))
} else {
    null
}

class TempFileViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
    private var tempFile: File? = null
    init {
        val tempFileBundle = savedStateHandle.get<Bundle>("temp_file")
        if (tempFileBundle != null) {
            tempFile = tempFileBundle.restoreTempFile()
        }
        savedStateHandle.setSavedStateProvider("temp_file") { // saveState()
            if (tempFile != null) {
                tempFile.saveTempFile()
            } else {
                Bundle()
            }
        }
    }

    fun createOrGetTempFile(): File {
      return tempFile ?: File.createTempFile("temp", null).also {
          tempFile = it
      }
    }
}

জাভা

class TempFileViewModel extends ViewModel {
    private File tempFile = null;

    public TempFileViewModel(SavedStateHandle savedStateHandle) {
        Bundle tempFileBundle = savedStateHandle.get("temp_file");
        if (tempFileBundle != null) {
            tempFile = TempFileSavedStateProvider.restoreTempFile(tempFileBundle);
        }
        savedStateHandle.setSavedStateProvider("temp_file", new TempFileSavedStateProvider());
    }

    @NonNull
    public File createOrGetTempFile() {
        if (tempFile == null) {
            tempFile = File.createTempFile("temp", null);
        }
        return tempFile;
    }

    private class TempFileSavedStateProvider implements SavedStateRegistry.SavedStateProvider {
        @NonNull
        @Override
        public Bundle saveState() {
            Bundle bundle = new Bundle();
            if (tempFile != null) {
                bundle.putString("path", tempFile.getAbsolutePath());
            }
            return bundle;
        }

        @Nullable
        private static File restoreTempFile(Bundle bundle) {
            if (bundle.containsKey("path") {
                return File(bundle.getString("path"));
            }
            return null;
        }
    }
}

টেস্টে সংরক্ষিত স্টেটহ্যান্ডেল

একটি নির্ভরতা হিসাবে একটি SavedStateHandle গ্রহণ করে এমন একটি ViewModel পরীক্ষা করতে, এটির প্রয়োজনীয় পরীক্ষার মানগুলির সাথে SavedStateHandle এর একটি নতুন উদাহরণ তৈরি করুন এবং আপনি যে ViewModel পরীক্ষা করছেন সেটিতে পাস করুন৷

কোটলিন

class MyViewModelTest {

    private lateinit var viewModel: MyViewModel

    @Before
    fun setup() {
        val savedState = SavedStateHandle(mapOf("someIdArg" to testId))
        viewModel = MyViewModel(savedState = savedState)
    }
}

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

ViewModel এর জন্য সংরক্ষিত স্টেট মডিউল সম্পর্কে আরও তথ্যের জন্য, নিম্নলিখিত সংস্থানগুলি দেখুন।

কোডল্যাব

{% শব্দার্থে %} {% endverbatim %} {% শব্দার্থে %} {% endverbatim %}