TaouBen
TaouBen

Reputation: 1315

Not getting my response when calling my api using MVVM and Retrofit?

I am trying to use MVVM, Retrofit, Dagger in my application, So in the begging I was only using a an ArrayList to display my data from the viewModel to the View and it worked, Now I am using it all, but I am getting an error, I don't get the error, does not seem clear to me.

I am using a php script that returns a JSON response, in my local machine.

I have a lot of code to provide here I think, so here is my ContractListViewModel :

public class ContractsListViewModel extends ViewModel {
    public MutableLiveData<List<ContractModel>> contractList = new MutableLiveData<List<ContractModel>>();
    MutableLiveData<Boolean> isLoading= new MutableLiveData<Boolean>();
    MutableLiveData<Boolean> error= new MutableLiveData<Boolean>();

    @Inject
    ContractService contractService;

    CompositeDisposable disposable = new CompositeDisposable();

    public ContractsListViewModel(){
        super();
        DaggerContractApiComponent.create().inject(this);
    }

    public void call(){
        fetchContracts();
    }

    public void fetchContracts(){

        isLoading.setValue(true);

        disposable.add(
                contractService.getContracts()
                        .subscribeOn(Schedulers.newThread())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribeWith(new DisposableSingleObserver<List<ContractModel>>() {

                            @Override
                            public void onSuccess(List<ContractModel> friendsModels) {
                                isLoading.setValue(false);
                                error.setValue(false);
                                contractList.setValue(friendsModels);
                            }

                            @Override
                            public void onError(Throwable e) {
                                error.setValue(true);
                                isLoading.setValue(false);
                                e.printStackTrace();
                            }
                        })
        );

    }

    @Override
    protected void onCleared(){
        super.onCleared();
        disposable.clear();
    }


}

Here is my ContractService :

public class ContractService {

    public static ContractService instance;

    @Inject
    public ContractApi api;

    private ContractService(){
        DaggerContractApiComponent.create().inject(this);
    }

    public static ContractService getInstance(){
        if(instance == null){
            instance = new ContractService();
        }
        return instance;
    }

    public Single<List<ContractModel>> getContracts(){
        return api.getContractList();
    }
}

This my ContratApiComponent ( for injection ) :

@Component(modules = { ApiModule.class})
public interface ContractApiComponent {

    public void inject(ContractService contractService);
    public void inject(ContractsListViewModel contractListViewModel);

}

This is my ContratctApi :

public interface ContractApi {

    @GET("contrats.php")
    Single<List<ContractModel>> getContractList();

}

This is my ApiModule :

@Module
public class ApiModule {

    public static String BASE_URL = "http://localhost/newconceptsphp/";

    @Provides
    public ContractApi provideContractApi(){
        return new Retrofit.Builder().baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build()
                .create(ContractApi.class);
    }

    @Provides
    public ContractService provideContractService(){
        return ContractService.getInstance();
    }

}

This is my MainActivity :

public class MainActivity extends AppCompatActivity {

    ContractsListViewModel contractsListViewModel;

    @BindView(R.id.newContractBtn)
    Button newContractBtn;

    RecyclerView.Adapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        ActivityMainBinding main = DataBindingUtil.setContentView(this, R.layout.activity_main);

        ButterKnife.bind(this);
        main.contractList.setLayoutManager(new LinearLayoutManager(this));

        contractsListViewModel = ViewModelProviders.of(this).get(ContractsListViewModel.class);
        contractsListViewModel.call();

        contractsListViewModel.contractList.observe(this,contractModels -> {
            if(contractModels != null){
            adapter = new ContractListAdapter(MainActivity.this, contractModels);
            main.contractList.setAdapter(adapter);
        }else {
            Log.d("TAG", "Nothing is here")
        }
        });

    }
}

I am getting nothing.

What I expect to get is this :

enter image description here

Here is what I get :

enter image description here

This an error I get :

2020-04-12 17:53:08.308 27128-27128/com.example.cosysimulation W/System.err: java.net.ConnectException: Failed to connect to localhost/127.0.0.1:80
2020-04-12 17:53:08.309 27128-27128/com.example.cosysimulation W/System.err:     at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:225)
2020-04-12 17:53:08.309 27128-27128/com.example.cosysimulation W/System.err:     at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:149)
2020-04-12 17:53:08.310 27128-27128/com.example.cosysimulation W/System.err:     at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:192)

Any help would be much appreciated, because I tried this in a project, then I tried to make a new one because I thought I did not set up everything right obviously but it seems like it is not working.

Thank you.

Upvotes: 0

Views: 586

Answers (2)

TaouBen
TaouBen

Reputation: 1315

So i found a solution to my problem, I had to not use a localhost in my BASE url, I had to call the IP adress, The reason is when you call localhost, it refers to the android emulator and not PC, so in order to target the api in your local pc machine, use its IP :

@Module
public class ApiModule {

public static String BASE_URL = "http://***IP ADRRSS HERE INSTEAD OF LOCALHOST***/newconceptsphp/";

@Provides
public ContractApi provideContractApi(){
    return new Retrofit.Builder().baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build()
            .create(ContractApi.class);
}

@Provides
public ContractService provideContractService(){
    return ContractService.getInstance();
}

}

Upvotes: 0

Jason
Jason

Reputation: 1698

Try using adb reverse tcp:80 tcp:80. This allows the emulator to access port 80 on your PC (host)

Upvotes: 2

Related Questions