Fetch large json one after one from RestApi , Retrofit and Rxjava? - java

I wanted to load a json, one after one, beacause its large JsonArray. before then i used Retrofit call and Its oKey, but the output take too long. Any help on how to implement it this way is appreciated.
ApiInterface.java
public interface ApiInterface {
#POST("/token/login")
Call<User> login(#Body Login login);
#Streaming
#GET("/api/schools/")
Observable<ResponseBody> getAllSchools(#Header("Authorization") String authToken);
}
Client.java
public class Client {
public static final String BASE_URL = "site.net";
private static Retrofit retrofit;
public static Retrofit getClient(){
if (retrofit == null){
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
return retrofit;
}
}
ApiInterface apiInterface = Client.getClient().create(ApiInterface.class);
String tok = "Token " + token;
apiInterface.getAllSchools(tok)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<ResponseBody>() {
#Override
public void onSubscribe(Disposable disposable) {
}
#Override
public void onNext(ResponseBody responseBody) {
//fetch json one after one.
Toast.makeText(getContext(), responseBody.toString(), Toast.LENGTH_SHORT).show();
}
#Override
public void onError(Throwable throwable) {
}
#Override
public void onComplete() {
Toast.makeText(getContext(), "finish--", Toast.LENGTH_SHORT).show();
}
});

Related

Retrofit - invalid parameters in call

I've just get the code from response, and it says, that my request parameters are wrong, what should my api call look like then?
Here's the hardcoded api call from documenatation
https://api.themoviedb.org/3/discover/movie?api_key=[API_KEY]&with_genres=27
Here's my api call
#GET("3/search/movie")
Call<itemList_model> test(#Query("api_key") String key,#Query("with_genres") int query);
Code
Invalid parameters: Your request parameters are incorrect.
Retrofit call
public void getListViewItems() {
String url = "https://api.themoviedb.org/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build();
apiCall api = retrofit.create(apiCall.class);
Call<itemList_model> call = api.test("API_KEY",27); <- 27 stand's for horror genres.
call.enqueue(new Callback<itemList_model>() {
#Override
public void onResponse(Call<itemList_model> call, Response<itemList_model> response) {
if (!response.isSuccessful()) {
Log.i(TAG, "onResponse: " + response.code());
}
Log.i(TAG, "onResponse: "+response.code());
}
#Override
public void onFailure(Call<itemList_model> call, Throwable t) {
Log.i(TAG, "onFailure: " + t.getMessage());
}
});
}
Simple typo. Should be:
https://api.themoviedb.org/3/discover/movie?api_key=[API_KEY]&with_genres=27
But:
https://api.themoviedb.org/3/search/movie?api_key=[API_KEY]&with_genres=27
Working code
package test;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface RetrofitProxy {
#GET("3/discover/movie")
Call<Object> test(#Query("api_key") String apiKey, #Query("with_genres") int genreCode);
}
package test;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import java.io.IOException;
public class RetrofitTest {
public static void main(String[] args) throws IOException {
String url = "https://api.themoviedb.org/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build();
RetrofitProxy retrofitProxy = retrofit.create(RetrofitProxy.class);
Call<Object> call = retrofitProxy.test("API_KEY", 27);
Response<Object> execute = call.execute();
System.out.println(execute.raw());
System.out.println(execute.isSuccessful());
System.out.println(execute.body());
}
}

Dagger 2 and Retrofit 2 change base URL

In my case, I need to change URL dynamically, but I don't want to create 2 instances of the retrofit client. I'm trying to change base URL via interceptor modifications, but retrofit still uses the old value. What am I doing wrong?
App.java
public class App extends Application {
private static AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
appComponent =
DaggerAppComponent
.builder()
.appModule(new AppModule(this))
.build();
}
#NonNull
public static App get(#NonNull Context context) {
return (App) context.getApplicationContext();
}
public static AppComponent getAppComponent() {
return appComponent;
}
}
AppModule.java
#Module
public class AppModule {
private Context context;
public AppModule(Context context) {
this.context = context;
}
#Provides
#Singleton
Context provideContext() {
return context;
}
}
NetModule.java
#Module
public class NetModule {
#Provides
#Singleton
Gson provideGson() {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
return gsonBuilder.create();
}
#Provides
#Singleton
MainInterceptor provideMyApiInterceptor() {
return MainInterceptor.get();
}
#Provides
#Singleton
OkHttpClient provideOkhttpClient() {
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.readTimeout(15, TimeUnit.SECONDS);
client.connectTimeout(20, TimeUnit.SECONDS);
return client.build();
}
#Provides
#Singleton
Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {
return new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl("first.url.com")
.client(okHttpClient)
.build();
}
}
NetComponent.java
#Singleton
#Component(modules = NetModule.class)
public interface NetComponent {
Retrofit getRetrofit();
MainInterceptor getInterceptor();
}
MainInterceptor.class
public class MainInterceptor implements Interceptor {
private static MainInterceptor sInterceptor;
private String mScheme;
private String mHost;
public static MainInterceptor get() {
if (sInterceptor == null) {
sInterceptor = new MainInterceptor();
}
return sInterceptor;
}
private MainInterceptor() {
}
public void setInterceptor(String url) {
HttpUrl httpUrl = HttpUrl.parse(url);
mScheme = httpUrl.scheme();
mHost = httpUrl.host();
}
#Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
if (mScheme != null && mHost != null) {
HttpUrl newUrl = original.url().newBuilder()
.scheme(mScheme)
.host(mHost)
.build();
original = original.newBuilder()
.url(newUrl)
.build();
}
return chain.proceed(original);
}
}
And this is the code to initialize the component in some class.
NetComponent component= DaggerNetComponent.create();
DataService service = component.getRetrofit().create(DataService.class);
MainInterceptor interceptor = component.getInterceptor();
interceptor.setInterceptor("second.url.com");
service.getSomeData();
After that, the URL is still "first.url.com"
The simple way is to use #Named:
#Provides
#Singleton
#Named("retrofit_1")
Retrofit provideRetrofit1(Gson gson, OkHttpClient okHttpClient) {
return new Retrofit.Builder()
...
.baseUrl("url_1.com")
...;}
#Provides
#Singleton
#Named("retrofit_2")
Retrofit provideRetrofit2(Gson gson, OkHttpClient okHttpClient) {
return new Retrofit.Builder()
...
.baseUrl("url_2.com")
...;}
then use the same #Named:
#Provides
IApi1 provideApi_1(#Named("retrofit_1") RestAdapter adapter){....}
#Provides
IApi2 provideApi_2(#Named("retrofit_2") RestAdapter adapter){....}
When you provide a Retrofit, you already set baseUrl "first.url.com"
return new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl("first.url.com")
.client(okHttpClient) //<------ It not OkHttp with your MainInterCeptor
.build();
And fun fact is, your MainInterceptor which is set-up with new url is unrelated to your Retrofit, because Retrofit was built with OkHttp
#Provides
#Singleton
OkHttpClient provideOkhttpClient() {
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.readTimeout(15, TimeUnit.SECONDS);
client.connectTimeout(20, TimeUnit.SECONDS);
return client.build();
}
If you want to dynamically change your BASE_URL, there are many ways for you to do that.
public class ApiConstant {
public static String BASE_URL = "yourUrl";
private ApiConstant() {
}
}
Create a #Scope for Retrofit because it can be changed
#Scope
#Retention(RetentionPolicy.RUNTIME)
public #interface PerActivity {
}
Then use it when building Retrofit
#Provides
#PerActivity
Retrofit provideRetrofit(Gson gson, OkHttpClient okHttpClient) {
return new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.baseUrl("first.url.com")
.client(ApiConstant.BASE_URL)
.build();
}
Then change the BASE_URL when init DaggerActivityComponent. (Or create a new #Scope for new url)
Read this documentation for more detail
Hope this help!
Add Interceptor in your AppModule
#Provides
#Singleton
OkHttpClient provideOkHttpClient(Cache cache, MainInterceptor interceptor) {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.cache(cache)
.build();
return okHttpClient;
}
and then in your activity or presenter set url before calling retrofit service
mInterceptor.setInterceptor(urlname);
mRetrofitService.call();
If you already have a base URL set but you want to override it for just one API call and not all of them, it can be done pretty easily.
#PUT("https://my-api.com/user")
fun cancelOrder(#Path("user") user: String): Single<MyResponse>
Works the same way for POST and GET as well.

Error occured in Retrofit connection

My interface
#POST("/insert.php")
void login(Callback<Response> callback);
Java code
Retrofit adapter = new Retrofit.Builder()
.baseUrl(ROOT_URL) //Setting the Root URL
.addConverterFactory(GsonConverterFactory.create())
.build(); //Finally building the adapter
Register_Retrofit api = adapter.create(Register_Retrofit.class);
api.login( new Callback<Response>() {
public void onResponse(Call<Response> call, Response<Response> response) {
}
public void onFailure(Call<Response> call, Throwable t) {
}
});
Your login method return void, so you need to define it like this:
#POST("/insert.php")
Call<Void> login();
Then, to call the login method try this:
Retrofit adapter = new Retrofit.Builder()
.baseUrl(ROOT_URL) //Setting the Root URL
.addConverterFactory(GsonConverterFactory.create())
.build(); //Finally building the adapter
Register_Retrofit api = adapter.create(Register_Retrofit.class);
Call<Void> loginCall = api.login();
loginCall.enqueue(new Callback<Void>() {
public void onResponse(Call<Void> call, Response<Void> response) {
...
}
public void onFailure(Call<Void> call, Throwable t) {
...
}
});

Fatal exception when I run my application (retrofit)?

So I have an application which pulls information from an API using retrofit as the library. I thought I had it all working but whenever I run the application I get a null pointer exception and the app crashes and I'm unsure why:
The interface that builds retrofit:
public interface FriendsAPI {
static final String URL = "https://www.cs.kent.ac.uk/";
#GET("https://www.cs.kent.ac.uk/people/staff/iau/LocalUsers.php")
Call<User> getFriends();
class Factory {
private static FriendsAPI service;
public static FriendsAPI getInstance() {
if (service == null) {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(URL)
.build();
return service;
} else {
return service;
}
}
}
}
Stores the JSON array into a list:
public class FriendsInfo {
#SerializedName("Users")
#Expose
private List<User> Users = new ArrayList<User>();
/**
*
* #return
* The Users
*/
public List<User> getUsers() {
return Users;
}
/**
*
* #param Users
* The Users
*/
public void setUsers(List<User> Users) {
this.Users = Users;
}
}
Finally where I'm calling it (and the code that triggers the fatal exception, although I don't know why):
public void populateFriends(){
FriendsAPI.Factory.getInstance().getFriends().enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
String tempLat = response.body().getLat();
String tempLon = response.body().getLon();
tLat = Double.parseDouble(tempLat);
tLon = Double.parseDouble(tempLon);
}
#Override
public void onFailure(Call<User> call, Throwable t) {
Log.e("Failed :(",t.getMessage());
}
});
}
I think I've included all the relevant code but if there is anything missing I can post it here. I also have a more complete version of the project on Github.
Thanks in advance guys.
You have not written anything to service inside getInstance(). Hence it is always null. You need to assign the retrofit.create() object to service.
public static FriendsAPI getInstance() {
if (service == null) {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(URL)
.build();
service = retrofit.create(FriendsAPI.class); //Add this line
return service;
} else {
return service;
}
}
}
} else {
return service;
}
}
If service is null you return null, change it like this
class Factory {
private static MyApiEndpointInterface service;
if (service == null) {
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(URL)
.build();
service=retrofit.create(FriendsApi.class);
return service;
} else {
return service;
}
}
}

Retrofit android not working and has no error

I just implemented the retrofit android library for rest api call but it is not working and has no error. My code is
ApiInterface.java
public interface ApiInterface {
#POST("url")
void getLoginResponse(#Field("username") String username , #Field("password") String password,
#Field("clientId") String clientId , Callback<LoginResponse> cb);
}
RestClient.java
public class RestClient {
private static ApiInterface REST_CLIENT;
private static String BASE_URL = "base_url";
static {
setupRestClient();
}
private RestClient() {}
public static ApiInterface get() {
return REST_CLIENT;
}
private static void setupRestClient() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(BASE_URL)
.build();
REST_CLIENT = restAdapter.create(ApiInterface.class);
}
}
and in activity i call
RestClient.get().getLoginResponse(usernameText, passwordText, clientId, new Callback<LoginResponse>() {
#Override
public void success(LoginResponse loginResponse, Response response) {
Toast.makeText(getApplicationContext(), loginResponse.getToken(), Toast.LENGTH_SHORT).show();
}
#Override
public void failure(RetrofitError error) {
}
});
And in AndroidManifest i set the permission for internet.
How to make RestClient as a singleton:
public class RestClient {
private static ApiInterface REST_CLIENT;
private static String BASE_URL = "base_url";
public RestClient() {}
public static ApiInterface getInstance() {
//if REST_CLIENT is null then set-up again.
if (REST_CLIENT == null) {
setupRestClient();
}
return REST_CLIENT;
}
private static void setupRestClient() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(BASE_URL)
.build();
REST_CLIENT = restAdapter.create(ApiInterface.class);
}
}
Then when you wanna call api you should always call:
ApiInterface api = RestClient.getInstance();
api.callWhatApiYouWant
I am answering late but it will be useful for others, I preferred to use retrofit 2.
// Retrofit
compile 'com.squareup.retrofit2:retrofit:2.1.0'
// JSON Parsing
compile 'com.google.code.gson:gson:2.7'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
Quit Simple to create instance.
public static Retrofit getClient(String baseUrl) {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
Here is Detailed explanation about retrofit 2 android best example and quit simple to understand.
http://al-burraq.com/retrofit-android-get-and-post-api-request-tutorial/

Categories