কম্পিউটার

ড্যাগার 2 এর সাথে আপনার অ্যাপে ডিপেনডেন্সি ইনজেকশন কীভাবে প্রয়োগ করবেন

Kriptofolio অ্যাপ সিরিজ - পার্ট 4

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

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

সিরিজ বিষয়বস্তু

  • পরিচয়:2018-2019 সালে একটি আধুনিক অ্যান্ড্রয়েড অ্যাপ তৈরি করার একটি রোডম্যাপ
  • পর্ব 1:সলিড নীতিগুলির একটি ভূমিকা
  • অংশ 2:কিভাবে আপনার Android অ্যাপ তৈরি করা শুরু করবেন:Mockups, UI, এবং XML লেআউট তৈরি করা
  • ৩য় খণ্ড:সেই আর্কিটেকচার সম্বন্ধে সমস্ত কিছু:বিভিন্ন আর্কিটেকচার প্যাটার্ন অন্বেষণ করা এবং কীভাবে সেগুলি আপনার অ্যাপে ব্যবহার করবেন
  • ৪র্থ পর্ব:ড্যাগার ২ এর মাধ্যমে আপনার অ্যাপে ডিপেন্ডেন্সি ইনজেকশন কীভাবে প্রয়োগ করবেন (আপনি এখানে আছেন)
  • অংশ 5:Retrofit, OkHttp, Gson, Glide এবং Coroutines ব্যবহার করে RESTful ওয়েব পরিষেবাগুলি পরিচালনা করুন

নির্ভরতা ইনজেকশন কি?

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

class MyAppClass() {

    private val library: MyLibrary = MyLibrary(true)
    ...
}

class MyLibrary(private val useSpecialFeature: Boolean) {
    
    ...
}

যেমন আপনি এই উদাহরণ থেকে দেখতে পাচ্ছেন আপনার ক্লাস MyAppClass আপনার লাইব্রেরি ক্লাসের কংক্রিট কনফিগারেশন এবং বাস্তবায়নের উপর সরাসরি নির্ভর করবে MyLibrary . আপনি যদি একদিন পরিবর্তে তৃতীয় পক্ষের লাইব্রেরি ব্যবহার করতে চান? যদি আপনি অন্য ক্লাস করতে চান যেখানে আপনি ঠিক একই লাইব্রেরি কনফিগারেশন ব্যবহার করতে চান? প্রতিবার আপনাকে আপনার কোডের মাধ্যমে অনুসন্ধান করতে হবে, সঠিক স্থানটি সন্ধান করতে হবে এবং এটি পরিবর্তন করতে হবে। এটা মাত্র কয়েকটি উদাহরণ।

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

class MyAppClass(private val library: MyLibrary) {
    
    ...
}

class MyLibrary(private val useSpecialFeature: Boolean) {
    
    ...
}

এটাই, এটি একটি খুব আদিম নির্ভরতা ইনজেকশন উদাহরণ। একটি নতুন MyLibrary তৈরি এবং কনফিগার করার পরিবর্তে ক্লাস অবজেক্ট আপনার ক্লাস MyAppClass এর ভিতরে , আপনি শুধু পাস বা কনস্ট্রাক্টর মধ্যে ইনজেকশনের. তাই MyAppClass MyLibrary এর জন্য সম্পূর্ণ দায়িত্বজ্ঞানহীন হতে পারে .

ড্যাগার 2 কি?

Dagger জাভা এবং অ্যান্ড্রয়েড উভয়ের জন্য একটি সম্পূর্ণ স্ট্যাটিক, কম্পাইল-টাইম, ওপেন-সোর্স নির্ভরতা ইনজেকশন ফ্রেমওয়ার্ক। এই নিবন্ধে আমি এর দ্বিতীয় সংস্করণ সম্পর্কে কথা বলব যা Google বজায় রাখে। স্কয়ার তার আগের সংস্করণ তৈরি করেছে৷

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

আপনি এখন নির্ভরতা ইনজেকশন সম্পর্কে বুঝতে পেরেছেন, আমাদের ক্লাসের নির্ভরতা তৈরি করা বা থাকা উচিত নয়। পরিবর্তে তাদের বাইরে থেকে সবকিছু পেতে হবে। তাই ড্যাগার 2 ব্যবহার করার সময়, এই কাঠামোটি প্রয়োজনীয় সমস্ত নির্ভরতা প্রদান করবে।

এটি আমাদের জন্য প্রচুর বয়লারপ্লেট কোড তৈরি করে এটি করে। সেই জেনারেট করা কোডটি সম্পূর্ণরূপে ট্রেসযোগ্য হবে এবং কোডটি নকল করবে যা একজন ব্যবহারকারী হাতে লিখতে পারে। ড্যাগার 2 জাভাতে লেখা এবং এর টীকা প্রসেসর দ্বারা জেনারেট করা কোডটিও জাভা কোড হবে।

তবে এটি কোটলিনের সাথে কোন সমস্যা বা পরিবর্তন ছাড়াই কাজ করে। মনে রাখবেন কোটলিন জাভার সাথে সম্পূর্ণ আন্তঃপ্রক্রিয়াযোগ্য। অনুরূপ কাঠামোর সাথে তুলনা করলে, ড্যাগার 2 একটি কম গতিশীল। এটি প্রতিফলনের সাথে রান-টাইমের পরিবর্তে কম্পাইল সময়ে কাজ করে। কোন প্রতিফলন ব্যবহার এ সব নেই. এর অর্থ হল এই কাঠামোটি সেট আপ করা এবং শেখা কঠিন হবে। এটি কম্পাইল-টাইম নিরাপত্তার সাথে পারফরম্যান্স বুস্ট প্রদান করবে।

টুল ছাড়াই ম্যানুয়াল ডিপেন্ডেন্সি ইনজেকশন

আপনি পূর্ববর্তী অংশ থেকে My Crypto Coins অ্যাপের সোর্স কোডে লক্ষ্য করেছেন যে কোনও নির্ভরতা ইনজেকশন সরঞ্জাম ব্যবহার না করেই বস্তুকে ইনজেকশন দেওয়ার জন্য কোডের একটি অংশ রয়েছে। এটা সূক্ষ্ম কাজ করে, এবং এই সমাধান এই মত একটি ছোট অ্যাপ্লিকেশন জন্য যথেষ্ট ভাল হবে. ইউটিলিটি প্যাকেজটি দেখুন:

/**
 * Static methods used to inject classes needed for various Activities and Fragments.
 */
object InjectorUtils {

    private fun getCryptocurrencyRepository(context: Context): CryptocurrencyRepository {
        return CryptocurrencyRepository.getInstance(
                AppDatabase.getInstance(context).cryptocurrencyDao())
    }

    fun provideMainViewModelFactory(
            application: Application
    ): MainViewModelFactory {
        val repository = getCryptocurrencyRepository(application)
        return MainViewModelFactory(application, repository)
    }

    fun provideAddSearchViewModelFactory(
            context: Context
    ): AddSearchViewModelFactory {
        val repository = getCryptocurrencyRepository(context)
        return AddSearchViewModelFactory(repository)
    }
}

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

/**
 * Factory for creating a [MainViewModel] with a constructor that takes a
 * [CryptocurrencyRepository].
 */
class MainViewModelFactory(private val application: Application, private val repository: CryptocurrencyRepository) : ViewModelProvider.NewInstanceFactory() {

    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return MainViewModel(application, repository) as T
    }

}

তারপর আপনি InjectorUtils ব্যবহার করুন এই ধরনের ক্লাস যেখানে আপনাকে একটি নির্দিষ্ট ভিউমডেল ফ্যাক্টরি পেতে হবে:

/**
 * A placeholder fragment containing a simple view.
 */
class MainListFragment : Fragment() {

    ...

    private lateinit var viewModel: MainViewModel

    ...

    override fun onActivityCreated(savedInstanceState: Bundle?) {

        super.onActivityCreated(savedInstanceState)

        setupList()
        ...
    }

    ...

    private fun subscribeUi(activity: FragmentActivity) {

        // This is the old way how we were injecting code before using Dagger.
        val factory = InjectorUtils.provideMainViewModelFactory(activity.application)

        // Obtain ViewModel from ViewModelProviders, using parent activity as LifecycleOwner.
        viewModel = ViewModelProviders.of(activity, factory).get(MainViewModel::class.java)

        ...
    }

}

আপনি আমাদের MainListFragment দেখতে পাচ্ছেন ক্লাস এমনকি CryptocurrencyRepository সম্পর্কেও জানে না অথবা AppDatabase . এটি InjectorUtils ক্লাস থেকে একটি সফলভাবে নির্মিত কারখানা পায়। আসলে এটি এটি করার একটি সহজ উপায়। আমরা এটি থেকে পরিত্রাণ পেতে যাচ্ছি এবং উন্নত নির্ভরতা ইনজেকশনের জন্য কীভাবে ড্যাগার 2 টুল সেটআপ করতে হয় তা শিখতে যাচ্ছি। যদি এই অ্যাপটি কার্যকারিতা এবং কোডে প্রসারিত হয়, তবে আমি সন্দেহ করি না যে আমরা একটি ম্যানুয়াল সমাধানের উপর একটি পেশাদার নির্ভরতা ইনজেকশন ফ্রেমওয়ার্ক ব্যবহার করে খুব দ্রুত সুবিধাগুলি দেখতে শুরু করব৷

তাহলে চলুন InjectorUtils মুছে ফেলি এখনই ক্লাস করুন এবং আমার ক্রিপ্টো কয়েন অ্যাপ সোর্স কোডে কীভাবে ড্যাগার 2 সেটআপ করবেন তা শিখুন।

কোটলিনের সাথে MVVM-এর জন্য নির্ভরতা ইনজেকশন

ভিউ মডেল, অ্যাক্টিভিটি এবং ফ্র্যাগমেন্টের সাথে ড্যাগার 2 কিভাবে সেটআপ করবেন

এখন আমরা মাই ক্রিপ্টো কয়েন অ্যাপ প্রকল্পে ড্যাগার 2 ধাপে ধাপে সেটআপের মধ্য দিয়ে যাব।

শুরু করতে, আপনাকে Kotlin এর নিজস্ব টীকা প্রক্রিয়াকরণ টুল (kapt) সক্ষম করতে হবে। তারপরে বিশেষ ড্যাগার 2 নির্ভরতা যোগ করুন।

আপনি আপনার গ্রেডল ফাইলে এই লাইনগুলি যোগ করে এটি করতে পারেন:

apply plugin: 'kotlin-kapt' // For annotation processing

...

implementation "com.google.dagger:dagger:$versions.dagger"
implementation "com.google.dagger:dagger-android:$versions.dagger"
implementation "com.google.dagger:dagger-android-support:$versions.dagger"
kapt "com.google.dagger:dagger-compiler:$versions.dagger"
kapt "com.google.dagger:dagger-android-processor:$versions.dagger"
মডিউল:অ্যাপ

ক্যাপ্ট প্লাগইন কম্পাইলারকে জাভা এবং কোটলিনের মধ্যে ইন্টারঅপারেবিলিটির জন্য প্রয়োজনীয় স্টাব ক্লাস তৈরি করতে সক্ষম করবে। সুবিধার জন্য আমরা কংক্রিট ড্যাগার 2 সংস্করণটিকে একটি পৃথক গ্রেডল ফাইলে সংজ্ঞায়িত করব, কারণ আমরা এটি আমাদের সমস্ত নির্ভরতার সাথে করি৷

def versions = [:]

versions.dagger = "2.16"

ext.versions = versions

উপলব্ধ সর্বশেষ সংস্করণ খুঁজে পেতে Github এ Dagger 2 এর অফিসিয়াল রিপোজিটরিতে রিলিজগুলি দেখুন৷

এখন, আপনার অ্যাপ্লিকেশন App তৈরি করুন ক্লাস।

আপনার যদি ইতিমধ্যে এই ক্লাস সেট থাকে তবে এটি এড়িয়ে যান। আপনি এটি করার পরে, আমরা এটিকে কিছু সময়ের জন্য রেখে দেব, কিন্তু পরে ফিরে আসব৷

class App : Application() {

    override fun onCreate() {
        super.onCreate()
    }

}

My Crypto Coins অ্যাপের জন্য, আমরা ইতিমধ্যেই অ্যাপ্লিকেশন ক্লাস তৈরি করেছি।

এরপর, আপনার App সক্ষম করতে আপনার ম্যানিফেস্ট ফাইল আপডেট করুন ক্লাস।

আপনি যদি এটি আগে করে থাকেন তবে এটি এড়িয়ে যান৷

<manifest xmlns:android="https://schemas.android.com/apk/res/android"
    package="com.baruckis.mycryptocoins">

    <application
        android:name=".App"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        ...

My Crypto Coins অ্যাপের জন্য, আমরা ইতিমধ্যেই App সেট করেছি আগে ম্যানিফেস্টে ক্লাস।

এখন dependencyinjection নামে একটি নতুন প্যাকেজ তৈরি করা যাক .

এখানে আমরা ড্যাগার ইমপ্লিমেন্টেশন সম্পর্কিত সমস্ত ফাইল রাখতে যাচ্ছি।

তৈরি করুন AppModule ক্লাস মডিউল যা আপনার সমস্ত অ্যাপ্লিকেশন জুড়ে নির্ভরতা প্রদান করবে।

/**
 * AppModule will provide app-wide dependencies for a part of the application.
 * It should initialize objects used across our application, such as Room database, Retrofit, Shared Preference, etc.
 */
@Module(includes = [ViewModelsModule::class])
class AppModule() {

    @Singleton // Annotation informs Dagger compiler that the instance should be created only once in the entire lifecycle of the application.
    @Provides // Annotation informs Dagger compiler that this method is the constructor for the Context return type.
    fun provideContext(app: App): Context = app // Using provide as a prefix is a common convention but not a requirement.

    @Singleton
    @Provides
    fun provideCryptocurrencyRepository(context: Context): CryptocurrencyRepository {
        return CryptocurrencyRepository.getInstance(AppDatabase.getInstance(context).cryptocurrencyDao())
    }
}

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

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

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

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

বস্তুর অন্য একটি উদাহরণ ইতিমধ্যে উপলব্ধ আছে কিনা তা পরীক্ষা করার জন্য আপনাকে বয়লারপ্লেট কোড লিখতে হবে না। কোড তৈরি করার সময় ড্যাগার এই টীকাটির কারণে আপনার জন্য সেই সমস্ত যুক্তি পরিচালনা করবে। লক্ষ্য করুন যে আমাদের AppModule-এ আরেকটি মডিউল ViewModelsModule অন্তর্ভুক্ত রয়েছে। এখন এটি তৈরি করা যাক।

একটি ViewModelsModule তৈরি করুন ক্লাস মডিউল। এই মডিউলটি আপনার সমস্ত অ্যাপ্লিকেশন জুড়ে ViewModels প্রদানের জন্য দায়ী।

/**
 * Will be responsible for providing ViewModels.
 */
@Module
abstract class ViewModelsModule {

    // We'd like to take this implementation of the ViewModel class and make it available in an injectable map with MainViewModel::class as a key to that map.
    @Binds
    @IntoMap
    @ViewModelKey(MainViewModel::class) // We use a restriction on multibound map defined with @ViewModelKey annotation, and if don't need any, we should use @ClassKey annotation provided by Dagger.
    abstract fun bindMainViewModel(mainViewModel: MainViewModel): ViewModel

    @Binds
    @IntoMap
    @ViewModelKey(AddSearchViewModel::class)
    abstract fun bindAddSearchViewModel(addSearchViewModel: AddSearchViewModel): ViewModel

    @Binds
    abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
}

এই মডিউলটি ড্যাগার 2 বৈশিষ্ট্য মানচিত্র মাল্টি বাইন্ডিং ব্যবহার করে। এটি ব্যবহার করে, আমরা আমাদের পছন্দের বস্তুগুলিকে একটি মানচিত্রে অবদান রাখি যা আমাদের অ্যাপের যেকোনো জায়গায় ইনজেকশনযোগ্য হয়ে ওঠে। ড্যাগার টীকা @Binds এর সমন্বয় ব্যবহার করে , @IntoMap এবং আমাদের কাস্টম টীকা @ViewModelKey (এটি আমরা তৈরি করতে যাচ্ছি), আমরা কী MainViewModel::class দিয়ে আমাদের মানচিত্রের ভিতরে একটি এন্ট্রি তৈরি করি এবং মান MainViewModel দৃষ্টান্ত. আমরা কিছু সাধারণ ViewModelFactory এর সাহায্যে নির্দিষ্ট ফ্যাক্টরি আবদ্ধ করি ক্লাস আমাদের এই ক্লাস তৈরি করতে হবে।

একটি কাস্টম টীকা ক্লাস তৈরি করুন ViewModelKey .

/**
 * An annotation class which tells dagger that it can be used to determine keys in multi bound maps.
 */
@MustBeDocumented
@Target(
        AnnotationTarget.FUNCTION,
        AnnotationTarget.PROPERTY_GETTER,
        AnnotationTarget.PROPERTY_SETTER
)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class ViewModelKey(val value: KClass<out ViewModel>) // We might use only those classes which inherit from ViewModel.

এই ক্লাসটি ViewModelsModule-এ ভিউমডেল বাঁধাই করার জন্য ব্যবহৃত হয় . নির্দিষ্ট টীকা @ViewModelKey আমাদের মানচিত্রের কী প্রতিনিধিত্ব করে। আমাদের কী শুধুমাত্র একটি ক্লাস হতে পারে যা ViewModel থেকে উত্তরাধিকারসূত্রে পাওয়া যায় .

ViewModelFactory তৈরি করুন ক্লাস।

/**
 * Factory to auto-generate a Class to Provider Map.
 * We use Provider<T> to create an injectable object at a later time.
 */
@Suppress("UNCHECKED_CAST")
@Singleton
class ViewModelFactory @Inject constructor(private val viewModelsMap: Map<Class<out ViewModel>,
        @JvmSuppressWildcards Provider<ViewModel>>) : ViewModelProvider.Factory {

    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        var creator: Provider<out ViewModel>? = viewModelsMap[modelClass]
        if (creator == null) {
            for (entry in viewModelsMap.entries) {
                if (modelClass.isAssignableFrom(entry.key)) {
                    creator = entry.value
                    break
                }
            }
        }
        if (creator == null) {
            throw IllegalArgumentException("Unknown model class $modelClass")
        }

        try {
            return creator.get() as T
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
    }
}

এই ViewModelFactory একটি ইউটিলিটি ক্লাস যা আপনাকে গতিশীলভাবে ViewModels তৈরি করতে সাহায্য করে। এখানে আপনি একটি যুক্তি হিসাবে তৈরি মানচিত্র প্রদান. create() পদ্ধতি মানচিত্র থেকে সঠিক উদাহরণ বাছাই করতে সক্ষম হবে।

ActivityBuildersModule তৈরি করুন ক্লাস মডিউল।

/**
 * All activities intended to use Dagger @Inject should be listed here.
 */
@Module
abstract class ActivityBuildersModule {

    @ContributesAndroidInjector(modules = [MainListFragmetBuildersModule::class]) // Where to apply the injection.
    abstract fun contributeMainActivity(): MainActivity

    @ContributesAndroidInjector
    abstract fun contributeAddSearchActivity(): AddSearchActivity
}

এই মডিউল আপনার সমস্ত কার্যকলাপ নির্মাণের জন্য দায়ী. এটি AndroidInjector তৈরি করবে এই ক্লাসে সংজ্ঞায়িত সমস্ত কার্যকলাপের জন্য। তারপর বস্তুগুলিকে AndroidInjection.inject(this) ব্যবহার করে কার্যকলাপে ইনজেকশন করা যেতে পারে onCreate-এ কার্যকলাপ জীবনচক্র থেকে ফাংশন. লক্ষ্য করুন যে এই মডিউলটি খণ্ডের জন্য দায়ী আরেকটি পৃথক মডিউলও ব্যবহার করে। আমরা পরবর্তীতে এই মডিউলটি তৈরি করব।

MainListFragmetBuildersModule তৈরি করুন ক্লাস মডিউল।

/**
 * All fragments related to MainActivity intended to use Dagger @Inject should be listed here.
 */
@Module
abstract class MainListFragmetBuildersModule {

    @ContributesAndroidInjector() // Attaches fragment to Dagger graph.
    abstract fun contributeMainListFragment(): MainListFragment
}

এই মডিউলটি MainActivity এর সাথে সম্পর্কিত আপনার সমস্ত টুকরো তৈরি করবে . এটি AndroidInjector তৈরি করবে এই শ্রেণীতে সংজ্ঞায়িত সমস্ত খণ্ডের জন্য। AndroidSupportInjection.inject(this) ব্যবহার করে অবজেক্টগুলিকে ফ্র্যাগমেন্টে ইনজেক্ট করা যেতে পারে onAttach-এ ফ্র্যাগমেন্ট লাইফ সাইকেল থেকে ফাংশন।

AppComponent তৈরি করুন ক্লাস কম্পোনেন্ট।

/**
 * Singleton component interface for the app. It ties all the modules together.
 * The component is used to connect objects to their dependencies.
 * Dagger will auto-generate DaggerAppComponent which is used for initialization at Application.
 */
@Singleton
@Component(
        modules = [
            // AndroidSupportInjectionModule is a class of Dagger and we don't need to create it.
            // If you want to use injection in fragment then you should use AndroidSupportInjectionModule.class else use AndroidInjectionModule.
            AndroidSupportInjectionModule::class,
            AppModule::class,
            ActivityBuildersModule::class
        ]
)
interface AppComponent {

    @Component.Builder // Used for instantiation of a component.
    interface Builder {

        @BindsInstance // Bind our application instance to our Dagger graph.
        fun application(application: App): Builder

        fun build(): AppComponent
    }

    // The application which is allowed to request the dependencies declared by the modules
    // (by means of the @Inject annotation) should be declared here with individual inject() methods.
    fun inject(app: App)
}

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

একটি কম্পোনেন্ট ক্লাস তৈরি করতে আপনাকে ড্যাগার টীকা @Component ব্যবহার করতে হবে . এটি একটি ইনপুট হিসাবে মডিউলগুলির একটি তালিকা নেয়। আরেকটি টীকা @Component.Builder আমাদেরকে উপাদানের সাথে কিছু উদাহরণ আবদ্ধ করার অনুমতি দেয়।

তারপর একটি গ্রাফ অবজেক্ট তৈরি করুন৷

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

এখন একটি Injectable তৈরি করুন ইন্টারফেস।

/**
 * It is just a plain empty marker interface, which tells to automatically inject activities or fragments if they implement it.
 */
interface Injectable

এটি ভবিষ্যতের পদক্ষেপের জন্যও প্রয়োজন হবে। Injectable ইন্টারফেস ক্রিয়াকলাপ বা টুকরা দ্বারা প্রয়োগ করা উচিত যা আমরা স্বয়ংক্রিয়ভাবে ইনজেকশনযোগ্য হতে চাই।

AppInjector নামে একটি নতুন সাহায্যকারী শ্রেণী তৈরি করুন৷ .

/**
 * It is simple helper class to avoid calling inject method on each activity or fragment.
 */
object AppInjector {
    fun init(app: App) {
        // Here we initialize Dagger. DaggerAppComponent is auto-generated from AppComponent.
        DaggerAppComponent.builder().application(app).build().inject(app)

        app.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
            override fun onActivityPaused(activity: Activity) {

            }

            override fun onActivityResumed(activity: Activity) {

            }

            override fun onActivityStarted(activity: Activity) {

            }

            override fun onActivityDestroyed(activity: Activity) {

            }

            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle?) {

            }

            override fun onActivityStopped(activity: Activity) {

            }

            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
                handleActivity(activity)
            }
        })
    }

    private fun handleActivity(activity: Activity) {
        if (activity is HasSupportFragmentInjector || activity is Injectable) {
            // Calling inject() method will cause Dagger to locate the singletons in the dependency graph to try to find a matching return type.
            // If it finds one, it assigns the references to the respective fields.
            AndroidInjection.inject(activity)
        }

        if (activity is FragmentActivity) {
            activity.supportFragmentManager.registerFragmentLifecycleCallbacks(object : FragmentManager.FragmentLifecycleCallbacks() {
                override fun onFragmentCreated(fragmentManager: FragmentManager, fragment: Fragment, savedInstanceState: Bundle?) {
                    if (fragment is Injectable) {
                        AndroidSupportInjection.inject(fragment)
                    }
                }
            }, true)
        }
    }

}

প্রতিটি অ্যাক্টিভিটি বা ফ্র্যাগমেন্টে ইনজেকশন পদ্ধতিতে কল করা এড়াতে এটি একটি সাধারণ সাহায্যকারী শ্রেণী।

এরপর, App সেটআপ করুন ক্লাস যা আমরা ইতিমধ্যেই তৈরি করেছি৷

class App : Application(), HasActivityInjector {

    @Inject // It implements Dagger machinery of finding appropriate injector factory for a type.
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>

    override fun onCreate() {
        super.onCreate()

        // Initialize in order to automatically inject activities and fragments if they implement Injectable interface.
        AppInjector.init(this)

        ...
    }


    // This is required by HasActivityInjector interface to setup Dagger for Activity.
    override fun activityInjector(): AndroidInjector<Activity> = dispatchingAndroidInjector
}

যেহেতু অ্যাপ্লিকেশনটির কার্যক্রম রয়েছে, তাই আমাদের HasActivityInjector বাস্তবায়ন করতে হবে ইন্টারফেস. আপনি যদি DaggerAppComponent এ Android স্টুডিওর দ্বারা কল করা একটি ত্রুটি দেখতে পান , কারণ আপনি একটি নতুন ফাইল তৈরি করেননি, যেমনটি পূর্ববর্তী ধাপে উল্লেখ করা হয়েছিল৷

সুতরাং, MainActivity সেটআপ করুন প্রধান ভিউমডেল ফ্যাক্টরিতে ইনজেকশন করতে এবং ফ্র্যাগমেন্ট ইনজেকশনের জন্য একটি সমর্থন যোগ করতে।

// To support injecting fragments which belongs to this activity we need to implement HasSupportFragmentInjector.
// We would not need to implement it, if our activity did not contain any fragments or the fragments did not need to inject anything.
class MainActivity : AppCompatActivity(), HasSupportFragmentInjector {

    @Inject
    lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>

    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory
    private lateinit var mainViewModel: MainViewModel


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

        // Obtain ViewModel from ViewModelProviders, using this activity as LifecycleOwner.
        mainViewModel = ViewModelProviders.of(this, viewModelFactory).get(MainViewModel::class.java)

        ...
    }

    ...

    override fun supportFragmentInjector(): AndroidInjector<Fragment> = dispatchingAndroidInjector

    ...
}

কারণ আমাদের ক্রিয়াকলাপে শিশুর অংশ রয়েছে আমাদের HasSupportFragmentInjector বাস্তবায়ন করতে হবে ইন্টারফেস. আমাদের এটিও দরকার কারণ আমরা আমাদের টুকরোগুলিতে ইনজেকশন তৈরি করার পরিকল্পনা করি। এটা কিভাবে ইনজেকশন করা হয় সে সম্পর্কে আমাদের কার্যকলাপ জানা উচিত নয়। আমরা AndroidInjection.inject(this) ব্যবহার করি onCreate() ওভাররাইডিংয়ের ভিতরে কোড লাইন পদ্ধতি।

inject() কল করা হচ্ছে মেথডের কারণে ড্যাগার 2 নির্ভরতা গ্রাফে এককটন সনাক্ত করতে পারে যাতে একটি মিল রিটার্ন টাইপ খুঁজে বের করার চেষ্টা করা হয়। তবে আমাদের এখানে কোনো কোড লিখতে হবে না কারণ এটি আমাদের জন্য পূর্বে তৈরি করা AppInjector দ্বারা করা হয়েছে সহায়ক ক্লাস যা আমরা আমাদের অ্যাপ্লিকেশন ক্লাসের মধ্যে শুরু করেছি।

তারপর, MainListFragment সেটআপ করুন মূল ভিউমডেল ফ্যাক্টরিতে ইনজেকশন দিতে।

/**
 * A placeholder fragment containing a simple view.
 */
class MainListFragment : Fragment(), Injectable {

    ...

    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory
    private lateinit var viewModel: MainViewModel

    ...

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

        ...
        subscribeUi(activity!!)
    }

    ...

    private fun subscribeUi(activity: FragmentActivity) {

        // Obtain ViewModel from ViewModelProviders, using parent activity as LifecycleOwner.
        viewModel = ViewModelProviders.of(activity, viewModelFactory).get(MainViewModel::class.java)
        
        ...

    }

}

ক্রিয়াকলাপের অনুরূপ, যদি আমরা আমাদের খণ্ডটি ইনজেক্টযোগ্য হতে চাই, তবে তার onAttach এ পদ্ধতি আমাদের AndroidSupportInjection.inject(this) কোড লিখতে হবে . কিন্তু আবার এটি AppInjector দ্বারা করা একটি কাজ সাহায্যকারী, তাই আমরা এটি এড়িয়ে যেতে পারি। শুধু লক্ষ্য করুন যে আমাদের Injectable যোগ করতে হবে ইন্টারফেস যা আমরা সাহায্যকারীর কাজ করার জন্য আগে তৈরি করেছি।

অভিনন্দন, আমরা My Crypto Coins অ্যাপ প্রকল্পে Dagger 2 বাস্তবায়ন করেছি। অবশ্যই এই নিবন্ধটি সরাসরি আপনার অ্যাপে ড্যাগার 2 স্থাপন করার জন্য একটি দ্রুত নির্দেশিকা, তবে এটির গভীর কভারেজ নয়। আমি সুপারিশ করছি যে আপনি যদি মৌলিক বিষয়গুলি হারিয়ে ফেলেন তাহলে আপনি এই বিষয়ে গবেষণা চালিয়ে যান৷

ভাণ্ডার

GitHub-এ আপডেট করা “Kriptofolio” (পূর্বে “My Crypto Coins”) অ্যাপের সোর্স কোড দেখুন।

GitHub-এ উৎস দেখুন

অ্যাচিউ! পড়ার জন্য ধন্যবাদ! আমি মূলত এই পোস্টটি আমার ব্যক্তিগত ব্লগ www.baruckis.com-এর জন্য 7 অক্টোবর, 2018-এ প্রকাশ করেছি।


  1. এই আইফোন অ্যাপস দিয়ে কিভাবে আপনার ফ্লাইট চেক করবেন

  2. আপনার পিসিতে টেলিগ্রাম কীভাবে ব্যবহার করবেন

  3. আইফোনে ফিঙ্গারপ্রিন্ট বা ফেসআইডি দিয়ে কীভাবে আপনার হোয়াটসঅ্যাপ লক করবেন

  4. কিভাবে আপনার অ্যান্ড্রয়েড ফোন দিয়ে বন্ধুর আইফোন ট্র্যাক করবেন