今天要接續上次所講解的Dagger2繼續延伸,而今天要介紹的是@Singleton單例的用法和@Scope的用法,下面我們講解完這兩個註解後,就來用一個簡單的抓資料存資料範例,而這個範例會使用之前講解的 Retrofit和SharedPreferences 合併!!
下面是範例建立的各個class和分類。

這邊我建立了兩個Scope分別是CallAnntation和MainAnntation。
看到下面的註解這三個是綁在一起的。
給CallActivity使用。
@Scope
@Documented
@Retention(RUNTIME)
public @interface CallAnntation {
}
給MainActivity使用。
@Scope
@Documented
@Retention(RUNTIME)
public @interface MainAnntation {
}
抓取資料的方法。
public interface ApiService {
    //登入Token資料
    @POST("auth/login")
    Call<LoginResponse> login(@Body LoginResponse loginResponse);
}
要抓取的資料。
public class LoginResponse {
    private String token;
    private String account;
    private String password;
    
    //這裡是要讓上方抓API時需要帳號密碼,所以這裡我建立一個方法把帳密包起來,讓上方可以用@Body拿取帳密。
    public  LoginResponse(String account,String password){
        this.account=account;
        this.password=password;
    }
    /**--------------get方法---------------------*/
    public String getToken() {
        return token;
    }
}
用來提供"建立Retrofit"的實例化,而且因為這裡使用單例的方法,所以自每次叫API都不會再build一次Retrofit。
public class APIModule {
    private ApiServise apiServise;
    private Retrofit retrofit;
   
    @Singleton
    @Provides
    ApiServise providesApiservise(Retrofit retrofit){
        return apiServise=retrofit.create(ApiServise.class);
    }
    @Singleton
    @Provides
    Retrofit providesClient(){
        return retrofit = new Retrofit.Builder()
                .baseUrl("https://jsonplaceholder.typicode.com")
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }
這一個Module是用來實例化"LoginData"這一個class。
@Module
public class ShpfModule {
    @Singleton
    @Provides
    LoginData provicesLoginData(){
        return new LoginData();
    }
}
這裡是讓Application和要使用的主件(Module)建立橋樑。
//加上單例
@Singleton
@Component(modules = {ApiModule.class, ShpfModule.class})
public interface ApplicationComponent {
    void inject(MyApplication application);
    /**等等會看到其他的Component想要dependencies這一個Component,
    並且它們想使用這個Component所連接的Module裡實例的方法時,就必
    須讓要使用的方法暴露出來。*/
    ApiService providesApiService();
    LoginData provicesLoginData();
}
用來連接 CallComponen和它要用的主件。
//這邊加入了先前設定的@Scope,代表這一個Component只給有註解@CallAnntation的頁面使用
@CallAnntation
//這裡用的就是dependencies不同於modules,是用來依賴於其他的Componen
@Component(dependencies =ApplicationComponent.class)
public interface CallComponent {
    void inject(CallActivity callActivity);
}
用來連接 MainComponent和它要用的主件。
//跟上面一樣,這一個Component只給有註解@MainAnntation的頁面使用
@MainAnntation
//一樣的是用來依賴於ApplicationComponent的
@Component(dependencies = {ApplicationComponent.class})
public interface MainComponent {
    void inject(MainActivity mainActivity);
}
這裡是實作SharedPreferences的地方,這裡之前講解過就快速帶過。
public class LoginData {
    private static String TOKEN="token";
    private SharedPreferences shpf;
    private Context context;
    /**MODE_PRIVATE 只允許該APP存取
     MODE_WORLD_READABLE 所有APP都能讀取
     MODE_WORLD_WRITEABLE 所有APP都能存取、寫入
     MODE_MULTI_PROCESS 允許多個process 同時存取*/
    public void getShpf(Context context){
        this.context=context;
        shpf=this.context.getSharedPreferences(String.valueOf(R.string.app_name), Context.MODE_PRIVATE);
    }
    //存取TOKEN
    public void setToken(String token){
        shpf.edit().putString(TOKEN,token).apply();
    }
    //拿取TOKEN
    public String getToken(){
        return shpf.getString(TOKEN,"");
    }
}
用來實現單例模式。
public class MyApplication extends Application {
    //單利模式
    private static MyApplication instance;
    private static ApplicationComponent apiService;
    private static ApplicationComponent loginData;
    
    @Override
    public void onCreate(){
        super.onCreate();
        instance=this;
        //builder出DaggerApplicationComponent,並注入到此。
        apiService =DaggerApplicationComponent.builder().apiModule(new ApiModule()).build();
        apiService.inject(this);
        //builder出DaggerApplicationComponent,並將注入到此。
        loginData=DaggerApplicationComponent.builder().shpfModule(new ShpfModule()).build();
        loginData.inject(this);
    }
    
    public static MyApplication getInstance(){
        // 第一次被呼叫的時候再建立物件
        if(instance==null)
            instance=new MyApplication();
        return instance;
    }
    //建立getApiService方法
    public ApplicationComponent getApiService(){
        return apiService;
    }
    //建立getLoginData方法
    public ApplicationComponent getLoginData(){
        return loginData;
    }
}
public class MainActivity extends AppCompatActivity {
    //設定context
    private Context context = this;
    ApiService apiService;
    //把依賴注入
    @Inject
    ApiService apiService;
    @Inject
    LoginData loginData;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }
    public void init(){
        //
        DaggerMainComponent.builder()
                            .applicationComponent(MyApplication.getInstance().getApiService())
                            .build()
                            .inject(this);
        DaggerMainComponent.builder()
                            .applicationComponent(MyApplication.getInstance().getLoginData())
                            .build()
                            .inject(this);
                            
        apiService=apiClient.getApiService();
        //把context傳入loginData。
        loginData.getShpf(context);
    }
    按下"Button"抓取API
    public void buttonClick(View view){
        //呼叫API,並把帳密傳入
        apiService.login(new LoginResponse("e1001","e1001"))
                .enqueue(new Callback<LoginResponse>() {
            @Override
            public void onResponse(Call<LoginResponse> call, Response<LoginResponse> response) {
                //把API存入SharedPreferences
                loginData.setToken(response.body().getToken());
                //判斷是否抓取成功
                if(response.body()!=null)
                    Toast.makeText(context,"抓取資料成功",Toast.LENGTH_SHORT);
            }
            @Override
            public void onFailure(Call<LoginResponse> call, Throwable t) {
            }
        });
    }
    //按下"Button"跳到CallActivity
    public void nextPage(View view){
        Intent intent = new Intent(MainActivity.this,CallActivity.class);
        startActivity(intent);
    }
}
               按下抓取資料                                         按下拿取資料
  