Android Retrofit and Room Tutorial: API, ViewModel, RecyclerView

Computer science18.15 KB

Android Retrofit, ViewModel and RecyclerView Implementation

Retrofit Interface

public interface ApiService {
@GET("posts") // Replace with your API endpoint for posts
Call<List<Post>> getPosts();
}

Post Model Class

public class Post {
private int id;
private String title;
private String body;
}

Retrofit Client

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitClient {
private static final String BASE_URL = "https://your-base-url.com/";
private static Retrofit retrofit;

public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}

ViewModel

public class PostViewModel extends ViewModel {
private MutableLiveData<List<Post>> postList;

public LiveData<List<Post>> getPosts() {
if (postList == null) {
postList = new MutableLiveData<>();
loadPosts();
}
return postList;
}

private void loadPosts() {
ApiService apiService = RetrofitClient.getRetrofitInstance().create(ApiService.class);
Call<List<Post>> call = apiService.getPosts();
call.enqueue(new Callback<List<Post>>() {
@Override
public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
if (response.isSuccessful()) {
postList.setValue(response.body());
}
}

@Override
public void onFailure(Call<List<Post>> call, Throwable t) { }
});
}
}

MainActivity

public class MainActivity extends AppCompatActivity {
private PostViewModel postViewModel;
private RecyclerView recyclerView;
private PostAdapter postAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);

postAdapter = new PostAdapter(new ArrayList<>()); // Pass an empty list initially
recyclerView.setAdapter(postAdapter);

postViewModel = new ViewModelProvider(this).get(PostViewModel.class);
postViewModel.getPosts().observe(this, posts -> {
postAdapter.setPostList(posts);
postAdapter.notifyDataSetChanged();
});
}
}

Step-by-Step Implementation with Repository Pattern

Step 1: Create the Model

public class Item {
private String name;

public Item(String name) {
this.name = name;
}

public String getName() {
return name;
}
}

Step 2: Create the Repository

public class ItemRepository {
private ApiService apiService;

public ItemRepository() {
apiService = RetrofitClientInstance.getRetrofitInstance().create(ApiService.class);
}

public LiveData<List<Item>> getItems() {
MutableLiveData<List<Item>> data = new MutableLiveData<>();
apiService.getItems().enqueue(new Callback<List<Item>>() {
@Override
public void onResponse(Call<List<Item>> call, Response<List<Item>> response) {
if (response.isSuccessful()) {
data.setValue(response.body());
}
}

@Override
public void onFailure(Call<List<Item>> call, Throwable t) {
data.setValue(null);
}
});
return data;
}
}

Step 3: Create the ViewModel

public class ItemViewModel extends ViewModel {
private ItemRepository itemRepository;
private LiveData<List<Item>> itemList;

public ItemViewModel() {
itemRepository = new ItemRepository();
itemList = itemRepository.getItems();
}

public LiveData<List<Item>> getItemList() {
return itemList;
}
}

Step 4: Create the API Service Interface

public interface ApiService {
@GET("items")
Call<List<Item>> getItems();
}

Step 5: Create the RecyclerView Adapter

public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> {
private List<Item> itemList;

public ItemAdapter(List<Item> itemList) {
this.itemList = itemList;
}

@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
return new ViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Item item = itemList.get(position);
holder.bind(item);
}

@Override
public int getItemCount() {
return itemList.size();
}

public static class ViewHolder extends RecyclerView.ViewHolder {
private TextView itemName;

public ViewHolder(@NonNull View itemView) {
super(itemView);
itemName = itemView.findViewById(R.id.item_name);
}

public void bind(Item item) {
itemName.setText(item.getName());
}
}
}

Step 6: Create the Activity/Fragment

public class ItemListActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private ItemAdapter adapter;
private ItemViewModel itemViewModel;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_list);

recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new ItemAdapter(new ArrayList<>());
recyclerView.setAdapter(adapter);

itemViewModel = new ViewModelProvider(this).get(ItemViewModel.class);
itemViewModel.getItemList().observe(this, items -> {
if (items != null) {
adapter = new ItemAdapter(items);
recyclerView.setAdapter(adapter);
}
});
}
}

Alternative Implementation with Direct ViewModel Initialization

Step 2: Create a model class for the data received from the API

public class Post {
private int id;
private String title;
private String body;
}

Step 3: Create a Retrofit interface for API endpoints

public interface ApiService {
@GET("posts") // Adjust the endpoint based on your API
Call<List<Post>> getPosts();
}

Step 4: Create a ViewModel to handle API calls

public class PostViewModel extends ViewModel {
private MutableLiveData<List<Post>> postsLiveData = new MutableLiveData<>();
private ApiService apiService;

public void init(ApiService apiService) {
this.apiService = apiService;
fetchPosts();
}

public MutableLiveData<List<Post>> getPostsLiveData() {
return postsLiveData;
}

private void fetchPosts() {
apiService.getPosts().enqueue(new Callback<List<Post>>() {
@Override
public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
if (response.isSuccessful()) {
postsLiveData.setValue(response.body());
}
}

@Override
public void onFailure(Call<List<Post>> call, Throwable t) { }
});
}
}

Step 5: Implement the RecyclerView in your activity or fragment using View Binding

public class YourActivity extends AppCompatActivity {
private ActivityMainBinding binding;
private PostAdapter postAdapter;
private PostViewModel postViewModel;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

RecyclerView recyclerView = binding.recyclerView;
recyclerView.setLayoutManager(new LinearLayoutManager(this));
postAdapter = new PostAdapter(); // Create your adapter
recyclerView.setAdapter(postAdapter);

postViewModel = new ViewModelProvider(this).get(PostViewModel.class);
postViewModel.init(ApiClient.getRetrofit().create(ApiService.class));
postViewModel.getPostsLiveData().observe(this, posts -> postAdapter.setPosts(posts));
}
}

Building a Simple Form with View Binding

Step 1: Set up your layout file (activity_main.xml) containing EditText fields and a Button

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">

<EditText
android:id="@+id/editTextName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Name" />

<EditText
android:id="@+id/editTextEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Email" />

<EditText
android:id="@+id/editTextPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Enter Phone" />

<Button
android:id="@+id/buttonSubmit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Submit" />
</LinearLayout>

Step 2: Create your Activity class and implement View Binding

// MainActivity.java
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.yourpackage.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {
private ActivityMainBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
setContentView(view);

binding.buttonSubmit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String name = binding.editTextName.getText().toString().trim();
String email = binding.editTextEmail.getText().toString().trim();
String phone = binding.editTextPhone.getText().toString().trim();

if (!name.isEmpty() && !email.isEmpty() && !phone.isEmpty()) {
String userInfo = "Name: " + name + "\nEmail: " + email + "\nPhone: " + phone;
displayUserInfo(userInfo);
} else {
Toast.makeText(MainActivity.this, "Please fill in all fields", Toast.LENGTH_SHORT).show();
}
}
});
}

private void displayUserInfo(String userInfo) {
Toast.makeText(this, userInfo, Toast.LENGTH_LONG).show();
}
}

Notes App with Room Database

Step 2: Create an entity for your Note

@Entity(tableName = "notes")
public class Note {
@PrimaryKey(autoGenerate = true)
private int id;
private String title;
private String content;
}

Step 3: Create a DAO (Data Access Object) interface for performing database operations

@Dao
public interface NoteDao {
@Insert
void insert(Note note);

@Update
void update(Note note);

@Delete
void delete(Note note);

@Query("SELECT * FROM notes")
List<Note> getAllNotes();
}

Step 4: Create a Room Database class

import androidx.room.Database;
import androidx.room.RoomDatabase;

@Database(entities = {Note.class}, version = 1)
public abstract class NoteDatabase extends RoomDatabase {
public abstract NoteDao noteDao();
}

Step 5: Create a RecyclerView Adapter for displaying notes

public class NoteAdapter extends RecyclerView.Adapter<NoteAdapter.NoteViewHolder> {
private List<Note> noteList;

@NonNull
@Override
public NoteViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.note_item, parent, false);
return new NoteViewHolder(itemView);
}

@Override
public void onBindViewHolder(@NonNull NoteViewHolder holder, int position) {
Note currentNote = noteList.get(position);
holder.textViewTitle.setText(currentNote.getTitle());
holder.textViewContent.setText(currentNote.getContent());
}

@Override
public int getItemCount() {
return noteList.size();
}

public static class NoteViewHolder extends RecyclerView.ViewHolder {
public TextView textViewTitle;
public TextView textViewContent;

public NoteViewHolder(@NonNull View itemView) {
super(itemView);
textViewTitle = itemView.findViewById(R.id.text_view_title);
textViewContent = itemView.findViewById(R.id.text_view_content);
}
}
}

Step 6: Implement your main activity to manage adding, displaying, and deleting notes

public class MainActivity extends AppCompatActivity {
private NoteDatabase noteDatabase;
private NoteAdapter noteAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

RecyclerView recyclerView = findViewById(R.id.recycler_view_notes);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
noteAdapter = new NoteAdapter();
recyclerView.setAdapter(noteAdapter);

noteDatabase = Room.databaseBuilder(getApplicationContext(),
NoteDatabase.class, "note_database").build();

loadNotes();

new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
@Override
public boolean onMove(@NonNull RecyclerView recyclerView,
@NonNull RecyclerView.ViewHolder viewHolder,
@NonNull RecyclerView.ViewHolder target) {
return false;
}

@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
int position = viewHolder.getAdapterPosition();
List<Note> notes = noteAdapter.getNotes();
noteDatabase.noteDao().delete(notes.get(position));
notes.remove(position);
noteAdapter.notifyItemRemoved(position);
}
}).attachToRecyclerView(recyclerView);
}

private void loadNotes() {
List<Note> notes = noteDatabase.noteDao().getAllNotes();
noteAdapter.setNotes(notes);
}
}

Download

PDF Word HTML