Send parameter to method's of subscribe CompositeDisposable - Android? - java

I am using from rx for connect to service with retrofit, bellow is RetrofitApi.java :
public class RetrofitApi {
private static PublicApi retrofit = null;
public static PublicApi getClient(String url) {
retrofit = new Retrofit.Builder()
.baseUrl(url)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build().create(PublicApi.class);
return retrofit;
}
}
And here is PublicApi.java :
public interface PublicApi {
#GET("/web_service/mobile/rest")
Observable<LastNews> lastNews(#Query("function") String function);
}
Bellow I am connecting to my service :
#Override
public void fetchLastNewsStartPage(RemoteDataSource.ResultListener<List<LastNews>> resultListener) {
PublicApi publicApi = RetrofitApi.getClient("https://xxx.xxx.xxx/web_service/");
CompositeDisposable mCompositeDisposable = new CompositeDisposable();
mCompositeDisposable.add(publicApi.lastNews("getLastNews")
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(this::handleResponse, this::handleError));
}
My problem is here, how can I send parameter to handleResponse and handleError. I need to send this RemoteDataSource.ResultListener<List<LastNews>> resultListener to handleResponse and handleError:
private void handleResponse(LastNews lastNewses) {
}
private void handleError(Throwable error) {
}

Just don't use method reference as it can only accept one parameter. You can achieve the result with a lambda expression. Instead of
this::handleResponse
write
lastNews -> handleResponse(lastNews, resultListener)

Related

Retrofit2+RxJava Return null to Model class in OnNext()

I'm sending a simple get method to my server and get the result using RxJava and Retrofit. The thing that I did is:
Interface
public interface Posts {
#GET("/typicode/demo/{path}")
Observable<List<Beans>> getPosts(#Path("path") String path);
}
RetrofitInstance
public static Retrofit getInstance() {
if (retrofit == null) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
.client(client)
.build();
}
return retrofit;
}
MainActivity
Observer<List<Beans>> observer = new Observer<List<Beans>>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(List<Beans> value) {
Log.d("Saket", value.toString());
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
};
Posts client = RetrofitClientInstance.getInstance().create(Posts.class);
client.getPosts("posts").observeOn(Schedulers.newThread()).subscribeOn(AndroidSchedulers.mainThread()).subscribe(observer);
I am getting correct output using HTTPLoggingInterceptor.
You can use subscribeWith like this
also change subscribe on to --> Schedulers.newThread() or Schedulers.io()
right now you are making network call on UI thread
client.getPosts("posts")
.subscribeOn(Schedulers.newThread()) // change
.observeOn(AndroidSchedulers.mainThread()) // change
.subscribeWith(new Observer<Response<Observable<List<Beans>>>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Response<Observable<List<Beans>>> response) {
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
}
#Override
public void onComplete() {
}
});
It works when I use Single Observable and DisposableSingleObserver as an observer.

Android Callback method not fills the list

I'm working on an Android Project right now and I'm trying to parse from an URL. In my "ApiClient" I have no problem to parse. Here is my "ApiClient" class:
public class ApiClient implements Callback<Map<String, Channel>> {
static final String BASE_URL = "someURL";
public void start() {
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
RestInterface restInterface = retrofit.create(RestInterface.class);
Call<Map<String, Channel>> call = restInterface.getChannels();
call.enqueue(this);
}
#Override
public void onResponse(retrofit2.Call<Map<String, Channel>> call, Response<Map<String, Channel>> response) {
System.out.println(response.code());
if(response.isSuccessful()) {
Map<String, Channel> body = response.body();
List<Channel> channels = new ArrayList<>(body.values());
}
...
}
I'm trying to get the response into a List from using callback in my "Radio" class. This the place where I'm having the problem. I tried this three too but it didn't solved my problem:
private List<Channel> listChannels = new ArrayList<Channel>();
private List<Channel> listChannels = new ArrayList<>();
private List<Channel> listChannels = new List<>();
Here is my "Radio" class:
public class Radio {
private static final String STORAGE = "radio";
private List<Channel> listChannels;
public static Radio get() {
return new Radio();
}
private SharedPreferences storage;
private Radio() {
storage = App.getInstance().getSharedPreferences(STORAGE, Context.MODE_PRIVATE);
}
public List<Channel> getData() {
RestInterface restInterface = SingletonClass.getService();
restInterface.getChannels().enqueue(new Callback<Map<String, Channel>>() {
#Override
public void onResponse(Call<Map<String, Channel>> call, Response<Map<String, Channel>> response) {
if(response.isSuccessful()){
Map<String, Channel> body = response.body();
List<Channel> channels = new ArrayList<>(body.values());
loadChannels(channels);
}
}
#Override
public void onFailure(Call<Map<String, Channel>> call, Throwable t) {
}
});
System.out.println(listChannels.get(1).getArtist());
return listChannels;
}
public boolean isRated(int itemId) {
return storage.getBoolean(String.valueOf(itemId), false);
}
public void setRated(int itemId, boolean isRated) {
storage.edit().putBoolean(String.valueOf(itemId), isRated).apply();
}
private void loadChannels(List<Channel> channels){
listChannels.clear();
listChannels.addAll(channels);
}
}
Here is my interface class:
public interface RestInterface {
#GET("someURL")
retrofit2.Call<Map<String, Channel>> getChannels();
}
and my SingletonClass:
public class SingletonClass{
private static final Retrofit RETROFIT = new Retrofit.Builder()
.baseUrl(someURL)
.addConverterFactory(GsonConverterFactory.create())
.build();
private static final RestInterface SERVICE = RETROFIT.create(RestInterface.class);
public static RestInterface getService(){
return SERVICE;
}
}
I don't know what should I do to fill the List in my Radio class now. I'm totally open to suggestions. Thanks for the help.
Are you getting an empty list? You're asynchronously setting in the channel data in getData(), so if you're trying to get the data by reading it in the next line, it may not be loaded yet.
This means that when you call System.out.println(listChannels.get(1).getArtist()), you won't see the result of loadChannels, because that call happens right after you call enqueue() while loadChannels() is running on a separate thread. If you moved that into onResponse() you might have more luck.
In Android, a fairly easy way to do things like this and interact with the UI is by using AsyncTask, which for you would look something like this:
private class loadChannelTask extends AsyncTask<Void, Void, List<Channel>> {
protected List<Channel> doInBackground() {
//get response
//pass to load channels
}
protected void onPostExecute() {
System.out.println(listChannels.get(1).getArtist()); //presumably the artist name
}
}

RxJava Observer incompatible types

I am trying to use Retrofit and RxJava to make an API call within a custom view in an app that I am working on, but I encounter an incompatible type error when trying to subscribe to the Observable from my Retrofit API call.
My retrofit interface:
public interface ApiQueryInterface{
// Request method and URL specified in the annotation
// Callback for the parsed response is the last parameter
#GET("users/")
Observable<Users> getUsers (
#Query("key") String key,
#Query("address") String address
);
#GET("posts/")
Observable<Posts> getPosts (
#Query("key") String key,
#Query("address") String address
);
}
and the Retrofit call located within the onFinishInflate() of the custom view:
// Create RxJava adapter for synchronous call
RxJava2CallAdapterFactory rxAdapter = RxJava2CallAdapterFactory.create();
// Create Retrofit2 instance for API call
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(rxAdapter)
.build();
// Make API call using retrofit
final ApiQueryInterface apiQueryInterface = retrofit.create(ApiQueryInterface.class);
// API return type defined by interface
Observable<Users> query = apiQueryInterface
.getUsers(KEY, ADDRESS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Users>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Users users) {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
}
When I build the project I hit an incompatible types error in the custom view on the line beginning with Observable<Users> query = ...:
Error:(60, 27) error: incompatible types: void cannot be converted to Observable<Users>
"Users" is a generic model class which matches the JSON object returned from the API
RxJava 1 returns a Subscription object not an Observable. RxJava 2 subscription returns void. That's why you are getting Error:(60, 27) error: incompatible types. You are getting the Disposable in the callback onSubscribe. If you need a reference to it, you can assign it to a class level member when the callback is invoked
Change returned object to Subscription
private Subscription subscription;
....
subscription = ApiClient.getInstance()
.getUsers(KEY, ADDRESS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<Users>>() {
#Override public void onCompleted() {
}
#Override public void onError(Throwable e) {
}
#Override public void onNext(List<Users> users) {
}
});
apiclient
public class ApiClient {
private static ApiClient instance;
private ApiQueryInterface apiqueryinterface;
private ApiClient() {
final Gson gson =
new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
final Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
apiqueryinterface = retrofit.create(ApiQueryInterface.class);
}
public static ApiClient getInstance() {
if (instance == null) {
instance = new ApiClient();
}
return instance;
}
public Observable<List<Users>> getUsers(#NonNull String key, #NonNull String address) {
return apiqueryinterface.getUsers(key, address);
}
}
interface
public interface ApiQueryInterface{
// Request method and URL specified in the annotation
// Callback for the parsed response is the last parameter
#GET("users")
Observable<<List<Users>> getUsers (
#Query("key") String key,
#Query("address") String address
);

How to define API endpoint for retrofit?

This is my sample URL to the API end point:
https://api.projectoxford.ai/luis/v1/application?id=b0d5b503-eb2e-460a-b028-a3223aa93227&subscription-key=bc1cb297a94f4c9a9b58bcd36280466c&q=start%20test
Now, how do I create the base URL and define end point for use in Retrofit.
I've created model class for JSON, and this is how I defined base URL:
public class ApiClient {
public static final String BASE_URL = "https://api.projectoxford.ai/luis/v1/";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
This is how I tried to define the end point:
public interface ApiInterface {
#GET("application")
Call<LuisPojo> getValues(#Query("id") String apiKey);
}
But how to add the remaining part, subscription-key and the search term in the end
start test
Append it in your getValues()
#GET("application")
Call<LuisPojo> getValues(#Query("id") String apiKey, #Query("subscription-key") String key, #Query("q") String q);

Android Retrofit: missing method body, or declare abstract

I am writing an android app that will use Retrofit to make API requests.
I have a helper class like this:
public class ApiService {
public static final String TAG = ApiService.class.getSimpleName();
public static final String BASE_URL = "https://myapiurl.com";
public static void testApi(){
ApiEndpointInterface apiService = prepareService();
apiService.ping(new Callback<Response>() {
#Override
public void success(Response apiResponse, retrofit.client.Response response) {
Log.e(TAG, apiResponse.toString());
}
#Override
public void failure(RetrofitError error) {
Log.e("Retrofit:", error.toString());
}
});
}
private static ApiEndpointInterface prepareService() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(BASE_URL)
.build();
ApiEndpointInterface apiService =
restAdapter.create(ApiEndpointInterface.class);
restAdapter.setLogLevel(RestAdapter.LogLevel.FULL);
return apiService;
}
}
And my actual Retrofit implementation is simple:
public class ApiEndpointInterface {
#GET("/v1/myendpoint")
void ping(Callback<Response> cb);
}
The problem is, I cannot build the project, I get the error:
Error:(12, 10) error: missing method body, or declare abstract
Referring to my ApiEndpointInterface class.
Any idea what's going on?
Try public interface for your API declaration.
public interface ApiEndpointInterface {
#GET("/v1/myendpoint")
void ping(Callback<Response> cb);
}
Also, looks like you're creating your ApiEndpointInterface before telling the builder to set log level to full.
private static ApiEndpointInterface prepareService() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(BASE_URL)
.setLogLevel(RestAdapter.LogLevel.FULL);
.build();
ApiEndpointInterface apiService =
restAdapter.create(ApiEndpointInterface.class);
return apiService;
}
In case you update to okHttp Version 2.4.0 , you will get an exception for empty Body as latest version no more allows zero length request , in which case you would have to use the following syntax
public interface ApiEndpointInterface {
#GET("/v1/myendpoint")
void ping(Callback<Response> cb, #Body String dummy);
}
call
ApiEndpointInterface apiService =
restAdapter.create(ApiEndpointInterface.class);
apiService.ping(callback,"");
Ref
https://github.com/square/okhttp/issues/751

Categories