Better approach to call rest api from android - android

I am new to android programming. I am using rest call from android to query result and based on the queried result I allow user to navigate from one screen/activity to another. I have around 7 activity page and on each page I perform several operations for that I use rest call.
The way I am invoking is using AsyncHttpClient
Ex.
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://serverurl:8080/path1/path2/path3", params, new AsyncHttpResponseHandler() {
//some code
}
The one problem which I am facing is if I have to modify the url I need to modify in all the activity page.
Is there a way from where I can modify once that can be used in every activity?
Is there a better way? Please let me know.

Use Retrofit
public interface GitHubService {
#GET("users/{user}/repos")
Call<List<Repo>> listRepos(#Path("user") String user);
#GET("users/repos/{id}")
Call<Repo> getRepo(#Path("id") String id);
}
Any kind of url changes can be done in this interface
Initialization of retrofit with base url
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
Consuming Api
Call<List<Repo>> repos = service.listRepos("octocat");
repos.enqueue(new Callback<List<Repo>>() {
#Override
public void onResponse(Call<List<Repo>> call, Response<List<Repo>> response) {
//Do something with response
}
#Override
public void onFailure(Call<List<String>> call, Throwable t) {
//handle failure
}
});
For more Retrofit

There are several ways to do API calls in your android application.
Using a library like Retrofit, you can perform API requests without any problems by using an interface.
You can also use the default Url connection that comes with Android to do all sorts of operations like GET and POST among others.
If you are worried about how to easily change the endpoint (url), you can write your code so that you pass in a string param to your methods that way, you don't hard code the value.
I am sure there are a lot more libraries out there and normally, it is a matter of choice and taste.
I hope this helps you as you try to solve your problem!

Just use a static variable.
public class YourClass {
public static final String URL = "http://www.example.com/abc";
public void performApiCall() {
AsyncHttpClient client = new AsyncHttpClient();
client.get(URL, params, new AsyncHttpResponseHandler() {
//some code
});
}
}
You can then use the URL string from other classes:
public class SomeOtherClass {
public void performSomeOtherApiCall() {
AsyncHttpClient client = new AsyncHttpClient();
client.get(YourClass.URL, params, new AsyncHttpResponseHandler() {
//some other code
});
}
}

Related

Login using url with username and password in android mobile app

I am working on android mobile application for website I have a url username and password.I need to login through app.How it should be done? Do I need to use any library for authentication.Any help would be appreciated.Thanks in advance!
Network requests with Android should be done with a library, such as Retrofit or Volley. If you are new to Android and/or looking for a quick solution to your login, I suggest trying Volley as it takes less experience to set up. Here is a good resource to learn about Volley.
Another good option, and the most widely adopted solution as of current is Retrofit. If you are doing anything more than a few simple network calls in your app, I strongly suggest learning about Retrofit. It takes a bit more Android knowledge in my opinion, but it is a more elegant solution and worth the learning.
You will have to learn to make a POST request to your API using either of these libraries, passing in the username and password as parameters or in the request body. The API will likely return a token for authentication in the response body. Good luck!
First you have to implement some rest api libraries.
implementation('com.squareup.retrofit2:retrofit:2.1.0') {
exclude module: 'okhttp'
}
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
implementation 'com.squareup.okhttp3:logging-interceptor:4.2.0'
implementation 'com.squareup.okhttp3:okhttp:4.2.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
Then after create class ApiClient.. in this class write below code in it
public class ApiClient {
private static Retrofit retrofit = null;
public static Retrofit getClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
retrofit = new Retrofit.Builder()
.baseUrl("https://jsonplaceholder.typicode.com")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit;
}}
Now create Interface ApiInterface and write below code in it..
public interface ApiInterface {
#FormUrlEncoded
#POST("login/")
Call<Your Pojo Class> loginuser(#Field("method") String method, #Field("login_name")
String loginname,#Field("password") String password);}
In your MainActivity Write belowe code..
APIInterface apiInterface;
apiInterface = APIClient.getClient().create(APIInterface.class);
Call<EarnAmount> call = apiInterface.loginuser("loginuser", loginid,password);
call.enqueue(new Callback<Your Pojo>() {
#Override
public void onResponse(Call<Your Pojo> call, Response<Your Pojo> response) {
//you will get some response
//you can handle response from here
}
#Override
public void onFailure(Call<Your Pojo> call, Throwable t) {
//check internet connection or something went wrong
}
}); }

Retrofit - use response class with inheritance

I'm trying make reuse of single retrofit api call by inherit from a base response class.
However I'm not able to do it.
I will try to make myself clear with example (It's not a concrete scenario. I'm just trying to figure out the main idea):
Having this response objects and api service:
public class UserDetailsResponse
{
private int userId;
}
public class ExtendedUserDetailsResponse extends UserDetailsResponse
{
private int userAdditionalId;
}
interface APIService
{
#GET("/UserDetails/")
Call<UserDetailsResponse> getUserDetails(#Query("id") String userId);
}
Is there a way of using getUserDetails api with ExtendedUserDetailsResponse object?
This one gives me compilation error:
mService.getUserDetails("123").enqueue(new Callback<ExtendedUserDetailsResponse>()
{
#Override
public void onResponse(Call<ExtendedUserDetailsResponse> call, Response<ExtendedUserDetailsResponse> response)
{
}
#Override
public void onFailure(Call<ExtendedUserDetailsResponse> call, Throwable t)
{
}
});
How can I solve this? or at least something similar to this, without using a new api call for the specific derived class?
Thanks!
You get an error because ExtendedUserDetailsResponse is a UserDetailsResponse, however, UserDetailsResponse is not necessarily an ExtendedUserDetailsResponse.
In order to make it generic, sign your method this way
Call< ExtendedUserDetailsResponse > getUserDetails(#Query("id") String userId);
Then ExtendedUserDetailsResponse will have access to userId
Remember to expose userId with getters and setters so that it get parsed.
You are getting compilation error because you are using the wrong callback object:
Just change this line:
Call<UserDetailsResponse> getUserDetails(#Query("id") String userId);
to
Call<ExtendedUserDetailsResponse> getUserDetails(#Query("id") String userId);
Or depending on the response change the object in the callback
Note that ExtendedUserDetailsResponse will have userId so you can use ExtendedUserDetailsResponse even if the server returns object of type UserDetailsResponse or ExtendedUserDetailsResponse.

Android HttpHelper

I want a helper class for http connection. I am able to write simple code to connect using HttpUrlConnection and Async task and it works well.
But I am confused how can I write a more generic reusable class HttpHelper.
I got this HttpHelper class from internet (It just does a simple get call, I will later extend it to deal with post calls with query parameters), but I am not able to figure out how to call/use this as is. I am confused with the callbacks and the generics.
If I want to make a http request using this call and expect String result, this is what I attempted and it is all with syntax errors.
HttpHelper<String> api = new HttpHelper<>();
api.get("www.google.com", new HttpHelper.Callback<String>{
#Override
String execute(String html){
}
#Override
void finish(String result){
}
});
Thanks for your help
K
you have to call your method like this:
HttpHelper<String> api = new HttpHelper<String>();
api.get("www.google.com", new HttpHelper.Callback<String>{
#Override
String execute(String html){
return html; // This line is very very important.
}
#Override
void finish(String result){
// Do whatever you wan to do with your server response.
}
});
And do check your imports which HttpHelper class your are importing.
This works for me . Happy Coding !!!

Using TLS only with Retrofit in RoboSpice

I've got a basic setup using Robospice with Retrofit in a shell Android application making REST calls, parsing JSON response into a POJO and that I can then use to render in an Activity. I now want to use TLS only for transport security (not SSL). I've read that Retrofit with OkHttp can be used to achieve this but I don't know where to make the update in my code.
I have a basic interface:
public interface RandomAPI {
#GET("/users")
List<User> getUsers(#Path("owner") String owner, #Path("repo") String repo);
#GET("/users/{userid}")
User getUser(#Path("userid") int userID);
}
I have a Service:
public class RandomService extends RetrofitGsonSpiceService {
private final static String BASE_URL = "http://jsonplaceholder.typicode.com";
#Override
public void onCreate() {
super.onCreate();
addRetrofitInterface(RandomAPI.class);
}
#Override
protected String getServerUrl() {
return BASE_URL;
}
}
and finally a request:
public class RandomRequest extends RetrofitSpiceRequest<User, RandomAPI> {
private int userID;
public RandomRequest(int userID) {
super(User.class, RandomAPI.class);
this.userID = userID;
}
#Override
public User loadDataFromNetwork() throws Exception {
return getService().getUser(userID);
}
}
I'm guessing I need to update the Service but not really sure how. I really like the simplicity of this pattern so would like to keep it if possible. I can drop the OkHttp jars into the application but I don't know how to get at the actual implementation of the service, or how to add my custom one so that all requests use it.
Has any one had experience with this that could share some code snippets or point me to an example?
~~ EDIT ~~
Looking into the API for Robospice, looks like my request can just extend SpiceRequest, then within the loadFromNetwork() method I just do plain Retrofit and OkHTTP stuff. Is that the only way though? Thought there would be a way to set your own RestAdapter implementation in RetrofitSpiceService instead of just using the default.
So to do this is actually quite simple. Create a class which extends RetrofitGsonSpiceService and override the createRestAdapterBuilder() method.
e.g.
#Override
protected Builder createRestAdapterBuilder() {
RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(SERVICE_URL)
.setRequestInterceptor(requestInterceptor);
return builder;
}

Testing okHttp requests with Robolectric - callbacks

I have a function that I want to test which runs in an okHttp callback. I'm trying to test it using Robolectrics but the callback is never executed. I presume that is because the test moves on after request without waiting for okHttp to return. So far I've tried:
ShadowLooper.pauseMainLooper();
Robolectric.flushBackgroundScheduler();
ShadowLooper.unPauseMainLooper();
but that didn't work. Any suggestions?
EDIT:
Here's an example of my code:
ApiClient.sendSomeDataToServer(data, callback);
Where ApiClient is a helper class containing okHttp client. sendSomeDataToServer API call looks something like this:
public static void sendSomeDataToServer(MyObject data, Callback callback){
final Request request = new Request.Builder()
.url(API_SOME_URL)
.post(RequestBody.create(JSON, myObject.getAsJson().toString()))
.build();
sHttpClient.newCall(request).enqueue(callback);
}
Where sHttpClient is an initialised OkHttpClient.
I can test the execution of above by forcing Thread.sleep(5000) inside my test code and providing custom callback. The code I'm trying to test is inside the callback. Any suggestions how I can test that? I really don't want to change the main code to fit the test framework - should be the other way round.
Lets assume you have next code. Interface:
#GET("/user/{id}/photo")
void listUsers(#Path("id") int id, Callback<Photo> cb);
Implementation:
public void fetchData() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setServer("baseURL")
.build();
ClientInterface service = restAdapter.create(ClientInterface.class);
Callback<Photo> callback = new Callback<Photo>() {
#Override
public void success(Photo o, Response response) {
}
#Override
public void failure(RetrofitError retrofitError) {
}
};
service.listUsers(435, callback);
}
First of all you need to change service instantiation to service injection (as parameter or field). I will do it as parameter:
public void fetchData(ClientInterface clients) {
}
After this text is quite trivial:
#Test
public void checkThatServiceSuccessIsProcessed() {
ClientInterface mockedClients = mock(ClientInterface.class);
activity.fetchData(mockedClients);
// get callback
ArgumentCaptor<Callback<Photo>> captor = (ArgumentCaptor<Callback<Photo>>)ArgumentCaptor.forClass(Callback.class);
verify(mockedInterface).listUsers(anything(), captor.capture());
Callback<Photo> passedCallback = captor.value();
// run callback
callback.success(...);
// check your conditions
}
The used library for mocking and verifying is Mockito.
There will be one warning with captor instantiation because of generics but it fixable if you will use #Captor annotation instead of creating captor by hands.
The parameter injection is not perfect, especially for case of activities. This was used to simplify example. Consider for proper injection with library or without. I would encourage you to try Dagger for injections
You can use ArgumentCaptor (Mockito's class).
Reference:
http://www.mdswanson.com/blog/2013/12/16/reliable-android-http-testing-with-retrofit-and-mockito.html

Categories

Resources