দেখুন মডেল ওভারভিউ অ্যান্ড্রয়েড জেটপ্যাকের অংশ।

ViewModel ক্লাস হল একটি ব্যবসায়িক যুক্তি বা স্ক্রীন লেভেল স্টেট হোল্ডার । এটি UI-তে রাষ্ট্রকে প্রকাশ করে এবং সম্পর্কিত ব্যবসায়িক যুক্তিকে এনক্যাপসুলেট করে। এর প্রধান সুবিধা হল এটি ক্যাশে স্টেট এবং কনফিগারেশন পরিবর্তনের মাধ্যমে এটিকে টিকে থাকে। এর মানে হল যে ক্রিয়াকলাপগুলির মধ্যে নেভিগেট করার সময় বা স্ক্রীন ঘোরানোর মতো কনফিগারেশন পরিবর্তনগুলি অনুসরণ করার সময় আপনার UI কে আবার ডেটা আনতে হবে না।

রাষ্ট্র ধারকদের সম্পর্কে আরও তথ্যের জন্য, রাষ্ট্র ধারকদের নির্দেশিকা দেখুন। একইভাবে, সাধারণত UI স্তর সম্পর্কে আরও তথ্যের জন্য, UI স্তর নির্দেশিকা দেখুন।

দেখুন মডেল সুবিধা

একটি ViewModel-এর বিকল্প হল একটি প্লেইন ক্লাস যা আপনার UI-তে প্রদর্শিত ডেটা ধারণ করে। কার্যকলাপ বা নেভিগেশন গন্তব্যের মধ্যে নেভিগেট করার সময় এটি একটি সমস্যা হতে পারে। যদি আপনি সেভিং ইনস্ট্যান্স স্টেট মেকানিজম ব্যবহার করে এটি সংরক্ষণ না করেন তবে এটি করা সেই ডেটাটিকে ধ্বংস করে। ভিউমডেল ডেটা স্থিরতার জন্য একটি সুবিধাজনক API প্রদান করে যা এই সমস্যাটির সমাধান করে।

ViewModel ক্লাসের মূল সুবিধাগুলি মূলত দুটি:

  • এটি আপনাকে UI অবস্থা বজায় রাখার অনুমতি দেয়।
  • এটি ব্যবসায়িক যুক্তিতে অ্যাক্সেস সরবরাহ করে।

জেদ

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

ব্যাপ্তি

আপনি যখন একটি ভিউমডেল ইনস্ট্যান্টিয়েট করেন, আপনি এটিকে একটি বস্তু পাস করেন যা ViewModelStoreOwner ইন্টারফেস প্রয়োগ করে। এটি একটি ন্যাভিগেশন গন্তব্য হতে পারে, নেভিগেশন গ্রাফ, কার্যকলাপ, খণ্ড বা অন্য কোন প্রকার যা ইন্টারফেস প্রয়োগ করে। আপনার ViewModel তারপর ViewModelStoreOwner এর লাইফসাইকেলে স্কোপ করা হয়। এটি মেমরিতে থাকে যতক্ষণ না এর ViewModelStoreOwner স্থায়ীভাবে চলে যায়।

ক্লাসের একটি পরিসর হল ViewModelStoreOwner ইন্টারফেসের প্রত্যক্ষ বা পরোক্ষ সাবক্লাস। সরাসরি সাবক্লাসগুলি হল ComponentActivity , Fragment , এবং NavBackStackEntry । পরোক্ষ সাবক্লাসের সম্পূর্ণ তালিকার জন্য, ViewModelStoreOwner রেফারেন্স দেখুন।

যখন ViewModel স্কোপ করা হয়েছে সেই খণ্ড বা কার্যকলাপটি ধ্বংস হয়ে গেলে, ViewModel-এ অ্যাসিঙ্ক্রোনাস কাজ চলতে থাকে যা এটির স্কোপ করা হয়। এটি অধ্যবসায়ের চাবিকাঠি।

আরও তথ্যের জন্য, ViewModel জীবনচক্রের নীচের বিভাগটি দেখুন।

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

SavedStateHandle আপনাকে শুধুমাত্র কনফিগারেশন পরিবর্তনের মাধ্যমে নয়, বরং প্রক্রিয়া বিনোদন জুড়ে ডেটা বজায় রাখতে দেয়। অর্থাৎ, ব্যবহারকারী যখন অ্যাপটি বন্ধ করে এবং পরবর্তী সময়ে এটি খোলে তখনও এটি আপনাকে UI অবস্থা অক্ষত রাখতে সক্ষম করে।

ব্যবসায়িক যুক্তিতে অ্যাক্সেস

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

UI লেয়ারে ব্যবসার লজিক পরিচালনা করার জন্য ViewModel হল সঠিক জায়গা। ViewModel ইভেন্টগুলি পরিচালনা করার এবং অনুক্রমের অন্যান্য স্তরগুলিতে তাদের অর্পণ করার দায়িত্বে রয়েছে যখন অ্যাপ্লিকেশন ডেটা পরিবর্তন করার জন্য ব্যবসায়িক যুক্তি প্রয়োগ করা প্রয়োজন৷

জেটপ্যাক রচনা

জেটপ্যাক কম্পোজ ব্যবহার করার সময়, ViewModel হল আপনার কম্পোজেবলে স্ক্রীন UI অবস্থা প্রকাশ করার প্রাথমিক মাধ্যম। একটি হাইব্রিড অ্যাপে, ক্রিয়াকলাপ এবং টুকরোগুলি কেবল আপনার রচনাযোগ্য ফাংশনগুলিকে হোস্ট করে৷ এটি অতীতের পন্থা থেকে একটি পরিবর্তন, যেখানে ক্রিয়াকলাপ এবং টুকরো দিয়ে UI এর পুনঃব্যবহারযোগ্য টুকরো তৈরি করা এত সহজ এবং স্বজ্ঞাত ছিল না, যার কারণে তারা UI কন্ট্রোলার হিসাবে অনেক বেশি সক্রিয় ছিল।

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

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

আরও তথ্যের জন্য, জেটপ্যাক রচনার জন্য রাজ্য উত্তোলনের নির্দেশিকা দেখুন।

একটি ভিউ মডেল বাস্তবায়ন করুন

নিম্নলিখিতটি একটি স্ক্রিনের জন্য একটি ভিউ মডেলের একটি উদাহরণ বাস্তবায়ন যা ব্যবহারকারীকে পাশা রোল করতে দেয়৷

কোটলিন

data class DiceUiState(
    val firstDieValue: Int? = null,
    val secondDieValue: Int? = null,
    val numberOfRolls: Int = 0,
)

class DiceRollViewModel : ViewModel() {

    // Expose screen UI state
    private val _uiState = MutableStateFlow(DiceUiState())
    val uiState: StateFlow<DiceUiState> = _uiState.asStateFlow()

    // Handle business logic
    fun rollDice() {
        _uiState.update { currentState ->
            currentState.copy(
                firstDieValue = Random.nextInt(from = 1, until = 7),
                secondDieValue = Random.nextInt(from = 1, until = 7),
                numberOfRolls = currentState.numberOfRolls + 1,
            )
        }
    }
}

জাভা

public class DiceUiState {
    private final Integer firstDieValue;
    private final Integer secondDieValue;
    private final int numberOfRolls;

    // ...
}

public class DiceRollViewModel extends ViewModel {

    private final MutableLiveData<DiceUiState> uiState =
        new MutableLiveData(new DiceUiState(null, null, 0));
    public LiveData<DiceUiState> getUiState() {
        return uiState;
    }

    public void rollDice() {
        Random random = new Random();
        uiState.setValue(
            new DiceUiState(
                random.nextInt(7) + 1,
                random.nextInt(7) + 1,
                uiState.getValue().getNumberOfRolls() + 1
            )
        );
    }
}

তারপর আপনি নিম্নলিখিত হিসাবে একটি কার্যকলাপ থেকে ViewModel অ্যাক্সেস করতে পারেন:

কোটলিন

import androidx.activity.viewModels

class DiceRollActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same DiceRollViewModel instance created by the first activity.

        // Use the 'by viewModels()' Kotlin property delegate
        // from the activity-ktx artifact
        val viewModel: DiceRollViewModel by viewModels()
        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect {
                    // Update UI elements
                }
            }
        }
    }
}

জাভা

public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same MyViewModel instance created by the first activity.
        DiceRollViewModel model = new ViewModelProvider(this).get(DiceRollViewModel.class);
        model.getUiState().observe(this, uiState -> {
            // update UI
        });
    }
}

জেটপ্যাক রচনা

import androidx.lifecycle.viewmodel.compose.viewModel

// Use the 'viewModel()' function from the lifecycle-viewmodel-compose artifact
@Composable
fun DiceRollScreen(
    viewModel: DiceRollViewModel = viewModel()
) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()
    // Update UI elements
}

ViewModel এর সাথে coroutines ব্যবহার করুন

ViewModel Kotlin coroutines-এর জন্য সমর্থন অন্তর্ভুক্ত। এটি UI অবস্থার মতো একইভাবে অ্যাসিঙ্ক্রোনাস কাজ চালিয়ে যেতে সক্ষম।

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

একটি ভিউ মডেলের জীবনচক্র

একটি ViewModel এর জীবনচক্র সরাসরি এর সুযোগের সাথে আবদ্ধ। একটি ViewModel মেমরিতে থেকে যায় যতক্ষণ না ViewModelStoreOwner যার স্কোপ করা হয়েছে সেটি অদৃশ্য হয়ে যায়। এটি নিম্নলিখিত প্রসঙ্গে ঘটতে পারে:

  • একটি কার্যকলাপের ক্ষেত্রে, যখন এটি শেষ হয়।
  • একটি খণ্ডের ক্ষেত্রে, যখন এটি বিচ্ছিন্ন হয়।
  • একটি নেভিগেশন এন্ট্রির ক্ষেত্রে, যখন এটি পিছনের স্ট্যাক থেকে সরানো হয়।

এটি ViewModels কে ডেটা সঞ্চয় করার জন্য একটি দুর্দান্ত সমাধান করে তোলে যা কনফিগারেশন পরিবর্তন থেকে বেঁচে থাকে।

চিত্র 1 একটি ক্রিয়াকলাপের বিভিন্ন জীবনচক্রের অবস্থাকে চিত্রিত করে যখন এটি একটি ঘূর্ণনের মধ্য দিয়ে যায় এবং তারপরে শেষ হয়। দৃষ্টান্তটি সংশ্লিষ্ট কার্যকলাপ জীবনচক্রের পাশে ViewModel এর জীবনকালও দেখায়। এই বিশেষ চিত্রটি একটি কার্যকলাপের অবস্থাকে চিত্রিত করে। একই মৌলিক অবস্থা একটি খণ্ডের জীবনচক্রের ক্ষেত্রে প্রযোজ্য।

একটি ভিউ মডেলের জীবনচক্রকে চিত্রিত করে কারণ একটি কার্যকলাপের অবস্থা পরিবর্তন হয়।

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

ViewModel নির্ভরতা সাফ করা হচ্ছে

ViewModel-কে onCleared পদ্ধতি বলে যখন ViewModelStoreOwner তার জীবনচক্র চলাকালীন এটিকে ধ্বংস করে। এটি আপনাকে ভিউমডেলের জীবনচক্র অনুসরণ করে এমন কোনো কাজ বা নির্ভরতা পরিষ্কার করতে দেয়।

নিম্নলিখিত উদাহরণটি viewModelScope এর বিকল্প দেখায়। viewModelScope হল একটি অন্তর্নির্মিত CoroutineScope যা স্বয়ংক্রিয়ভাবে ViewModel এর জীবনচক্র অনুসরণ করে। ViewModel ব্যবসা-সম্পর্কিত ক্রিয়াকলাপ ট্রিগার করতে এটি ব্যবহার করে। আপনি যদি সহজ পরীক্ষার জন্য viewModelScope এর পরিবর্তে একটি কাস্টম সুযোগ ব্যবহার করতে চান, তাহলে ViewModel তার কনস্ট্রাক্টরের উপর নির্ভরতা হিসাবে একটি CoroutineScope পেতে পারে। যখন ViewModelStoreOwner তার জীবনচক্রের শেষে ViewModelটিকে সাফ করে, ViewModel এছাড়াও CoroutineScope বাতিল করে।

class MyViewModel(
    private val coroutineScope: CoroutineScope =
        CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
) : ViewModel() {

    // Other ViewModel logic ...

    override fun onCleared() {
        coroutineScope.cancel()
    }
}

লাইফসাইকেল সংস্করণ 2.5 এবং তার উপরে থেকে, আপনি ViewModel-এর কনস্ট্রাক্টরের কাছে এক বা একাধিক Closeable অবজেক্ট পাস করতে পারেন যা ViewModel ইন্সট্যান্স সাফ হয়ে গেলে স্বয়ংক্রিয়ভাবে বন্ধ হয়ে যায়।

class CloseableCoroutineScope(
    context: CoroutineContext = SupervisorJob() + Dispatchers.Main.immediate
) : Closeable, CoroutineScope {
    override val coroutineContext: CoroutineContext = context
    override fun close() {
        coroutineContext.cancel()
   }
}

class MyViewModel(
    private val coroutineScope: CoroutineScope = CloseableCoroutineScope()
) : ViewModel(coroutineScope) {
    // Other ViewModel logic ...
}

সেরা অনুশীলন

ViewModel বাস্তবায়ন করার সময় নিম্নলিখিত কয়েকটি মূল সেরা অনুশীলনগুলি অনুসরণ করা উচিত:

  • তাদের স্কোপিংয়ের কারণে, একটি স্ক্রীন স্তরের স্টেট হোল্ডারের বাস্তবায়নের বিবরণ হিসাবে ViewModels ব্যবহার করুন। পুনঃব্যবহারযোগ্য UI উপাদান যেমন চিপ গ্রুপ বা ফর্মগুলির স্টেট হোল্ডার হিসাবে ব্যবহার করবেন না৷ অন্যথায়, আপনি একই ViewModelStoreOwner-এর অধীনে একই UI উপাদানের বিভিন্ন ব্যবহারে একই ViewModel দৃষ্টান্ত পাবেন যদি না আপনি প্রতি চিপে একটি স্পষ্ট ভিউ মডেল কী ব্যবহার করেন।
  • ViewModels UI বাস্তবায়নের বিবরণ সম্পর্কে জানা উচিত নয়। ViewModel API যে পদ্ধতিগুলি প্রকাশ করে এবং UI স্টেট ক্ষেত্রগুলির নামগুলি যতটা সম্ভব জেনেরিক রাখুন৷ এইভাবে, আপনার ভিউমডেল যেকোনো ধরনের UI মিটমাট করতে পারে: একটি মোবাইল ফোন, ফোল্ডেবল, ট্যাবলেট, এমনকি একটি Chromebook!
  • যেহেতু তারা সম্ভাব্যভাবে ViewModelStoreOwner এর চেয়ে বেশি দিন বাঁচতে পারে, তাই ViewModels-এর কাছে লাইফসাইকেল-সম্পর্কিত API-এর কোনো রেফারেন্স রাখা উচিত নয় যেমন মেমরি ফাঁস প্রতিরোধ করার জন্য Context বা Resources
  • অন্য ক্লাস, ফাংশন বা অন্যান্য UI উপাদানগুলিতে ViewModels পাস করবেন না। যেহেতু প্ল্যাটফর্ম তাদের পরিচালনা করে, আপনার যতটা সম্ভব এটির কাছাকাছি রাখা উচিত। আপনার অ্যাক্টিভিটি, ফ্র্যাগমেন্ট বা স্ক্রিন লেভেল কম্পোজেবল ফাংশনের কাছাকাছি। এটি নিম্ন স্তরের উপাদানগুলিকে তাদের প্রয়োজনের চেয়ে বেশি ডেটা এবং যুক্তি অ্যাক্সেস করতে বাধা দেয়।

আরো তথ্য

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

অ্যান্ড্রয়েড অ্যাপ আর্কিটেকচারের গাইড এই ফাংশনগুলি পরিচালনা করার জন্য একটি সংগ্রহস্থল শ্রেণী তৈরি করার পরামর্শ দেয়৷

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

ViewModel ক্লাস সম্পর্কে আরও তথ্যের জন্য, নিম্নলিখিত সংস্থানগুলি দেখুন৷

ডকুমেন্টেশন

নমুনা

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