Room Architecture In Android

In Google I/O 2017, Google announced about Room Architecture for Android. This Architecture is used to maintain the State of Android Application when the orientation changes. As well as google announced about Room Architecture.

Room Architecture in Android

 

Introduction

In Google I/O 2017, Google announced the Room Architecture for Android. This architecture is used to maintain the state of the Android applications when the orientation changes. 

Room

We have numerous boilerplates while creating SQLite Database in Android. Room is a library used to remove the boilerplates like Cursors & Handlers and database can be handled with annotations and model classes. If we remember about Sugar ORM or Active Android, the same approach is dealt with in Room.

We don't want to go for any third party libraries, when the official Android libraries give you an equal, or better solution.

Life Cycle Activity

We have faced the problem mostly so as to maintain the State of Android Application when the orientation changes. The Life Cycle Activity is used to handle the state easily.

Coding Part

I have detailed the article as in the following steps.

 

  • Step 1 - Creating New Project with Empty Activity.
  • Step 2 - Setting up the Library and Manifest.
  • Step 3 - Implementation of Telegram Bot in the Android App.

 

Step 1 - Creating a New Project with Android Studio

  1. Open Android Studio and Select "Create new project".
  2. Name the project as your wish and select your activity template.

    Room Architecture in Android


  3. Click finish button to create a new project in Android Studio.

Step 2 - Setting up the Retrofit Http Library and Manifest

In this part, we will see how to setup the library for the project.

  1. First, add Google’s maven repository to your project-level build.gradle file.
    1. allprojects {  
    2.     repositories {  
    3.         jcenter()  
    4.         maven { url 'https://maven.google.com' }  
    5.     }  
    6. }  
  1. Then, add the following dependencies to your app-level build.gradle file.
    1. compile 'android.arch.persistence.room:runtime:1.0.0-alpha1'  
    2. annotationProcessor 'android.arch.persistence.room:compiler:1.0.0-alpha1'  
    3. compile 'android.arch.lifecycle:extensions:1.0.0-alpha1'  
  1. Then click Sync Now to setup your project.

Step 3 - Implementation of Room Architecture in Android

  1. Create a Model class named as ProductModel.
    1. @Entity  
    2. public class ProductModel {  
    3.   
    4.     @PrimaryKey(autoGenerate = true)  
    5.     public int itemId;  
    6.     private String itemName;  
    7.     private String itemQty;  
    8.     @TypeConverters(DateConverter.class)  
    9.     private Date itemAddedDate;  
    10.   
    11.     public ProductModel(int itemId, String itemName, String itemQty, Date itemAddedDate) {  
    12.         this.itemId = itemId;  
    13.         this.itemName = itemName;  
    14.         this.itemQty = itemQty;  
    15.         this.itemAddedDate = itemAddedDate;  
    16.     }  
    17.   
    18.     public void setItemName(String itemName) {  
    19.         this.itemName = itemName;  
    20.     }  
    21.   
    22.     public void setItemQty(String itemQty) {  
    23.         this.itemQty = itemQty;  
    24.     }  
    25.   
    26.     public void setItemAddedDate(Date itemAddedDate) {  
    27.         this.itemAddedDate = itemAddedDate;  
    28.     }  
    29.   
    30.     public String getItemName() {  
    31.         return itemName;  
    32.     }  
    33.   
    34.     public String getItemQty() {  
    35.         return itemQty;  
    36.     }  
    37.   
    38.     public Date getItemAddedDate() {  
    39.         return itemAddedDate;  
    40.     }  
    41.   
    42.     public int getItemId() {  
    43.         return itemId;  
    44.     }  
    45. }  
    Here, @Entity annotation is used to tell the Model Class about Database Table.

    @PrimaryKey annotation is used to set Primary Key for Table and autoGenerate = true is used to set Auto Increment to Primary Key.

    @TypeConverters annotation is used to convert the Date into String and Vice-Versa. The DateConverter is class created on your own as below.
  1. Create a class named as DateConverter and Paste the following code.
    1. class DateConverter {  
    2.   
    3.     @TypeConverter  
    4.     public static Date toDate(Long timestamp) {  
    5.         return timestamp == null ? null : new Date(timestamp);  
    6.     }  
    7.   
    8.     @TypeConverter  
    9.     public static Long toTimestamp(Date date) {  
    10.         return date == null ? null : date.getTime();  
    11.     }  
    12. }  
    This Converter is used to convert date to string and vice versa. Because we cannot save Date format in SQLite Directly.
  1. Create a class and name it as class and paste the following code. Here, the query for storing and retrieving data from Local DB is performed.
    1. @Dao  
    2. @TypeConverters(DateConverter.class)  
    3. public interface ProductModelDao {  
    4.       
    5.     @Query("select * from ProductModel")  
    6.     LiveData<List<ProductModel>> getAllProducts();  
    7.   
    8.     @Query("select * from ProductModel where itemId = :itemId")  
    9.     ProductModel getProductById(int itemId);  
    10.   
    11.     @Insert(onConflict = REPLACE)  
    12.     void addProduct(ProductModel ProductModel);  
    13.   
    14.     @Update(onConflict = REPLACE)  
    15.     void updateProduct(ProductModel ProductModel);  
    16.   
    17.     @Delete  
    18.     void deleteProduct(ProductModel ProductModel);  
    19.       
    20. }  

@Dao annotation indicates this interface is DAO.

@Query annotation indicates the data are queries to retrieve data from DB.

@Insert, @Update, @Delete annotations are used to insert, update and delete the data stored in the DB respectively.

onConflict indicates to replace the data when conflicts occur while performing the tasks.

  1. Create an abstract class and name it as class and paste the following code.
    1. @Database(entities = {ProductModel.class}, version = 1)  
    2. public abstract class AppDataBase extends RoomDatabase {  
    3.     private static AppDataBase INSTANCE;  
    4.   
    5.     public static AppDataBase getDatabase(Context context) {  
    6.         if (INSTANCE == null) {  
    7.             INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDataBase.class"product_db")  
    8.                     .build();  
    9.         }  
    10.         return INSTANCE;  
    11.     }  
    12.   
    13.     public static void destroyInstance() {  
    14.         INSTANCE = null;  
    15.     }  
    16.   
    17.     public abstract ProductModelDao itemAndPersonModel();  
    18. }  

@Database annotation indicates this class is the database of our application. Entities is an array of tables or entities separated by commas. The version is used to denote the version of the database. This class is used to create the database and get an instance of it.

We can create the database using this query.

  1. Room.databaseBuilder(context.getApplicationContext(), AppDataBase.class"product_db")  
  2. .build();  
  1. Create Android View Model for retrieving all the data from DB.
    1. public class ProductListViewModel extends AndroidViewModel {  
    2.   
    3.     private final LiveData<List<ProductModel>> itemAndPersonList;  
    4.     private AppDataBase appDatabase;  
    5.   
    6.     public ProductListViewModel(Application application) {  
    7.         super(application);  
    8.         appDatabase = AppDataBase.getDatabase(this.getApplication());  
    9.         itemAndPersonList = appDatabase.itemAndPersonModel().getAllProducts();  
    10.     }  
    11.   
    12.     public LiveData<List<ProductModel>> getItemAndPersonList() {  
    13.         return itemAndPersonList;  
    14.     }  
    15.   
    16.     public void deleteItem(ProductModel borrowModel) {  
    17.         new deleteAsyncTask(appDatabase).execute(borrowModel);  
    18.     }  
    19.   
    20.     private static class deleteAsyncTask extends AsyncTask<ProductModel, Void, Void> {  
    21.   
    22.         private AppDataBase db;  
    23.         deleteAsyncTask(AppDataBase appDatabase) {  
    24.             db = appDatabase;  
    25.         }  
    26.         @Override  
    27.         protected Void doInBackground(final ProductModel... params) {  
    28.             db.itemAndPersonModel().deleteProduct(params[0]);  
    29.             return null;  
    30.         }  
    31.     }  
    32. }  
  1. Create Android View Model for retrieving a single data from the DB as well as the code to update the Data.
    1. public class AddProductViewModel extends AndroidViewModel {  
    2.   
    3.     private AppDataBase appDatabase;  
    4.   
    5.     public AddProductViewModel(Application application) {  
    6.         super(application);  
    7.         appDatabase = AppDataBase.getDatabase(this.getApplication());  
    8.     }  
    9.   
    10.     public void addProduct(final ProductModel borrowModel) {  
    11.         new addAsyncTask(appDatabase).execute(borrowModel);  
    12.     }  
    13.   
    14.     private static class addAsyncTask extends AsyncTask {  
    15.   
    16.         private AppDataBase db;  
    17.   
    18.         addAsyncTask(AppDataBase appDatabase) {  
    19.             db = appDatabase;  
    20.         }  
    21.   
    22.         @Override  
    23.         protected Void doInBackground(final ProductModel... params) {  
    24.             db.itemAndPersonModel().addProduct(params[0]);  
    25.             return null;  
    26.         }  
    27.   
    28.     }  
    29. }  
  1. Create Android View Model for retrieving and inserting the Data.
    1. public class UpdateProductViewModel extends AndroidViewModel {  
    2.     private AppDataBase appDatabase;  
    3.     public UpdateProductViewModel(Application application) {  
    4.         super(application);  
    5.         appDatabase = AppDataBase.getDatabase(this.getApplication());  
    6.     }  
    7.   
    8.     public ProductModel readProduct(final int itemId) {  
    9.         try {  
    10.             return new readAsyncTask(appDatabase).execute(itemId).get();  
    11.         } catch (InterruptedException | ExecutionException e) {  
    12.             e.printStackTrace();  
    13.         }  
    14.         return null;  
    15.     }  
    16.   
    17.     public void updateProduct(final ProductModel borrowModel) {  
    18.         new UpdateProductViewModel.updateAsyncTask(appDatabase).execute(borrowModel);  
    19.     }  
    20.   
    21.     private static class updateAsyncTask extends AsyncTask<ProductModel, Void, Void> {  
    22.   
    23.         private AppDataBase db;  
    24.   
    25.         updateAsyncTask(AppDataBase appDatabase) {  
    26.             db = appDatabase;  
    27.         }  
    28.   
    29.         @Override  
    30.         protected Void doInBackground(final ProductModel... params) {  
    31.             db.itemAndPersonModel().updateProduct(params[0]);  
    32.             return null;  
    33.         }  
    34.   
    35.     }  
    36.   
    37.     private static class readAsyncTask extends AsyncTask<Integer, Void, ProductModel> {  
    38.   
    39.         private AppDataBase db;  
    40.   
    41.         readAsyncTask(AppDataBase appDatabase) {  
    42.             db = appDatabase;  
    43.         }  
    44.   
    45.         @Override  
    46.         protected ProductModel doInBackground(final Integer... params) {  
    47.             return db.itemAndPersonModel().getProductById(params[0]);  
    48.         }  
    49.     }  
    50. }  
  1. Create Adapter for Recyclerview and paste the following code.
    1. public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecyclerViewHolder> {  
    2.   
    3.     private List<ProductModel> ProductModelList;  
    4.     private View.OnLongClickListener longClickListener;  
    5.     private View.OnClickListener clickListener;  
    6.   
    7.     public RecyclerViewAdapter(List<ProductModel> ProductModelList,  
    8.                                View.OnLongClickListener longClickListener,  
    9.                                View.OnClickListener clickListener) {  
    10.         this.ProductModelList = ProductModelList;  
    11.         this.longClickListener = longClickListener;  
    12.         this.clickListener = clickListener;  
    13.     }  
    14.   
    15.     @Override  
    16.     public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  
    17.         return new RecyclerViewHolder(LayoutInflater.from(parent.getContext())  
    18.                 .inflate(R.layout.recycler_item, parent, false));  
    19.     }  
    20.   
    21.     @Override  
    22.     public void onBindViewHolder(final RecyclerViewHolder holder, int position) {  
    23.         ProductModel productModel = ProductModelList.get(position);  
    24.         holder.itemTextView.setText(productModel.getItemName());  
    25.         holder.nameTextView.setText(productModel.getItemQty());  
    26.         holder.dateTextView.setText(productModel.getItemAddedDate().toLocaleString().substring(0, 11));  
    27.         holder.itemView.setTag(productModel);  
    28.         holder.itemView.setOnLongClickListener(longClickListener);  
    29.         holder.itemView.setOnClickListener(clickListener);  
    30.     }  
    31.   
    32.     @Override  
    33.     public int getItemCount() {  
    34.         return ProductModelList.size();  
    35.     }  
    36.   
    37.     public void addItems(List<ProductModel> ProductModelList) {  
    38.         this.ProductModelList = ProductModelList;  
    39.         notifyDataSetChanged();  
    40.     }  
    41.   
    42.     static class RecyclerViewHolder extends RecyclerView.ViewHolder {  
    43.         private TextView itemTextView;  
    44.         private TextView nameTextView;  
    45.         private TextView dateTextView;  
    46.   
    47.         RecyclerViewHolder(View view) {  
    48.             super(view);  
    49.             itemTextView = view.findViewById(R.id.itemTextView);  
    50.             nameTextView = view.findViewById(R.id.nameTextView);  
    51.             dateTextView = view.findViewById(R.id.dateTextView);  
    52.         }  
    53.     }  
    54. }  
  1. To use the View models inside our Application, use LifeCycleActivity instead of extending the Activity and Access the view models:
    1. public class MainActivity extends AppCompatLifeCycleActivity implements View.OnLongClickListener, View.OnClickListener {  
    2.   
    3.     private ProductListViewModel viewModel;  
    4.     private RecyclerViewAdapter recyclerViewAdapter;  
    5.     private RecyclerView recyclerView;  
    6.   
    7.     @Override  
    8.     protected void onCreate(Bundle savedInstanceState) {  
    9.         super.onCreate(savedInstanceState);  
    10.         setContentView(R.layout.activity_main);  
    11.         Toolbar toolbar = findViewById(R.id.toolbar);  
    12.         setSupportActionBar(toolbar);  
    13.   
    14.         FloatingActionButton fab = findViewById(R.id.fab);  
    15.         fab.setOnClickListener(new View.OnClickListener() {  
    16.             @Override  
    17.             public void onClick(View view) {  
    18.                 startActivity(new Intent(MainActivity.this, AddActivity.class));  
    19.             }  
    20.         });  
    21.         recyclerView = findViewById(R.id.recyclerView);  
    22.         recyclerViewAdapter = new RecyclerViewAdapter(new ArrayList<ProductModel>(), thisthis);  
    23.         recyclerView.setLayoutManager(new LinearLayoutManager(this));  
    24.   
    25.         recyclerView.setAdapter(recyclerViewAdapter);  
    26.   
    27.         viewModel = ViewModelProviders.of(this).get(ProductListViewModel.class);  
    28.   
    29.         viewModel.getItemAndPersonList().observe(MainActivity.thisnew Observer<List<ProductModel>>() {  
    30.             @Override  
    31.             public void onChanged(@Nullable List<ProductModel> itemAndPeople) {  
    32.                 recyclerViewAdapter.addItems(itemAndPeople);  
    33.             }  
    34.         });  
    35.   
    36.     }  
    37.   
    38.     @Override  
    39.     protected void onDestroy() {  
    40.         super.onDestroy();  
    41.         AppDataBase.destroyInstance();  
    42.     }  
    43.   
    44.     @Override  
    45.     public boolean onLongClick(View v) {  
    46.         ProductModel productModel = (ProductModel) v.getTag();  
    47.         viewModel.deleteItem(productModel);  
    48.         return true;  
    49.     }  
    50.   
    51.     @Override  
    52.     public void onClick(View v) {  
    53.         ProductModel productModel = (ProductModel) v.getTag();  
    54.         Intent i = new Intent(MainActivity.this, UpdateActivity.class);  
    55.         i.putExtra("itemId",productModel.itemId);  
    56.         startActivity(i);  
    57.     }  
    58. }  

Here, AppCompatLifeCycleActivity is a custom Activity inherited with AppCompatActivity and LifeCycleActivity's feature. Create a class and name it AppCompatLifeCycleActivity.class and paste the following code.

  1. public class AppCompatLifeCycleActivity extends AppCompatActivity   
  2.                    implements LifecycleRegistryOwner {  
  3.   
  4.     private final LifecycleRegistry mRegistry = new LifecycleRegistry(this);  
  5.   
  6.     @Override  
  7.     public LifecycleRegistry getLifecycle() {  
  8.         return mRegistry;  
  9.     }  
  10. }  

I did this, because we cannot use setSupportActionbaras like in AppCompatActivity with NoActionBar Theme. You can simply use LifeCycleActivity with ActionBar Themes.

I have added the Add Product and Update Product Activity Screens in the Samples. You can download it in the Download Section. If you have any doubts regarding this, feel free to comment in the comment section.

Download Code

You can download the full source code of the article in GitHub. If you like this article, do star the repo in GitHub