Nizar Abdelhedi
Nizar Abdelhedi

Reputation: 1

try to get Retrofit with dependency injection

I am trying to get List of job leads in my android application.I use Dagger 2 with Retrofit and OkHttp,But I get this error

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.../com...AccueilActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object retrofit2.Retrofit.create(java.lang.Class)' on a null object reference
                                                                      at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3319)
                                                                      at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3415)
                                                                      at android.app.ActivityThread.access$1100(ActivityThread.java:229)
                                                                      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1821)
                                                                      at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                      at android.os.Looper.loop(Looper.java:148)
                                                                      at android.app.ActivityThread.main(ActivityThread.java:7325)
                                                                      at java.lang.reflect.Method.invoke(Native Method)
                                                                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
                                                                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
                                                                   Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object retrofit2.Retrofit.create(java.lang.Class)' on a null object reference

I create two components ApplicationComponent, NetComponent

@Singleton
@Component(modules = {NetModule.class,ApplicationModule.class})
public interface NetComponent {
    void inject(AppCompatActivity activity);
    void inject(Fragment fragment);
}

and Tow modules ApplicationModule, NetModule

import android.app.Application;
import dagger.Module;
import dagger.Provides;
import okhttp3.Cache;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import javax.inject.Singleton;
    
@Module
public class NetModule {
    String baseUrl;
    
    public NetModule(String baseUrl) {
        this.baseUrl = baseUrl;
    }
    
    @Provides
    @Singleton
    Cache provideOkHttpCache(Application application) {
        int cacheSize = 10 * 1024 * 1024; // 10 MiB
        Cache cache = new Cache(application.getCacheDir(), cacheSize);
        return cache;
    }
    
    @Provides
    @Singleton
    Gson provideGson() {
        GsonBuilder gsonBuilder = new GsonBuilder();
        gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
        return gsonBuilder.create();
    }

    @Provides
    @Singleton
    OkHttpClient provideOkHttpClient(Cache cache) {
        OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();
        return client;
    }
    
    @Provides
    @Singleton
    public Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {
        Retrofit retrofit = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .baseUrl(baseUrl)
                .client(okHttpClient)
                .build();
        return retrofit;
    }
}

I try to inject the Retrofit in my Activity but i get null exception

public class AccueilActivity extends AppCompatActivity {
    ArrayList<MenuItem> menu = new ArrayList<>();   
    @Inject
    Retrofit retrofit;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_accueil);
        ((AndroidApplication) getApplicationContext()).getNetComponent().inject(this);
        Call<List<JobLeads>> jobLeadList = retrofit.create(GetJobLeads.class).getJobLeads();
        jobLeadList.enqueue(new Callback<List<JobLeads>>() {
                @Override
                public void success(Result<List<JobLeads>> result) {
                }

                @Override
                public void failure(TwitterException exception) {
                }
        });
    }

and this is AndroidApplication class

public class AndroidApplication extends Application {
    private ApplicationComponent applicationComponent;
    private NetComponent netComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        this.initializeInjector();
        SugarContext.init(this);
    }
   
    private void initializeInjector() {
        this.applicationComponent = DaggerApplicationComponent.builder()
                .applicationModule(new ApplicationModule(this))
                .build();
        this.netComponent = DaggerNetComponent.builder()
                .applicationModule(new ApplicationModule(this))
                .netModule(new NetModule(JOB_LEADS_API2))
                .build();
    }

    public ApplicationComponent getApplicationComponent() {
        return this.applicationComponent;
    }

    public NetComponent getNetComponent() {
        return this.netComponent;
    }

    @Override
    public void onTerminate() {
        super.onTerminate();
        SugarContext.terminate();
    }
}

Upvotes: 0

Views: 4078

Answers (1)

Tim
Tim

Reputation: 707

You should inject in AccueilActivity not in AppCompatActivity

@Singleton
@Component(modules = {NetModule.class,ApplicationModule.class})
public interface NetComponent {
void inject(AccueilActivity activity);
void inject(Fragment fragment);
}

EDIT: this is my working example:

Create an InjectHelper so it's easier to reuse in other classes

public class InjectHelper {
private static RootComponent sRootComponent;

static {
    initModules();
}

private static void initModules() {
    sRootComponent = getRootComponentBuilder().build();
}

public static DaggerRootComponent.Builder getRootComponentBuilder() {
    return DaggerRootComponent.builder();
}

public static RootComponent getRootComponent() {
    if (sRootComponent == null) {
        initModules();
    }
    return sRootComponent;
}
}

The component

@Singleton
@Component(modules = { NetModule.class })
public interface RootComponent {
    void inject(AccueilActivity activity);
    void inject(Fragment fragment);
}

The Net module with retrofit instance

@Module
public class NetModule {
    private static final int CONNECT_TIMEOUT = 45;
    private static final int WRITE_TIMEOUT = 45;
    private static final int READ_TIMEOUT = 45;
    private static final long CACHE_SIZE = 10 * 1024 * 1024; // 10 MB

    private Cache provideHttpCache() {
        return new Cache(App.getInstance().getCacheDir(), CACHE_SIZE);
    }

    /**
     * @return OkHttpClient.Builder an instance of the configured http client
     */
    private OkHttpClient provideOkHttpClient() {
        OkHttpClient.Builder client = new OkHttpClient.Builder();
        client.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
        client.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
        client.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS);
        client.cache(provideHttpCache());
        client.addInterceptor(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                if (isConnected(App.getContext())) {
                    request = request.newBuilder().header("Cache-Control", "public, max-age=" + 60).build();
                } else {
                    request = request.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=" + 60 * 60 * 24 * 7).build(); // 1 week
                }
                return chain.proceed(request);
            }
        });
        return client.build();
    }

    private Gson provideGsonParser(){
        return new GsonBuilder()
                .setDateFormat("dd-MM-yyyy 'at' HH:mm")
                .create();
    }

    /**
     * Provides a singleton instance of Retrofit. This is injected with dagger DI into the baseDAO
     * @return Retrofit instance to create the api calls
     */
    @Provides
    @Singleton
    public Retrofit provideRetrofit() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(App.getContext().getString(R.string.base_url))
                .client(provideOkHttpClient())
                .addConverterFactory(GsonConverterFactory.create(provideGsonParser()))
                .build();
        return retrofit;
    }

    private boolean isConnected(Context context) {
        ConnectivityManager cm = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        if (cm == null) {
            return false;
        }
        NetworkInfo info = cm.getActiveNetworkInfo();
        return info != null && info.isConnected();
    }
}

Inject in your Activity:

public class MainActivity extends AppCompatActivity {
@Inject
Retrofit retrofit;
private ApiService service;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
InjectHelper.getRootComponent().inject(this); // call the InjectHelper
service = retrofit.create(ApiService.class); // use retrofit
}

Upvotes: 2

Related Questions