Langsung ke konten utama

Room Android Architecture

Android Mads

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

We have more boiler plates while creating SQLite Database in Android even it is small. Room as a library used to remove the boiler plates 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 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 as that to maintain the State of Android Application when the orientation changes. The Life Cycle Activity used to handle the state easily.

Coding Part

Create a new project in Android Studio.

First, Add Google’s maven repository to your project-level build.gradle file.
allprojects {
repositories {
jcenter()
maven { url 'https://maven.google.com' }
}
}
Then, Add following dependencies to your app-level build.gradle file.
compile 'android.arch.persistence.room:runtime:1.0.0-alpha1'
annotationProcessor 'android.arch.persistence.room:compiler:1.0.0-alpha1'
compile 'android.arch.lifecycle:extensions:1.0.0-alpha1'

Creating the Model

Create a Model class and named as ProductModel.
@Entity
public class ProductModel {

@PrimaryKey(autoGenerate = true)
public int itemId;
private String itemName;
private String itemQty;
@TypeConverters(DateConverter.class)
private Date itemAddedDate;

public ProductModel(int itemId, String itemName, String itemQty, Date itemAddedDate) {
this.itemId = itemId;
this.itemName = itemName;
this.itemQty = itemQty;
this.itemAddedDate = itemAddedDate;
}

public void setItemName(String itemName) {
this.itemName = itemName;
}

public void setItemQty(String itemQty) {
this.itemQty = itemQty;
}

public void setItemAddedDate(Date itemAddedDate) {
this.itemAddedDate = itemAddedDate;
}

public String getItemName() {
return itemName;
}

public String getItemQty() {
return itemQty;
}

public Date getItemAddedDate() {
return itemAddedDate;
}

public int getItemId() {
return itemId;
}
}
Here,
  1. @Entity annotation is used to tell the Model Class as Database Table. 
  2. @PrimaryKey annotation is used to set Primary Key for Table and autoGenerate = true is used to set Auto Increment to Primary Key. 
  3. @TypeConverters annotation is used to convert the Date into String and Vice-Versa. The DateConverter is class created by your own as like below.

Creating Type Converter

Create a class and named as DateConverter and Paste the following code.
class DateConverter {

@TypeConverter
public static Date toDate(Long timestamp) {
return timestamp == null ? null : new Date(timestamp);
}

@TypeConverter
public static Long toTimestamp(Date date) {
return date == null ? null : date.getTime();
}
}
This Converter is used to convert date to string and vice versa. Because, We cannot save Date format in SQLite Directly.

Creating Data Access Object(DAO)

Create a class and named as ProductModelDao.class and paste the following code.
Here, the Query for storing and retrieving data from Local DB performed.
@Dao
@TypeConverters(DateConverter.class)
public interface ProductModelDao {

@Query("select * from ProductModel")
LiveData<List<ProductModel>> getAllProducts();

@Query("select * from ProductModel where itemId = :itemId")
ProductModel getProductById(int itemId);

@Insert(onConflict = REPLACE)
void addProduct(ProductModel ProductModel);

@Update(onConflict = REPLACE)
void updateProduct(ProductModel ProductModel);

@Delete
void deleteProduct(ProductModel ProductModel);

}
  1. @Dao annotation indicate this interface as DAO. 
  2. @Query annotation indicate the data surrounded is Queries to retrieve data from DB. 
  3. @Insert, @Update, @Delete,annotations used to insert, update and delete the data stored in DB respectively. 
  4. onConflict indicates that to replace the data when conflicts occurs while performing the tasks..

Creating Database

Create a abstract class and named as AppDataBase.class and pass the following code.
@Database(entities = {ProductModel.class}, version = 1)
public abstract class AppDataBase extends RoomDatabase {
private static AppDataBase INSTANCE;

public static AppDataBase getDatabase(Context context) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDataBase.class, "product_db")
.build();
}
return INSTANCE;
}

public static void destroyInstance() {
INSTANCE = null;
}

public abstract ProductModelDao itemAndPersonModel();
}
  1. @Database annotation indicate this class as Database of our Application. 
  2. entities is an array of tables or entities and separated by comma. 
  3. 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
Room.databaseBuilder(context.getApplicationContext(), AppDataBase.class, "product_db")
.build();
Create Android View Model for Retrieving all the data from DB.
public class ProductListViewModel extends AndroidViewModel {

private final LiveData<List<ProductModel>> itemAndPersonList;
private AppDataBase appDatabase;

public ProductListViewModel(Application application) {
super(application);
appDatabase = AppDataBase.getDatabase(this.getApplication());
itemAndPersonList = appDatabase.itemAndPersonModel().getAllProducts();
}

public LiveData<List<ProductModel>> getItemAndPersonList() {
return itemAndPersonList;
}

public void deleteItem(ProductModel borrowModel) {
new deleteAsyncTask(appDatabase).execute(borrowModel);
}

private static class deleteAsyncTask extends AsyncTask<ProductModel, Void, Void> {

private AppDataBase db;
deleteAsyncTask(AppDataBase appDatabase) {
db = appDatabase;
}
@Override
protected Void doInBackground(final ProductModel... params) {
db.itemAndPersonModel().deleteProduct(params[0]);
return null;
}

}

}
Create Android View Model for Retrieve a single data from DB as well as the code update the Data.
public class AddProductViewModel extends AndroidViewModel {

private AppDataBase appDatabase;

public AddProductViewModel(Application application) {
super(application);
appDatabase = AppDataBase.getDatabase(this.getApplication());
}

public void addProduct(final ProductModel borrowModel) {
new addAsyncTask(appDatabase).execute(borrowModel);
}

private static class addAsyncTask extends AsyncTask {

private AppDataBase db;

addAsyncTask(AppDataBase appDatabase) {
db = appDatabase;
}

@Override
protected Void doInBackground(final ProductModel... params) {
db.itemAndPersonModel().addProduct(params[0]);
return null;
}

}
}
Create Android View Model for Retrieve a insert the Data.
public class UpdateProductViewModel extends AndroidViewModel {

private AppDataBase appDatabase;

public UpdateProductViewModel(Application application) {
super(application);
appDatabase = AppDataBase.getDatabase(this.getApplication());
}

public ProductModel readProduct(final int itemId) {
try {
return new readAsyncTask(appDatabase).execute(itemId).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
return null;
}

public void updateProduct(final ProductModel borrowModel) {
new UpdateProductViewModel.updateAsyncTask(appDatabase).execute(borrowModel);
}

private static class updateAsyncTask extends AsyncTask<ProductModel, Void, Void> {

private AppDataBase db;

updateAsyncTask(AppDataBase appDatabase) {
db = appDatabase;
}

@Override
protected Void doInBackground(final ProductModel... params) {
db.itemAndPersonModel().updateProduct(params[0]);
return null;
}

}

private static class readAsyncTask extends AsyncTask<Integer, Void, ProductModel> {

private AppDataBase db;

readAsyncTask(AppDataBase appDatabase) {
db = appDatabase;
}

@Override
protected ProductModel doInBackground(final Integer... params) {
return db.itemAndPersonModel().getProductById(params[0]);
}
}
}

Creating Custom Adapter

Create Adapter for Recyclerview and Paste the Following code.
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecyclerViewHolder> {

private List<ProductModel> ProductModelList;
private View.OnLongClickListener longClickListener;
private View.OnClickListener clickListener;

public RecyclerViewAdapter(List<ProductModel> ProductModelList,
View.OnLongClickListener longClickListener,
View.OnClickListener clickListener) {
this.ProductModelList = ProductModelList;
this.longClickListener = longClickListener;
this.clickListener = clickListener;
}

@Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new RecyclerViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.recycler_item, parent, false));
}

@Override
public void onBindViewHolder(final RecyclerViewHolder holder, int position) {
ProductModel productModel = ProductModelList.get(position);
holder.itemTextView.setText(productModel.getItemName());
holder.nameTextView.setText(productModel.getItemQty());
holder.dateTextView.setText(productModel.getItemAddedDate().toLocaleString().substring(0, 11));
holder.itemView.setTag(productModel);
holder.itemView.setOnLongClickListener(longClickListener);
holder.itemView.setOnClickListener(clickListener);
}

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

public void addItems(List<ProductModel> ProductModelList) {
this.ProductModelList = ProductModelList;
notifyDataSetChanged();
}

static class RecyclerViewHolder extends RecyclerView.ViewHolder {
private TextView itemTextView;
private TextView nameTextView;
private TextView dateTextView;

RecyclerViewHolder(View view) {
super(view);
itemTextView = view.findViewById(R.id.itemTextView);
nameTextView = view.findViewById(R.id.nameTextView);
dateTextView = view.findViewById(R.id.dateTextView);
}
}
}
To use the View models inside our Application, use LifeCycleActivity instead of extending the Activity. and Access the view models by
public class MainActivity extends AppCompatLifeCycleActivity implements View.OnLongClickListener, View.OnClickListener {

private ProductListViewModel viewModel;
private RecyclerViewAdapter recyclerViewAdapter;
private RecyclerView recyclerView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startActivity(new Intent(MainActivity.this, AddActivity.class));
}
});
recyclerView = findViewById(R.id.recyclerView);
recyclerViewAdapter = new RecyclerViewAdapter(new ArrayList<ProductModel>(), this, this);
recyclerView.setLayoutManager(new LinearLayoutManager(this));

recyclerView.setAdapter(recyclerViewAdapter);

viewModel = ViewModelProviders.of(this).get(ProductListViewModel.class);

viewModel.getItemAndPersonList().observe(MainActivity.this, new Observer<List<ProductModel>>() {
@Override
public void onChanged(@Nullable List<ProductModel> itemAndPeople) {
recyclerViewAdapter.addItems(itemAndPeople);
}
});

}

@Override
protected void onDestroy() {
super.onDestroy();
AppDataBase.destroyInstance();
}

@Override
public boolean onLongClick(View v) {
ProductModel productModel = (ProductModel) v.getTag();
viewModel.deleteItem(productModel);
return true;
}

@Override
public void onClick(View v) {
ProductModel productModel = (ProductModel) v.getTag();
Intent i = new Intent(MainActivity.this, UpdateActivity.class);
i.putExtra("itemId",productModel.itemId);
startActivity(i);
}
}
Here, AppCompatLifeCycleActivity is custom Activity inherited with AppCompatActivity and LifeCycleActivity's feature. Create a class and Named as AppCompatLifeCycleActivity.class and paste the following code.
public class AppCompatLifeCycleActivity extends AppCompatActivity 
implements LifecycleRegistryOwner {

private final LifecycleRegistry mRegistry = new LifecycleRegistry(this);

@Override
public LifecycleRegistry getLifecycle() {
return mRegistry;
}
}
I did this, because of we cannot use setSupportActionbaras like in AppCompatActivity with NoActionBar Theme. You Can simply use LifeCycleActivitywith WithActionBar Themes.
I have added the Add Product and Update Product Activity Screens in the Samples. You Download in the Download Section. If you have any doubt regarding this, feel free to comment in the comment section.

Download Code

You can download the full source code for this tutorial from the following Github link. If you Like this tutorial, Please star it in Github.

Download From Github

Komentar

Postingan populer dari blog ini

FlatBuffers Android Tutorial

FlatBuffers is an efficient cross platform serialization library for C++, Java, C#, Go, Python and JavaScript. It was originally created at Google for game development and other performance-critical applications. FlatBuffers is Open Source (Apache license V2) and available on GitHub . It's currently used by:   Cocos2d-x , the open source mobile game engine and used to serialize the game data. Facebook uses it for client-server communication in the Android app (see the article) . Fun Propulsion Labs at Google in most of libraries and games. Solution overview  The schema will be defind in JSON format, then it will be converted to FlatBuffer format outside the application The Java classes of the Data model will be generated manually using flatc (FlatBuffer compiler) Step 1: Build FlatBuffers Download the source code in Google’s flatbuffers repository .  The build process is described on Google's documentation FlatBuffers Building .  On MacOS for example: Open the xcode proje

QR-Code Generator - Library

In this Post, I introduce my new Gradle Library. This Library is used to Generate QR Code Automatically for our specified input. How to Import the Library: Gradle: compile 'androidmads.library.qrgenearator:QRGenearator:1.0.0' Permission: <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> How to use this Library: After importing this library, use the following lines to use this library. The following lines are used to generated the QR Code // Initializing the QR Encoder with your value to be encoded, type you required and Dimension QRGEncoder qrgEncoder = new QRGEncoder(inputValue, null, QRGContents.Type.TEXT, smallerDimension); try { // Getting QR-Code as Bitmap bitmap = qrgEncoder.encodeAsBitmap(); // Setting Bitmap to ImageView qrImage.setImageBitmap(bitmap); } catch (WriterException e) { Log.v(TAG, e.toString()); } Save QR Code as Image // Save with location, value, bitmap returned and type of Image(JPG/PNG). QRGSaver.save(s

Download file using Okio in Android

Okio is a library that complements java.io and java.nio to make it much easier to access, store, and process your data. Simply Okio is a modern I/O API for Java.  In this post, we will see how to download image or any file using Okio. Okio is component for OkHttp Coding Part Create a new project in Android Studio. Add following dependencies to your  app-level  build.gradle  file. compile 'com.squareup.okhttp3:okhttp:3.6.0' Don't forget to add the following permission in your AndroidManifest.xml <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> Implementation Paste the following code in your Activity and Here, I have kept as MainActivity.java public void downloadImg(View view) { try { Request request = new Request.Builder() .url(imageLink) .build(); new OkHttpClient().newCall(request).enqueue(new Callback() { @Override public void onFail