অ্যান্ড্রয়েড প্রকল্পে স্ক্র্যাচ থেকে কীভাবে ডাগার নির্ভরতা ইনজেকশন সেট আপ করবেন?


100

কীভাবে ডগার ব্যবহার করবেন? আমার অ্যান্ড্রয়েড প্রকল্পে কাজ করার জন্য ড্যাগার কীভাবে কনফিগার করবেন?

আমি আমার অ্যান্ড্রয়েড প্রকল্পে ডগার ব্যবহার করতে চাই, তবে আমি এটি বিভ্রান্তিকর মনে করি।

সম্পাদনা: ডাগার 2 2015 04 15 এর পরেও বাইরে, এবং এটি আরও বিভ্রান্তিকর!

[এই প্রশ্নটি একটি "স্টাব" যার উপরে আমি ডাগার 1 সম্পর্কে আরও শিখতে এবং ডাগার 2 সম্পর্কে আরও জানার সাথে সাথে আমার উত্তরটিতে যুক্ত করছি। এই প্রশ্নটি "প্রশ্ন" না দিয়ে গাইডের বেশি]]


এছাড়াও দেখুন: stackoverflow.com/a/40546157/2413303
EpicPandaForce

এটি ভাগ করে নেওয়ার জন্য ধন্যবাদ। ভিউমোডেল ক্লাস কীভাবে ইনজেক্ট করবেন সে সম্পর্কে আপনার কি জ্ঞান আছে? আমার ভিউমোডেল ক্লাসটি কোনও @ সহায়ক তালিকাভুক্ত না হলেও এটির নির্ভরতা যা ডাগার গ্রাফ দ্বারা সরবরাহ করা যেতে পারে?
অ্যান্ড্রয়েডদেভ

1
নিশ্চিত, দেখতে stackoverflow.com/questions/60884402/...
EpicPandaForce

আরও একটি প্রশ্ন, ডাগার 2 এর সাথে, কী কোনও অবজেক্ট থাকা সম্ভব এবং এটির রেফারেন্স ViewModelএবং দ্বারা ভাগ করা যায় PageKeyedDataSource? আমি যেমন RxJava2 ব্যবহার করি এবং উভয় শ্রেণীর দ্বারা কমপোজাইটডিস্পোজেবলকে ভাগ করে নিতে চাই এবং ব্যবহারকারীরা ব্যাক বোতামটি টিপলে আমি ডিসপোজেবল অবজেক্টটি সাফ করতে চাই। : আমি এখানে জোড়া ক্ষেত্রে haved stackoverflow.com/questions/62595956/...
AndroidDev

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

উত্তর:


193

ডাগার ২.x এর জন্য গাইড (সংশোধিত সংস্করণ)) :

পদক্ষেপগুলি নিম্নলিখিত:

1.) যোগ Daggerআপনার টু build.gradleফাইলগুলি:

  • শীর্ষ স্তরের বিল্ড.gradle :

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.0'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' //added apt for source code generation
    }
}

allprojects {
    repositories {
        jcenter()
    }
}
  • অ্যাপ্লিকেশন স্তর বিল্ড.gradle :

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt' //needed for source code generation

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.2"

    defaultConfig {
        applicationId "your.app.id"
        minSdkVersion 14
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        debug {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    apt 'com.google.dagger:dagger-compiler:2.7' //needed for source code generation
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:24.2.1'
    compile 'com.google.dagger:dagger:2.7' //dagger itself
    provided 'org.glassfish:javax.annotation:10.0-b28' //needed to resolve compilation errors, thanks to tutplus.org for finding the dependency
}

২) আপনার AppContextModuleশ্রেণি তৈরি করুন যা নির্ভরতা সরবরাহ করে।

@Module //a module could also include other modules
public class AppContextModule {
    private final CustomApplication application;

    public AppContextModule(CustomApplication application) {
        this.application = application;
    }

    @Provides
    public CustomApplication application() {
        return this.application;
    }

    @Provides 
    public Context applicationContext() {
        return this.application;
    }

    @Provides
    public LocationManager locationService(Context context) {
        return (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
    }
}

৩)AppContextComponent ইনজেকশনযোগ্য ক্লাসগুলি পেতে ইন্টারফেস সরবরাহ করে এমন শ্রেণী তৈরি করুন ।

public interface AppContextComponent {
    CustomApplication application(); //provision method
    Context applicationContext(); //provision method
    LocationManager locationManager(); //provision method
}

৩.১।) আপনি কীভাবে একটি বাস্তবায়ন দিয়ে একটি মডিউল তৈরি করবেন:

@Module //this is to show that you can include modules to one another
public class AnotherModule {
    @Provides
    @Singleton
    public AnotherClass anotherClass() {
        return new AnotherClassImpl();
    }
}

@Module(includes=AnotherModule.class) //this is to show that you can include modules to one another
public class OtherModule {
    @Provides
    @Singleton
    public OtherClass otherClass(AnotherClass anotherClass) {
        return new OtherClassImpl(anotherClass);
    }
}

public interface AnotherComponent {
    AnotherClass anotherClass();
}

public interface OtherComponent extends AnotherComponent {
    OtherClass otherClass();
}

@Component(modules={OtherModule.class})
@Singleton
public interface ApplicationComponent extends OtherComponent {
    void inject(MainActivity mainActivity);
}

সাবধানতা:: আপনাকে মডিউলটির উপর @Scopeটিকা (যেমন @Singletonবা @ActivityScope) সরবরাহ করতে হবে@Provides আপনার উত্পন্ন উপাদান মধ্যে একটি বিশ্লেষণ করা প্রদানকারী পেতে সটীক পদ্ধতি, অন্যথায় এটি unscoped হবে, এবং আপনি একটি নতুন দৃষ্টান্ত প্রতিটি সময় আপনি উদ্বুদ্ধ পাবেন।

৩.২।) একটি অ্যাপ্লিকেশন-স্কোপযুক্ত উপাদান তৈরি করুন যা আপনাকে কী ইনজেকশন করতে পারে তা নির্দিষ্ট করে (এটি injects={MainActivity.class}ড্যাজার ১.x এর মতোই ):

@Singleton
@Component(module={AppContextModule.class}) //this is where you would add additional modules, and a dependency if you want to subscope
public interface ApplicationComponent extends AppContextComponent { //extend to have the provision methods
    void inject(MainActivity mainActivity);
}

৩.৩।) আপনি যে কনস্ট্রাক্টরের মাধ্যমে নিজে তৈরি করতে পারেন এবং যেটি ব্যবহার করে নতুন সংজ্ঞা দিতে চান না তার @Moduleজন্য (উদাহরণস্বরূপ, আপনি প্রয়োগের ধরণের পরিবর্তনের পরিবর্তে বিল্ড ফ্লেভারগুলি ব্যবহার করেন), আপনি @Injectটীকাযুক্ত কনস্ট্রাক্টর ব্যবহার করতে পারেন ।

public class Something {
    OtherThing otherThing;

    @Inject
    public Something(OtherThing otherThing) {
        this.otherThing = otherThing;
    }
}

এছাড়াও, আপনি যদি @Injectকনস্ট্রাক্টর ব্যবহার করেন তবে আপনি স্পষ্টভাবে কল না করেই ফিল্ড ইঞ্জেকশনটি ব্যবহার করতে পারেন component.inject(this):

public class Something {
    @Inject
    OtherThing otherThing;

    @Inject
    public Something() {
    }
}

এইগুলো @Inject কনস্ট্রাক্টর ক্লাসগুলি মডিউলে স্পষ্টভাবে নির্দিষ্ট না করে একই স্কোপের অংশে স্বয়ংক্রিয়ভাবে যুক্ত করা হয়।

একটি @Singletonস্কোপযুক্ত @Injectকনস্ট্রাক্টর ক্লাস @Singletonস্কোপযুক্ত উপাদানগুলিতে দেখা যাবে ।

@Singleton // scoping
public class Something {
    OtherThing otherThing;

    @Inject
    public Something(OtherThing otherThing) {
        this.otherThing = otherThing;
    }
}

3.4।) আপনি প্রদত্ত ইন্টারফেসের জন্য একটি নির্দিষ্ট বাস্তবায়ন সংজ্ঞায়িত করার পরে, এরকম:

public interface Something {
    void doSomething();
}

@Singleton
public class SomethingImpl {
    @Inject
    AnotherThing anotherThing;

    @Inject
    public SomethingImpl() {
    }
}

আপনার সাথে ইন্টারফেসে নির্দিষ্ট প্রয়োগটি "বাঁধাই" করতে হবে @Module

@Module
public class SomethingModule {
    @Provides
    Something something(SomethingImpl something) {
        return something;
    }
}

ডাগার ২.৪ এর থেকে এটির জন্য একটি সংক্ষিপ্ত হাত নিম্নরূপ:

@Module
public abstract class SomethingModule {
    @Binds
    abstract Something something(SomethingImpl something);
}

৪)Injector আপনার অ্যাপ্লিকেশন-স্তরের উপাদানটি পরিচালনা করার জন্য একটি শ্রেণী তৈরি করুন (এটি একচেটিয়া প্রতিস্থাপন করে ObjectGraph)

(দ্রষ্টব্য: এপিটি ব্যবহার Rebuild Projectকরে DaggerApplicationComponentবিল্ডার শ্রেণি তৈরি করতে )

public enum Injector {
    INSTANCE;

    ApplicationComponent applicationComponent;

    private Injector(){
    }

    static void initialize(CustomApplication customApplication) {
        ApplicationComponent applicationComponent = DaggerApplicationComponent.builder()
           .appContextModule(new AppContextModule(customApplication))
           .build();
        INSTANCE.applicationComponent = applicationComponent;
    }

    public static ApplicationComponent get() {
        return INSTANCE.applicationComponent;
    }
}

৫) আপনার CustomApplicationক্লাস তৈরি করুন

public class CustomApplication
        extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Injector.initialize(this);
    }
}

6.)CustomApplication আপনার যোগ করুন AndroidManifest.xml

<application
    android:name=".CustomApplication"
    ...

7.) আপনার ক্লাস ইনজেক্ট করুনMainActivity

public class MainActivity
        extends AppCompatActivity {
    @Inject
    CustomApplication customApplication;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Injector.get().inject(this);
        //customApplication is injected from component
    }
}

8) উপভোগ করুন!

+1।) আপনি Scopeআপনার উপাদানগুলির জন্য নির্দিষ্ট করতে পারেন যা দিয়ে আপনি ক্রিয়াকলাপ স্তরের স্কোপযুক্ত উপাদান তৈরি করতে পারেন । সাবস্কোপগুলি আপনাকে নির্ভরশীলতা সরবরাহ করতে দেয় যা পুরো অ্যাপ্লিকেশন জুড়ে কেবলমাত্র আপনাকে প্রদত্ত সাবস্কোপের জন্য প্রয়োজন। সাধারণত, প্রতিটি ক্রিয়াকলাপ এই সেটআপটির সাথে নিজস্ব মডিউল পায়। দয়া করে নোট করুন যে কোনও স্কোপযুক্ত সরবরাহকারীর উপস্থিতি রয়েছে প্রতি উপাদান হিসাবে যার অর্থ সেই ক্রিয়াকলাপের উদাহরণটি ধরে রাখতে, উপাদানটি নিজেই কনফিগারেশন পরিবর্তনে বেঁচে থাকতে পারে। উদাহরণস্বরূপ, এটি মাধ্যমে বেঁচে থাকতে পারেonRetainCustomNonConfigurationInstance() বা মর্টার স্কোপের ।

সাবস্কোপিং সম্পর্কিত আরও তথ্যের জন্য, গুগল দ্বারা গাইড দেখুন । এছাড়াও দয়া করে বিধানের পদ্ধতি এবং উপাদানগুলির নির্ভরতা বিভাগ সম্পর্কেও এই সাইটটি দেখুন ) এবং এখানে

একটি কাস্টম সুযোগ তৈরি করতে, আপনাকে অবশ্যই স্কোপ কোয়ালিফায়ার টিকাটি নির্দিষ্ট করতে হবে:

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface YourCustomScope {
}

সাবস্কোপ তৈরি করতে আপনাকে আপনার উপাদানটির সুযোগটি নির্দিষ্ট করতে হবে এবং ApplicationComponentএর নির্ভরতা হিসাবে নির্দিষ্ট করতে হবে । স্পষ্টতই আপনাকে মডিউল সরবরাহকারীর পদ্ধতিতেও সাবস্কোপ নির্দিষ্ট করতে হবে।

@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
        extends ApplicationComponent {
    CustomScopeClass customScopeClass();

    void inject(YourScopedClass scopedClass);
}

এবং

@Module
public class CustomScopeModule {
    @Provides
    @YourCustomScope
    public CustomScopeClass customScopeClass() {
        return new CustomScopeClassImpl();
    }
}

দয়া করে মনে রাখবেন যে কেবলমাত্র একটি স্কোপযুক্ত উপাদান নির্ভরতা হিসাবে নির্দিষ্ট করা যেতে পারে। একেবারে ঠিক ভাবেন যে জাভাতে একাধিক উত্তরাধিকার কীভাবে সমর্থিত নয়।

+2।) সম্পর্কে@Subcomponent : মূলত, একটি স্কোপড@Subcomponent একটি উপাদান নির্ভরতা প্রতিস্থাপন করতে পারে; তবে টিকা প্রসেসরের দ্বারা সরবরাহ করা কোনও বিল্ডার ব্যবহার না করে আপনাকে কোনও উপাদান ফ্যাক্টরি পদ্ধতি ব্যবহার করতে হবে।

আমার স্নাতকের:

@Singleton
@Component
public interface ApplicationComponent {
}

@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
        extends ApplicationComponent {
    CustomScopeClass customScopeClass();

    void inject(YourScopedClass scopedClass);
}

এটি হয়ে:

@Singleton
@Component
public interface ApplicationComponent {
    YourCustomScopedComponent newYourCustomScopedComponent(CustomScopeModule customScopeModule);
}

@Subcomponent(modules={CustomScopeModule.class})
@YourCustomScope
public interface YourCustomScopedComponent {
    CustomScopeClass customScopeClass();
}

এবং এই:

DaggerYourCustomScopedComponent.builder()
      .applicationComponent(Injector.get())
      .customScopeModule(new CustomScopeModule())
      .build();

এটি হয়ে:

Injector.INSTANCE.newYourCustomScopedComponent(new CustomScopeModule());

+3।): দয়া করে ডাগার 2 সম্পর্কিত অন্যান্য স্ট্যাক ওভারফ্লো প্রশ্নগুলিও পরীক্ষা করে দেখুন, তারা প্রচুর তথ্য সরবরাহ করে। উদাহরণস্বরূপ, আমার বর্তমান ডাগার 2 কাঠামো এই উত্তরে নির্দিষ্ট করা আছে ।

ধন্যবাদ

এ গাইড করার জন্য আপনাকে ধন্যবাদ গিটহাব , TutsPlus , জো স্টিল , Froger এমসিএস এবং গুগল

এছাড়াও এই পদক্ষেপে মাইগ্রেশন গাইড পদক্ষেপের জন্য আমি এই পোস্টটি লেখার পরে পেয়েছি।

এবং ক্যারিল দ্বারা সুযোগ ব্যাখ্যা জন্য ।

এমনকি সরকারী নথিতে আরও তথ্য ।


আমি বিশ্বাস করি আমরা ডাগার অ্যাপ্লিকেশন সংস্থার বাস্তবায়ন অনুপস্থিত
থানাসিস কাপেলোনিস

1
@ থানাসিসক্যাপেলোনিসটি DaggerApplicationComponentএপিটি তৈরির সময় স্বয়ংক্রিয়ভাবে তৈরি হয়েছে তবে আমি এটি যুক্ত করব।
এপিকপান্ডাফোরস্

1
আমার কাস্টম অ্যাপ্লিকেশনটি প্যাকেজের আওতার বাইরে ছিল এবং সবকিছুই নিখুঁতভাবে কাজ করে বলে আমাকে কেবল ইনজেক্টর.ইনটিইলাইজ অ্যাপ্লিকেশনস কম্পোনেন্টটি পদ্ধতিটি সর্বজনীন করতে হয়েছিল! ধন্যবাদ!
জুয়ান সরভিয়া

2
কিছুটা দেরি হলেও সম্ভবত নিম্নলিখিত উদাহরণগুলি যে কাউকে সহায়তা করবে: github.com/dawidgdanski/android-compass-api github.com/dawidgdanski/Bakery
dawid gdanski

1
যদি আপনি 'সতর্কতা পান: টীকাগুলি প্রসেসিংয়ের জন্য বেমানান প্লাগইন ব্যবহার করছেন: অ্যান্ড্রয়েড-অ্যাপ্লিকেশন। এর ফলে একটি অপ্রত্যাশিত আচরণ হতে পারে '' পদক্ষেপ 1-এ, 'com.google.dagger: dagger-compiler: 2.7' এনেটেশনপ্রসেসর 'com.google.dagger: dagger-compiler: 2.7' পরিবর্তন করুন এবং সমস্ত অ্যাপ্লিকেশন কনফিগারেশন সরান। বিটবুককেট.আরএইচভিজার
অ্যান্ড্রয়েড-

11

ড্যাজারের জন্য গাইড 1.x :

পদক্ষেপগুলি নিম্নলিখিত:

1.) যোগ Daggerকরতে build.gradleনির্ভরতা জন্য ফাইল

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    ...
    compile 'com.squareup.dagger:dagger:1.2.2'
    provided 'com.squareup.dagger:dagger-compiler:1.2.2'

এছাড়াও, packaging-optionসম্পর্কে একটি ত্রুটি রোধ করতে যুক্ত করুন duplicate APKs

android {
    ...
    packagingOptions {
        // Exclude file to avoid
        // Error: Duplicate files during packaging of APK
        exclude 'META-INF/services/javax.annotation.processing.Processor'
    }
}

২) Injectorপরিচালনা করার জন্য একটি শ্রেণি তৈরি করুন ObjectGraph

public enum Injector
{
    INSTANCE;

    private ObjectGraph objectGraph = null;

    public void init(final Object rootModule)
    {

        if(objectGraph == null)
        {
            objectGraph = ObjectGraph.create(rootModule);
        }
        else
        {
            objectGraph = objectGraph.plus(rootModule);
        }

        // Inject statics
        objectGraph.injectStatics();

    }

    public void init(final Object rootModule, final Object target)
    {
        init(rootModule);
        inject(target);
    }

    public void inject(final Object target)
    {
        objectGraph.inject(target);
    }

    public <T> T resolve(Class<T> type)
    {
        return objectGraph.get(type);
    }
}

৩) RootModuleআপনার ভবিষ্যতের মডিউলগুলি একসাথে লিঙ্ক করতে একটি তৈরি করুন । দয়া করে নোট করুন যে আপনাকে অবশ্যই injectsপ্রতিটি শ্রেণি নির্দিষ্ট করতে হবে যেখানে আপনি @Injectটীকাটি ব্যবহার করবেন কারণ অন্যথায় ড্যাজার ছুড়ে দেয় RuntimeException

@Module(
    includes = {
        UtilsModule.class,
        NetworkingModule.class
    },
    injects = {
        MainActivity.class
    }
)
public class RootModule
{
}

৪) আপনার রুটে নির্দিষ্ট করা মডিউলগুলির মধ্যে আপনার কাছে অন্যান্য উপ-মডিউল রয়েছে সেগুলির জন্য মডিউলগুলি তৈরি করুন:

@Module(
    includes = {
        SerializerModule.class,
        CertUtilModule.class
    }
)
public class UtilsModule
{
}

৫) লিফ পাতার মডিউলগুলি তৈরি করুন যা কনস্ট্রাক্টর পরামিতি হিসাবে নির্ভরতা প্রাপ্ত করে। আমার ক্ষেত্রে, কোনও বিজ্ঞপ্তি নির্ভরতা ছিল না, তাই ডাগার এটি সমাধান করতে পারে কিনা তা আমি জানি না, তবে আমি এটি অসম্ভব বলে মনে করি। কনস্ট্রাক্টর প্যারামিটারগুলি অবশ্যই মডিউলটিতে ডাগার দ্বারা সরবরাহ complete = falseকরতে হবে , যদি আপনি নির্দিষ্ট করেন তবে এটি অন্যান্য মডিউলগুলিতেও হতে পারে।

@Module(complete = false, library = true)
public class NetworkingModule
{
    @Provides
    public ClientAuthAuthenticator providesClientAuthAuthenticator()
    {
        return new ClientAuthAuthenticator();
    }

    @Provides
    public ClientCertWebRequestor providesClientCertWebRequestor(ClientAuthAuthenticator clientAuthAuthenticator)
    {
        return new ClientCertWebRequestor(clientAuthAuthenticator);
    }

    @Provides
    public ServerCommunicator providesServerCommunicator(ClientCertWebRequestor clientCertWebRequestor)
    {
        return new ServerCommunicator(clientCertWebRequestor);
    }
}

6.) প্রসারিত Applicationএবং আরম্ভ Injector

@Override
public void onCreate()
{
    super.onCreate();
    Injector.INSTANCE.init(new RootModule());
}

7.) আপনার MainActivity, onCreate()পদ্ধতিতে ইনজেক্টর কল ।

@Override
protected void onCreate(Bundle savedInstanceState)
{
    Injector.INSTANCE.inject(this);
    super.onCreate(savedInstanceState);
    ...

৮) আপনার ব্যবহার @Injectকরুন MainActivity

public class MainActivity extends ActionBarActivity
{  
    @Inject
    public ServerCommunicator serverCommunicator;

...

আপনি যদি ত্রুটিটি পান তবে no injectable constructor foundনিশ্চিত হয়ে নিন যে আপনি @Providesটীকাগুলি ভোলেন নি।


এই উত্তরটি আংশিকভাবে উত্পন্ন কোডের উপর ভিত্তি করে Android Bootstrap। সুতরাং, এটি বের করার জন্য তাদের কাছে কৃতিত্ব। সমাধান ব্যবহার করে Dagger v1.2.2
এপিকপান্ডাফোরস

3
এর সুযোগটি অন্যথায় dagger-compilerহওয়া উচিত providedএটি প্রয়োগের অন্তর্ভুক্ত হবে এবং এটি জিপিএল লাইসেন্সের আওতায় রয়েছে।
ডেনিস নাইজিয়াভ

@ এডিস্কনিয়াজেভ ওহ, আমি জানি না! সতর্ক থাকুন জন্য ধন্যবাদ!
এপিকপান্ডাফোরস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.