Retrofit in Android networking
useful video :
https://www.youtube.com/watch?v=4JGvDUlfk7Y&list=PLrnPJCHvNZuCbuD3xpfKzQWOj3AXybSaM
Call Adapters : https://futurestud.io/tutorials/retrofit-2-introduction-to-call-adapters
RETROFIT provides a abstraction layer over all the low level networking code, We just need to provide an Interface that contains method declarations for different network operations that we want to do & just give annotations to them , then Retrofit will Generate all things by itself.
Put & Patch : used to update Data using Rest api.
Network operations are sometimes slow and may take few seconds.
DO NOT FORGET TO GET INTERNET USAGE PERMISSION IN MANIFEST
<uses-permission android:name="android.permission.INTERNET"/>
-------------------------------------------------------------------------------------------------
Dependencies :
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.google.code.gson:gson:2.8.6'
Also add the below lines in the gradle files , just to be safe.
-----------------------------------------------------------------------------------------------
If you get java.lang.NoSuchMethodError: No static method metafactory
Add the following lines in your Gradle.build(App) file
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
---------------------------------------------------------------------------------------------------
If you have a different name of variable in your modal class & Json data , and you want to match them up , you can use @SerializeName anotation from Gson & provide the name of the variable in the Json data to match with your variable in Modal class.
Eg - Below is a Modal class variable with different name in Json data ( newbody) , so to tell Gson that "newbody" in Json data is to be set at the variable "body" in modal data , put @SerializeName() above that variable.
@SerializedName("newbody")
private String body;
--------------------------------------------------------------------------------------------------------------
Simple GET requests to get JSON array of objects & display their data on a textview.
Client Interface.
It acts as an API method we'll use to fetch the data from web api.
Inside the @GET() give the remaining part of the api url other than the base url.
Inside the Call< > pass the return type of the method
package com.example.myapplication;
import java.util.List;
import retrofit2.Call;
import retrofit2.http.GET;
public interface JsonPlaceHolder {
@GET("posts")
Call<List<Post>> getPosts();
}
Modal class
package com.example.myapplication;
import com.google.gson.annotations.SerializedName;
public class Post {
int userId;
int id;
String title;
@SerializedName("body")
String text;
public int getUserId() {
return userId;
}
public int getId() {
return id;
}
public String getTitle() {
return title;
}
public String getText() {
return text;
}
}
MainActivity.class
OnResponse() is called when our request was sucessful , but doesnt mean we got what we were expecting hence we need to check for error codes.
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class MainActivity extends AppCompatActivity {
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.mytextview);
getCode();
}
public void getCode(){
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://jsonplaceholder.typicode.com/")
.build();
//We cannot write "new jsonplaceholder()" since its an interface we need to implement it.
// And that is what retrofit will do , so we dont need to write extra code.
JsonPlaceHolder jsonPlaceHolder = retrofit.create(JsonPlaceHolder.class);
Call<List<Post>> call = jsonPlaceHolder.getPosts();
// execte() - runs on main thread.
// enqueue() - runs on background thread.
call.enqueue(new Callback<List<Post>>() {
@Override
public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
//This method is called if the response code that retrofit code was between 200-299
// But this dont mean response we get are sucessful, we need to check for 404.
//check if response is empty i.e 404 - Not found error
if (!response.isSuccessful()){
textView.setText("Code : " + response.code());
return;
}
// body() returns the contents of the response
List<Post> posts = response.body();
for (Post i : posts){
String content = " ";
content += "Id : " + i.getId() + "\n";
content += "UserId : " + i.getUserId() + "\n";
content += "Title : " + i.getTitle()+ "\n";
content += "Body : " + i.getText() + "\n\n";
textView.append(content);
}
}
@Override
public void onFailure(Call<List<Post>> call, Throwable t) {
//This method is called if there is a failure in response.
textView.setText(t.getMessage());
}
});
}
}
EXAMPLE 2 :
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/meme_ImageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="36dp"
android:layout_marginBottom="53dp"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="58dp"
android:onClick="getNextMeme"
android:text="Click"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/meme_ImageView" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@+id/meme_ImageView"
app:layout_constraintEnd_toEndOf="@+id/meme_ImageView"
app:layout_constraintStart_toStartOf="@+id/meme_ImageView"
app:layout_constraintTop_toTopOf="@+id/meme_ImageView" />
</androidx.constraintlayout.widget.ConstraintLayout>
package com.deepesh.exampleapp4;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import java.lang.annotation.Target;
import java.util.List;
import javax.sql.DataSource;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;
import static android.content.ContentValues.TAG;
public class MainActivity extends AppCompatActivity {
final static String BASE_URL = "https://meme-api.herokuapp.com";
final static String URL_ENDPOINT = "/gimme";
ImageView memeImageView;
ProgressBar progressBarCircle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBarCircle = findViewById(R.id.progressBar);
memeImageView = findViewById(R.id.meme_ImageView);
getNextMeme(null);
}
// Button OnClick()
public void getNextMeme(View view) {
progressBarCircle.setVisibility(View.VISIBLE);
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(BASE_URL)
.build();
MemeAPI memeAPI = retrofit.create(MemeAPI.class);
Call<Meme> call = memeAPI.getMemeUrl();
call.enqueue(new Callback<Meme>() {
@Override
public void onResponse(Call<Meme> call, Response<Meme> response) {
if (!response.isSuccessful()) {
Log.d(TAG, "onResponse: CODE " + response.code());
return;
}
Meme meme = response.body();
String url = meme.getUrl();
// Loads image into imageview given image url
Glide.with(MainActivity.this).load(url).into(memeImageView);
progressBarCircle.setVisibility(View.INVISIBLE);
}
@Override
public void onFailure(Call<Meme> call, Throwable t) {
Log.d(TAG, "onFailure: RESPONSE FAILED !");
Log.d(TAG, "onFailure: EXCEPTION MESSAGE : " + t.getMessage());
}
});
}
//=============================================================
// Modal Class
public static class Meme {
private String postLink;
private String subreddit;
private String title;
private String url;
private Boolean nsfw;
private Boolean spoiler;
private String author;
private Integer ups;
private List<String> preview;
public String getUrl() {
return url;
}
}
//=============================================================
public interface MemeAPI {
@GET(URL_ENDPOINT)
Call<Meme> getMemeUrl();
}
}
--------------------------------------------------------------------------------------------------------------
useful video :
https://www.youtube.com/watch?v=TyJEDhauUeQ&list=PLrnPJCHvNZuCbuD3xpfKzQWOj3AXybSaM&index=2
URL manipulation :
1] @Path - used to make dynamic manipulation to url. eg - put parameters in url
// use @Path("name") to tell retrofit to put the parameter at
// brackets with value "name".
@GET("posts/{id}/comments")
Call<List<Comment>> getComments(@Path("id") int PostId);
2] @Query - used to make query url
// Query url : https://jsonplaceholder.typicode.com/comments?postId=1
// pass @query() the actual query variable, as in our case postId.
// retrofit will automatically put " ? " in front of the variable.
@GET("comments")
Call<List<Comment>> getComments(@Query("postId") int PostId);
3] @Url - used to pass an entire url if the entire url is complex.
using this you can pass an entire url .
@GET
Call<List<Comment>> getComments(@Url String url);
Call<List<Comment>> call = jsonPlaceHolder.getComments("comments?postId=3");
-----------------------------------------------------------------------------------------------------------------
useful video : https://youtu.be/GP5OyYDu_mU
Simple POST requests to get JSON array of objects & display their data on a textview.
POST request is the opposite of GET request.
package com.example.myapplication;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.POST;
public interface JsonPlaceHolder {// use the @Body annotation to pass the body/data that needs to be send with request.// Retrofit automatically converts the data into required form i.e JSON. // Use a converter if any other form needed
@POST("posts")
Call<Post> createPost(@Body Post post);
}
--------------------------------------------------------------------------------------------
You can also use @FormUrlEncoded , to pass complex data into post request.
Using this , you dont need to create a object , rather just pass the data as parameters.
// Forms a encoded url & send the post request
// @Field must contain names of actual fields the api needs.
@FormUrlEncoded
@POST("posts")
Call<MyModal> post_userData(
@Field("userId") int userId ,
@Field("title") String title ,
@Field("body") String body);
// MyModal myModal1 = new MyModal(3,"Hello user 3","This is the body");
Call<MyModal> modal = jsonplaceholderAPI.post_userData(3,
"This is the title bitch","This is a mf body !");
-------------------------------------------------------------------------------------------
The site where we send the Post request here , sends the fake data back to the Us on sucessful post response.
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class MainActivity extends AppCompatActivity {
TextView textView;
JsonPlaceHolder jsonPlaceHolder;
Retrofit retrofit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.mytextview);
retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://jsonplaceholder.typicode.com/")
.build();
//We cannot write "new jsonplaceholder()" since its an interface we need to implement it.
// And that is what retrofit will do , so we dont need to write extra code.
jsonPlaceHolder = retrofit.create(JsonPlaceHolder.class);
// getPosts();
// getComments();
createPost();
}
private void createPost() {
Post post = new Post(23,"New text","New title");// REAL APP WE USE EDITTEXT
Call<Post> call = jsonPlaceHolder.createPost(post);
//The site where we send the Post request here , sends
// the fake data back to the Us on sucessful post response.
call.enqueue(new Callback<Post>() {
@Override
public void onResponse(Call<Post> call, Response<Post> response) {
if (!response.isSuccessful()) {
textView.setText("Code : " + response.code());
return;
}
Post postResponse = response.body();
String content = " ";
content += "Response Code : " + response.code() + "\n";
content += "Id : " + postResponse.getId() + "\n";
content += "UserId : " + postResponse.getUserId() + "\n";
content += "Title : " + postResponse.getTitle() + "\n";
content += "Body : " + postResponse.getText() + "\n\n";
textView.setText(content);
}
}
-------------------------------------------------------------------------------------------------------
Setup a logging intercepter to get all the data in the LOGCAT , during the execution.
Step 1 ]
Get the Dependency for LoggingIntercepter from Square's github & add to the android studio.
https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor
Step 2 ] Follow the code below
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.mytextview);
//------------------ Logging intercepter code starts here ---------------------------------
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build();
retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://jsonplaceholder.typicode.com/")
//add client for logger
.client(okHttpClient)
.build();
//------------------ Logging intercepter code end here ---------------------------------
//We cannot write "new jsonplaceholder()" since its an interface we need to implement it.
// And that is what retrofit will do , so we dont need to write extra code.
jsonPlaceHolder = retrofit.create(JsonPlaceHolder.class);
// getPosts();
// getComments();
createPost();
}
-------------------------------------------------------------------------------------------------------
Add Headers in Retrofit
Response headers provide information about the status of the request, and return ETag information. The response also includes a status code.
Headers are like Meta-Data
You can send Static Headers or Dynamic Headers , whose values can be taken from the user.
-------------------------------------------------------------------------------------------------------

Comments
Post a Comment