--

Showing posts with label AKC. Show all posts
Showing posts with label AKC. Show all posts

Monday, 7 January 2019

Chapter -5 : Modern Android Architecture ‘Android Jetpack’ - Handling background tasks (WorkManager)

        In this Android Jetpack, team at Google release one library specifically designed for scheduling and managing the background tasks. It’s called “WorkManager”. The WorkManager API makes it easy to specify deferrable, asynchronous tasks and when they should run. These APIs let you create a task and hand it off to WorkManager to run immediately or at an appropriate time.

Drawbacks of existing background task APIs

       Earlier we had AlarmManager, JobScheduler, FirebaseJobDispatcher for scheduling the background tasks. But the issues were
  • JobScheduler – Available only for API >= 21
  • FirebaseJobDispatcher – For backward compatibility
So developer had to understand which method to use when. To overcome these issues we have WorkManager, and it will automatically choose the best method for your task and you do not need to write logic for it. So basically WorkManager is providing an abstraction layer. It gives us a clean interface hiding all the complexities and giving the guaranteed execution of the task.


WorkManager Features

  1. It is fully backward compatible so in your code you do not need to write if-else for checking the android version.
  2. So it has benefits over the Firebase Job Dispatcher which backwards compatible but not work for device without Google play service.
  3. With WorkManager we can check the status of the work.
  4. Tasks can be chained as well, for example when one task is finished it can start another.
  5. And it provides guaranteed execution with the constraints, we have many constrained available that we will see ahead. 

While scheduling background/long running task like network availability, device in doze mode (Like, if your app is in DOZE mode then it wouldn’t execute, it wouldn’t wake up your phone just to do that work), sync data only when charging so many but WorkManager is taking care of all these constraints and give app guaranteed to be executed even if device get rebooted or app get exited without executing that task.


Technical details of Base classes

Worker - Specifies what tasks we need to perform. By extending this class and perform the work here.
WorkRequest - Represents an individual task. At a minimum, a WorkRequest object specifies which Worker class should perform the task. Every WorkRequest has an auto-generated unique ID; we can use the ID to do things like cancel a queued task or get the task's state. We will be using one of the direct subclasses, OneTimeWorkRequest or 

PeriodicWorkRequest.
WorkManager - Enqueues and manages the work requests. You pass your WorkRequest object to WorkManager to enqueue the task.
WorkInfo - The class contains information about the works. For each WorkRequest we can get a LiveData using WorkManager. The LiveData holds the WorkInfo and by observing it we can determine the Work Informations.

Creating a Worker

         For creating a worker we need to create a class and then in the class we need to extend Worker. So here I am creating a class named NotificationWorker. This class has one abstract method called doWork(). As the name suggests, you need to perform the work you want to do in the background. This method will be called in the background/worker thread. Write a program to perform the task in this method.

public class NotificationWorker extends Worker {
public static final String TASK_DESC = "Desc";
public NotificationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@NonNull
@Override
public Result doWork() {
//getting the input data
String taskDesc = getInputData().getString(TASK_DESC);
displayNotification("Hello", "Welcome to my world!"+"\n"+taskDesc);
//setting output data
Data data = new Data.Builder()
.putString(TASK_DESC, "The notification is shown.")
.build();
setOutputData(data);
return Result.SUCCESS;
}
private void displayNotification(String title, String task) {
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("truedreamz", "truedreamz", NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder notification = new NotificationCompat.Builder(getApplicationContext(), "truedreamz")
.setContentTitle(title)
.setContentText(task)
.setSmallIcon(R.mipmap.ic_launcher);
notificationManager.notify(1, notification.build());
}
}


WorkResult has three values
1) SUCCESS
2) FAILURE
3) RETRY : Means encountered a transient error i.e if device lost network connection in the middle so we will have to retry after little bit some back off.


Performing the Work


Now let’s perform the work that we created. For this first come inside MainActivity.java and write the following code.




OneTimeWorkRequest: Used when we want to perform the work only once. This is because WorkRequest is an abstract class and we have to use the direct subclasses of it.
Finally to enqueue the work we simple used the enqueue() method from WorkManager.

Determining Work Status


So we successfully performed the work. Now let’s learn how we can determine the status of the work.



Now you can run your application to see it is working fine.



Data transfer to/from WorkManager


We can also pass data to our WorkManager class and we can also get back some data after finishing the work.

Sending Data

Data data = new Data.Builder()
.putString(NotificationWorker.TASK_DESC, "The data passed from MainActivity")
.build();
final OneTimeWorkRequest oneTimeWorkRequest=
new OneTimeWorkRequest.Builder(NotificationWorker.class)
.setInputData(data)
.build();


So to receive data we will do the following modification in our NotificationWorker class.
String taskDesc = getInputData().getString(TASK_DESC);

Adding Constraints


Now let’s add some constraints in our work so that it will execute at a specific time. We have many constraints available for example.

  • setRequiresCharging(boolean b): If it is set true the work will only be done when the device is charging.
  • setRequiresBatteryNotLow(boolean b): Work will be done only when the battery of the device is not low.
  • setRequiresDeviceIdle(boolean b): Work will be done only when the device is idle.

Canceling Work

We can also cancel the work if required. For this we have a method cancelWorkById(). It takes the work id as an argument that we can get from our WorkRequest object.

We also have the following methods to cancel the work.
  • cancelAllWork(): To cancel all the work.
  • cancelAllWorkByTag(): To cancel all works of a specific tag.
  • cancelUniqueWork(): To cancel a unique work.


PeriodicWorkRequest


Sometimes it is needed to perform the work periodically for example taking backup to the server. In scenarios like this we can use PeriodicWorkRequest class. Everything else is the same.

public class PeriodicToastWorker extends Worker {
public PeriodicToastWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@NonNull
@Override
public Result doWork() {
//getting the input data
displayNotification("Hello", "Periodic notification!");
return Result.SUCCESS;
}
private void displayNotification(String title, String task) {
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("truedreamz", "truedreamz", NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder notification = new NotificationCompat.Builder(getApplicationContext(), "truedreamz")
.setContentTitle(title)
.setContentText(task)
.setSmallIcon(R.mipmap.ic_launcher);
notificationManager.notify(1, notification.build());
}
}




The WorkManager attempts to run your task at the interval you request, subject to the constraints you impose and its other requirements.
I have uploaded the latest source code in GitHub for your reference. Kindly raise your queries in the command section.

References :
https://developer.android.com/topic/libraries/architecture/workmanager/
https://developer.android.com/topic/libraries/architecture/workmanager/basics#java
https://www.simplifiedcoding.net/android-workmanager-tutorial/


Happy coding!!!
Cheers!!!

Wednesday, 26 December 2018

Chapter - 4 : Modern Android Architecture ‘Android Jetpack’ - Navigation library

      Navigation Architecture Component was introduced with Android Jetpack to facilitate the implementation of the navigation within your app and simultaneously enforce guidelines that will provide a consistent and predictable navigation to the end users.


Why it helps ?

  • Aside from one-time setup, an app should have a fixed starting screen when started from the launcher.
  • Android navigation stack should follow a LIFO structure. With the starting screen at bottom of the stack and the current on top.
  • The up button should never exit your app.
  • With the exception of the bottom element of the stack, the up button should function identically to the system back button.
  • The navigation stack should be consistent even if it’s triggered from an outside source. This is a common mistake when using deep links to app content, where the system back button and up button have distinct destinations.


Key definitions


NavHost: Context or container that has all the information it needs to handle any navigation-related actions on its own.
NavController: Component used to perform navigation between destinations.
NavigationUI: Component that connects the navigation with some material design components (such as the BottomNavigationView and the DrawerLayout)


Implement Navigation


      The Navigation Architecture Component is designed to have a single activity with multiple Fragments. The Activity hosts a Navigation Graph. If your app has multiple activities each Activity hosts its own Navigation Graph.

Gradle Dependency




Add the following dependencies to your app or module build.gradle file



Navigation Graph XML

       This component handles navigation as a graph, where each node represents a screen. These nodes are called destinations and are bounded by each other through actions. The set of destinations and actions compose the navigation graph.

       Let’s start by the creation of our navigation graph. So, on your res directory go to New > Android resource file and select Navigation from the resource type list. On the newly created navigation directory, we can start writing our navigation graph.



android:name: Attribute that flags the fragment as a NavHost — A container for the navigation graph that allows destinations to be swapped as the user navigates through the app.
app:navGraph: Connects the NavHostFragment to the navigation graph resource.
app:defaultNavHost: When set to true, NavHostFragment is capable of intercepting the system’s back button presses.
Now you should be able to hop to the design editor of your navigation graph resource and see which resource holds your NavFragmentHost.

       Now going back to handling up and back navigation, how does it happen? Since the navigation graph is the single source of truth for all navigation within the app, the navigation component does the right thing when navigating back or up. Not only does it handle this, but it correctly takes care of things such as the back stack, transactions, pop behaviour and transition animations.



Now that the layouts are ready, let’s see how to navigate from one Fragment to the other via the actions. NavController manages app navigation within the NavHost.

public class FirstFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.navigation_first_fragment, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
final Bundle bundle = new Bundle();
bundle.putBoolean("test_boolean", true);
final NavController navController = Navigation.findNavController(getActivity(), R.id.my_nav_host_fragment);
Button button = view.findViewById(R.id.button_frag1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
navController.navigate(R.id.action_firstFragment_to_secondFragment, bundle);
}
});
}
}


Trigger navigation

       So we have established a connection with a destination, the next move is to actually that transition, right? Now, each NavHost has a controller — NavController — that is capable of swapping destinations with one of these two methods:
navigate(): Pushes the specified action destination to the stack.
navigateUp(): Pops to the top destination on the stack. On this case, this method would trigger an app exit since fragment A is the last on the stack.

Overall Jetpack makes android development easy and it helps you to focus more on your app’s business logic rather than spending more time on framework specific implementations.

I have uploaded the latest source code in GitHub for your reference. Kindly raise your queries in the command section.


Reference

https://developer.android.com/topic/libraries/architecture/navigation/
https://proandroiddev.com/android-jetpack-navigation-to-the-rescue-fe588271d36
https://medium.com/deemaze-software/android-jetpack-navigation-architecture-component-b603c9a8100c


Happy coding!!!
Cheers!!!

Thursday, 8 November 2018

Chapter -2 : Modern Android Architecture ‘Android Jetpack’ - Working with DataBinding


       The Data Binding Library i.e. support library enables us to bind UI components in our layouts to data sources in your app using a declarative format rather than programmatically. In Simple words, Data binding enables a way to combine the UI with business logic allowing the UI values to update automatically without manual intervention.

Benefits

  • Reduces lot of boilerplate code in our business logic while sync up the UI when new data is available. 
  • Making them simpler and easier to maintain. 
  • Improve the app's performance 
  • Help prevent memory leaks and null pointer exceptions.


How to use ?

To get started with DataBinding, open the build.gradle located under app and enable dataBinding under android module. Once enabled, Sync the project



Adding Data Binding element to Layout file


The expression language allows us to write expressions that connect variables to the views in the layout. The next step in converting the layout file to a data binding layout file is to add the data element. To enable DataBinding in a layout, the root element should start with <layout> tag. Along with it, <data> and <variable> tags are used.



<layout> – Indicate the compiler that this layout has data binding in it so generate the binding class for this layout.
<import> – Similar to how we interpret imports in normal classes. Import a class in this layout.
<variable> – similar to how we interpret variables in normal classes. Declare a variable 'name' and it’s type for the layout to use.
<data> – Parent tag for <import> and <variable> tags for the “data” that we are going to bind for this layout.


Access data in layout through Layout Expressions




It’s structured like a normal class where our imports and most of our variables are declared at the top and we use them at the bottom. The user variable declared within data describes a property that may be used within this layout. Also, if you want to use expressions inside your layout, you can call attribute properties using the “@{}" syntax.


Project structure for Binding Data




The Data Binding Library provides classes and methods to easily observe data for changes. You don't have to worry about refreshing the UI when the underlying data source changes. You can make your variables or their properties observable. The library allows you to make objects, fields, or collections observable.

public class User extends BaseObservable {
String username;
String email;
String userImage;
String info;
public ObservableField<Long> numberOfFriends = new ObservableField<>();
public ObservableField<Long> numberOfArticles = new ObservableField<>();
public ObservableField<Long> numberOfFavourite = new ObservableField<>();
public User() {
}
@Bindable
public String getUsername() {
return username; 
}
public void setUsername(String username) {
this.username = username;
notifyPropertyChanged(BR.username);
}
@BindingAdapter({"profileImage"})
public static void loadImage(ImageView view, String imageUrl) {
Glide.with(view.getContext())
.load(imageUrl)
.apply(RequestOptions.circleCropTransform())
.into(view);
}
@Bindable
public String getUserImage() {
return userImage;
}
public void setUserImage(String userImage) {
this.userImage = userImage;
notifyPropertyChanged(BR.userImage);
}
@Bindable
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
notifyPropertyChanged(BR.info);
}
public ObservableField<Long> getNumberOfFriends() {
return numberOfFriends;
}
public ObservableField<Long> getNumberOfArticles() {
return numberOfArticles;
}
public ObservableField<Long> getNumberOfFavourite() {
return numberOfFavourite;
}
}
  • To make User pojo class Observable, extend the class from BaseObservable. For demonstration, both Observable and ObservableField are used in the same class.
  • For variables username, email, userImage and info., @Bindable annotation is used and notifyPropertyChanged is called upon setting new data if needed.
  • Variables numberOfArticless, numberOfFriends, numberOfFavourites are declared as ObservableFields.
  • @BindingAdapter is used to bind profileImage to ImageView in order to load the image from URL using Glide library.


Generating binding class

When you set the root tag of your layout to <layout>, a binding class is generated by the Data Binding library. For instance, activity_main.xml will have a binding class called ActivityMainBinding.
Note : This class holds all the bindings from the layout properties to the layout’s views and knows how to assign values for the binding expressions.



If you are using data binding items in a Fragment, ListView, or RecyclerView adapter, use the inflate() methods of the binding classes or the DataBindingUtil class:




In this chapter, we will make a very simple app that loads images in RecyclerView using data binding library.

DataBinding in RecyclerView


Binding a RecyclerView layout is similar to normal binding except few changes in onCreateViewHolder and onBindViewHolder methods. Create layout named article_row_item.xml. This layout contains an ImageView to render the image in RecyclerView. In this layout, data binding is enabled by keeping the root element as <layout>. The Post model in bound to this layout using <variable> tag.



Generating adapter binding class


Create a class named ArticleAdapter.java under view package. As the layout name is article_row_item.xml, the generated binding class will be ArticleRowItemBinding. In onCreateViewHolder() method, article_row_item layout is inflated with the help of ArticleRowItemBinding class. articleViewHolder.rowItemBinding.setArticle() binds the Post model to each row.

public class ArticleAdapter extends RecyclerView.Adapter<ArticleAdapter.ArticleViewHolder> {
private List<Article> articleList;
private LayoutInflater layoutInflater;
private ArticlesAdapterListener listener;
public ArticleAdapter(List<Article> articleList, ArticlesAdapterListener listener) {
this.articleList = articleList;
this.listener = listener;
}
@NonNull
@Override
public ArticleViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
if (null == layoutInflater) {
layoutInflater = LayoutInflater.from(viewGroup.getContext());
}
ArticleRowItemBinding articleRowItemBinding = DataBindingUtil.inflate(layoutInflater, R.layout.article_row_item, viewGroup, false);
return new ArticleViewHolder(articleRowItemBinding);
}
@Override
public void onBindViewHolder(@NonNull ArticleViewHolder articleViewHolder, final int i) {
articleViewHolder.rowItemBinding.setArticle(articleList.get(i));
articleViewHolder.rowItemBinding.thumbnail.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.onArticleClicked(articleList.get(i));
}
}
});
}
@Override
public int getItemCount() {
return articleList.size();
}
public class ArticleViewHolder extends RecyclerView.ViewHolder {
private ArticleRowItemBinding rowItemBinding;
public ArticleViewHolder(final ArticleRowItemBinding binding) {
super(binding.getRoot());
this.rowItemBinding = binding;
}
}
public interface ArticlesAdapterListener {
void onArticleClicked(Article post);
}
}


Loading RecyclerView in MainActivity


As the main activity layout name is activity_main, the generated binding class will be ActivityMainBinding. loadUserData() renders the user information such as username, , articles, friends and favourite count. init() initialize the RecyclerView with sample images data. AppClickHandlers handles the click events of UI elements. Here, all the binding of click events is done via xml layout only. We don’t explicitly assign anything from activity code.

public class MainActivity extends AppCompatActivity implements ArticleAdapter.ArticlesAdapterListener {
private User user;
private ActivityMainBinding binding;
private AppClickHandlers handler;
private RecyclerView recyclerView;
private ArticleAdapter articleAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
handler = new AppClickHandlers(this);
loadUserData();
init();
}

private void loadUserData() {
user = new User();
user.setUsername("Mr. Sherlock Holmes");
user.setUserImage("https://tse4.mm.bing.net/th?id=OIP.gHhJlg-RAvR-XosdERsIMQHaEo&pid=Api&w=1440&h=900&rs=1&p=0");
// updating ObservableField
user.numberOfArticles.set(1500L);
user.numberOfFriends.set(205090L);
user.numberOfFavourite.set(10L);
// display user
binding.setUser(user);
// assign click handlers
binding.setHandlers(handler);
}
private void init() {
recyclerView = binding.recyclerView;
recyclerView.setLayoutManager(new GridLayoutManager(this, 3));
recyclerView.addItemDecoration(new GridItemDecoration(3, ImageUtil.dpToPx(MainActivity.this, 4), true));
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setNestedScrollingEnabled(false);
articleAdapter = new ArticleAdapter(getArticles(), this);
recyclerView.setAdapter(articleAdapter);
}
private ArrayList<Article> getArticles() {
ArrayList<Article> articles = new ArrayList<>();
for (int i = 1; i < 10; i++) {
Article article = new Article();
article.setImageUrl("https://tse3.mm.bing.net/th?id=OIP.f1bDVK_DN6xiTaYAM79ucgHaEK&pid=Api");
articles.add(article);
}
return articles;
}

@Override
public void onArticleClicked(Article article) {
Toast.makeText(getApplicationContext(), "Article clicked! " + article.getImageUrl(), Toast.LENGTH_SHORT).show();
}

public class AppClickHandlers {
Context context;
public AppClickHandlers(Context context) {
this.context = context;
}
public void onFriendsClicked(View view) {
Toast.makeText(context, "Friends is clicked!", Toast.LENGTH_SHORT).show();
}
public void onFavouriteClicked(View view) {
Toast.makeText(context, "Favourite is clicked!", Toast.LENGTH_SHORT).show();
}
public void onArticlesClicked(View view) {
Toast.makeText(context, "Article is clicked!", Toast.LENGTH_SHORT).show();
}
}
}


Run and test the app once. Make sure the device is having internet connection as images will be downloaded from network.
I have uploaded the latest source code in GitHub for your reference. Kindly raise your queries in the command section.

References :

https://developer.android.com/topic/libraries/data-binding/
https://www.androidhive.info/android-working-with-databinding/
http://imakeanapp.com/android-jetpack-data-binding/

Happy coding!!!
Cheers!!!

Wednesday, 24 October 2018

Chapter 1 : Modern Android Architecture ‘Android Jetpack’ – Managing & Tracking Android Lifecycle (Room, LiveData and ViewModel)


        While managing lifecycle, we have to manage the data, orientations or memory leaks all based on lifecycle and we have to do it on our own which is cumbersome sometimes. So, we need these new set of libraries which can do most of our work very easily without going into deep. The Support Library components aren’t the only familiar features in the list of Jetpack components. All of the Architecture Components (Lifecycle, LiveData, Room and ViewModel) are now part of Jetpack, too.

It helps us to solve two critical points:

  • Manage our UI components lifecycle
  • Persist data over configuration changes

In this chapter, We are going to develop an app, which basically
  1. Takes some input from the user(LiveData)
  2. Save into the local database(Room) 
  3. Show it on the screen(ViewModel)
Let’s get started!!

Note : Use Android Studio 3.0 or later version.

Adding Dependencies (Pre AndroidX)


Room is basically a Database object mapping library use to access the database. Lifecycle, this has some good set of classes like ViewModel and LiveData which we will use to manage the lifecycle of our app. Add these libraries to build.gradle (Module: app) file, at the end of the dependencies block.

dependencies {
// Room components
implementation 'android.arch.persistence.room:runtime:2.0.0'
annotationProcessor 'android.arch.persistence.room:compiler:2.0.0'

// Lifecycle components
implementation 'android.arch.lifecycle:extensions:2.0.0'
annotationProcessor 'android.arch.lifecycle:compiler:2.0.0'
}

Refer here for AndroidX Dependencies.


Room (Local database)

We can query your data without having to deal with cursors or loaders. We can define our database by adding annotations in your Model class. So get rid of third-party ORMs like Sugar, In fact, when the official Android libraries give you an equal, or if not, better solution. The library helps you create a cache of your app's data on a device that's running your app. If user does not have internet connection, Just chill ! No problem! This cache allows users to view a consistent copy of key information within your app.

3 key concepts of Room


@Entity - We just have to annotate “@Entity” to a class and the name of the class becomes table name and, data members becomes the name of the columns. “@Entity” class represent an entity in a table.



Here, we have class StudentModel, and name of table is also same. We had made a column itemName, personName, and addedDate.

@Dao (Data Access Object) - An Interface where we put all our SQL queries. No need to write whole quires now, we just need to make a method and annotate with specific annotations like “@Insert”, “@Delete”, “@Query(SELECT FROM *)”



Here, we have an interface StudentModelDao. To insert the data we annotated “@Insert” to insert method. Room doesn’t gives us annotations which can help us in selecting everything so we have “@Query” to do some custom queries.

@Database - We need to create an abstract class (Room class) which extends RoomDatabase. It is a database layer over the SQLite database; this helps us in all the work which we use to do in SQLiteOpenHelper class. We need only a single instance for the whole app.



Here, we have a Room class AppRoomDatabase in which we declare all our entities and version of the database. getDatabase() method will return the room database instance. If we want to access the database lets deep dive into ViewModel and LiveData.


ViewModel (Data-handling business logic)

ViewModel is the new class provided by lifecycle. It can be termed as the bridge between model and UI but quite intelligent one in the sense that it can be automatically retained in the case of orientation change .

Generally what happens during orientation change?
        For instance we are in one activity and the activity loads some list and add it to the RecyclerView. Now when the orientation change has not been handled then new instance of activity will be created and the loading of list takes place and is then again added to RecyclerView.

How does 
ViewModel solve this problem?
        If you have used 
ViewModel along with LiveData class to store data then during orientation change new instance of activity will be created but the data won't be downloaded again. ViewModel will provide the most recent available data.

Note: Don’t think that 
ViewModel will hold data forever or for every case. If you close or activity is destroyed the ViewModel will also be destroyed or cleared.



StudentListViewModel class must extend the ViewModel class. If the ViewModel needs the application context, then it must extend the AndroidViewModel class. 
In our ViewModel, we first get an instance of our database using AppRoomDatabase.getDatabase(this.getApplication())

We need to load the list of student items from the database. For that, we should use the query we defined in the DAO class, getAllStudItems(). Next, call the abstract method we created for DAO and then call the query method. 


appDatabase.itemAndStudentModel().getAllStudItems();

The ViewModel will contain all the data needed for our Activity. In our example, we are using something called LiveData.

LiveData

LiveData is an observable data holder. It can only be observed in the context of a lifecycle, more precisely in the context of an Activity or Fragment lifecycle. By passing the reference of an Activity or Fragment, it can understand whether your UI onScreen, offScreen or Destroyed. After passing the UI object to LiveData, whenever the data in the live data changes. It notifies the lifecycle owner with updates and then the UI redraw itself with updates.

MutableLiveData extends LiveData internally and also the two methods of LiveData available,
1. setValue() : Set the value and dispatch the value to all the active observers. It cannot be done in background thread it must be done in the main thread only.
2. postValue() : Post a task to main thread to override value set by setvalue. As setvalue cannot be called from background thread so post value must be used to set value from background thread.


How LiveData solved developer`s major Headaches ?

  • No more manual life-cycling handle - Observers just observe relevant data and don’t stop or resume observation. LiveData manages all of this under control.
  • Proper configuration changes - If an observer is recreated due to a configuration change, like device rotation, it immediately receives the latest available data.
  • Ensures your UI matches the data state -Instead of updating the UI every-time when the data changes, your observer can update the UI every time there’s a change. It receives the latest data upon becoming active again.
  • No memory leaks - Observers are bound to Lifecycle objects and clean up after themselves when their associated life cycle destroyed.
  • No crashes due to stopped activities - It means if an activity is in the back stack, then it doesn’t receive any LiveData stream.
  • Sharing resources - You can extend LiveData object using the singleton pattern to wrap system services so that they can be shared in your app.
  • We wrap our list of student items inside LiveData so that the Activity can observe changes in the data and update the UI.


Framing RecyclerView Adapter

Now since we will be displaying a list of student items, we need a RecyclerView. So first, let’s create an adapter for the same.

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.RecyclerViewHolder> {
private List<StudentModel> studentModelList;
private View.OnLongClickListener longClickListener;

public RecyclerViewAdapter(List<StudentModel> studentModelList, View.OnLongClickListener longClickListener) {
this.studentModelList = studentModelList;
this.longClickListener = longClickListener;
}

@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) {
StudentModel borrowModel = studentModelList.get(position);
holder.itemTextView.setText(borrowModel.getItemName());
holder.nameTextView.setText(borrowModel.getPersonName());
holder.dateTextView.setText(borrowModel.getAddedDate().toLocaleString().substring(0, 11));
holder.itemView.setTag(borrowModel);
holder.itemView.setOnLongClickListener(longClickListener);
}

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

public void addItems(List<StudentModel> borrowModelList) {
this.studentModelList = borrowModelList;
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);
}
}
}


Creating the Android LifecycleObserver & LifecycleOwner


The basic idea here is that there is a class named LifecycleOwner which emits various lifecycle events (such as ON_CREATE, ON_PAUSE, etc) which you as an Android Developer are already familiar with. Now you can implement an interface name LifecycleObserver which listens to these events and respond accordingly.

public class AppLifeCycleObserver implements LifecycleObserver {
private String LOG_TAG = "AppLifeCycleObserver";
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
Log.i(LOG_TAG, "onResume");
}
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
Log.i(LOG_TAG, "onPause");
}
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void onCreate() {
Log.i(LOG_TAG, "onCreate");
}
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void onStart() {
Log.i(LOG_TAG, "onStart");
}
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
public void onStop() {
Log.i(LOG_TAG, "onStop");
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void onDestroy() {
Log.i(LOG_TAG, "onDestroy");
}
}


Adding the Observer


Observers are added to lifecycle owners via calls to the addObserver() method of owner’s Lifecycle object, a reference to which is obtained via a call to the getLifecycle() method. Edit the HomeActivity.java class file and add code to the onCreate() method to add the observer:



Creating a Lifecycle Owner

By creating a custom lifecycle owner class and demonstrate how to trigger events and modify the lifecycle state from within that class. The class is going to need a LifecycleRegistry instance initialized with a reference to itself, and a getLifecycle() method configured to return the LifecycleRegistry instance. Declare a variable to store the LifecycleRegistry reference, a constructor to initialize the LifecycleRegistry instance and add the getLifecycle() method:




Next, the class will need to notify the registry of lifecycle state changes. By triggering lifecycle events using the handleLifecycleEvent() method. For this example, we will add some methods that simply trigger lifecycle events when called. Finally change within the AppLifecycleOwner class is to add the AppLifeCycleObserver class as an observer.

In HomeActivity.java, create an instance of the AppLifecycleOwner class and to call the startLifecycleOwner() and stopLifecycleOwner() methods.



We must remove observer in onDestory() method of calling activity to avoid memory leaks.

@Override
protected void onDestroy() {
super.onDestroy();
getLifecycle().removeObserver(new AppLifeCycleObserver());
}


I have uploaded the latest source code in 
GitHub for your reference. Kindly raise your queries in the command section.

References :

https://developer.android.com/jetpack/arch/lifecycle
https://medium.com/mindorks/android-architecture-components-room-viewmodel-and-livedata-50611793e4a9
https://blog.iamsuleiman.com/android-architecture-components-tutorial-room-livedata-viewmodel/
https://codinginfinite.com/android-livedata-example/


Happy coding!!!
Cheers!!!

Sunday, 7 October 2018

Chapter 0 : Modern Android Architecture ‘Android Jetpack’ - Lifecycle


       Jetpack is “the next generation of components to accelerate app development”. It’s a set of libraries, tools and architectural guidelines to help making building great Android apps quick and easy. It provides common infrastructure code so you can focus on what makes your app unique.



Activity/Fragment - Depend only on a view model.
View model - Provides the data for fragment or activity, and contains data-handling business logic to communicate with the model.
Repository - Depends on a persistent data model and a remote backend data source and handle data operations.
Room - An object-mapping library that provides local data persistence with minimal boilerplate code.
Retrofit library - To access our backend through REST API.

Lifecycle-manageable components such as activities and fragments perform actions in response to a change in another Android component. The lifecycle methods of activities and fragments leads to a poor organization of the code and to the proliferation of errors in most of the cases.
The lifecycle-aware component helps to move the code of dependent components out of the lifecycle methods of activity & fragments and into the components themselves.

Dependencies


AndroidX

dependencies {
def lifecycle_version = "2.0.0"
// Lifecycles only (no ViewModel or LiveData)
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" // use kapt for Kotlin
// alternately - if using Java8, use the following instead of lifecycle-compiler
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
}


Pre-AndroidX

dependencies {
def lifecycle_version = "1.1.1"
// Lifecycles only (no ViewModel or LiveData)
implementation "android.arch.lifecycle:runtime:$lifecycle_version"
annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version" // use kapt for Kotlin
// alternately - if using Java8, use the following instead of compiler
implementation "android.arch.lifecycle:common-java8:$lifecycle_version"
}


Refer here for updated Dependencies.

The android.arch.lifecycle package can automatically adjust their behavior based on the current lifecycle state of an activity or fragment that has three main classes that we’ll deal with:
  • LifeCycle
  • LifeCycleOwner
  • LifeCycleObserver

Lifecycle


Lifecycle class holds the information about the component (like an activity or a fragment) lifecycle state where allows other objects to observe this state.

The lifecycle events (i.e. Lifecycle.Event.ON_CREATE, Lifecycle.Event.ON_RESUME, Lifecycle.Event.ON_PAUSE and etc) & lifecycle states (INITIALIZED, CREATED, RESUMED and etc) are used to track the lifecycle status for its associated component.




A single state can span multiple lifecycle owner events, so for an activity it’s considered in the CREATED state once it’s created and just before it’s paused, and in the same time the duration between the activity’s onStart() and just before onPause() it’s considered also in the STARTED state.
Since multiple states can interleave for a given point of time, if we want to check for a specific state, we always use the isAtLeast method:

if (lifeCycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { //...}

LifecycleOwner and Lifecycle Observers


If we're trying to manage the lifecycle of activity or Fragment, we must implement LifecycleOwner interface to the activity. The lifecycle of a whole application process is managed by ProcessLifecycleOwner. Fragments and Activities in Support Library 26.1.0 and later already implement the LifecycleOwner interface.

If we have a custom class that we would like to make a LifecycleOwner, we can use the LifecycleRegistry class, but we need to forward events into that class.

LifecycleOwners such as Activity & Fragments are objects with lifecycle like Activity and Fragments. LifecycleObserver (e.g. LiveData) observes LifecycleOwners and are notified of lifecycle changes.

class SampleObserver implements LifecycleObserver{

@OnLifecycleEvent(ON_CREATE)
void startUp(LifecycleOwner source) {
}

@OnLifecycleEvent(ON_ANY)
void onAny(LifecycleOwner source, Event event) {
}

@OnLifecycleEvent(ON_STOP)
void cleanUp(LifecycleOwner source) {
}
}


The best way to handle lifecycle-aware components (activities and fragments) as lean as possible. They should not try to acquire their own data; instead, use a ViewModel to do that, and observe a LiveData object to reflect the changes back to the views.
So, Android Lifecycle-aware components are tracked and managed by Room, LiveData and ViewModel in the next episode.

Tuesday, 4 September 2018

Part 1 - Integrating Travis CI with Android app



Why Continuous Integration (CI)?


CI is the practice of merging in small code changes frequently instead of merging large change at the end of a development cycle. The goal is to build healthier software without last minute surprises. Travis CI helps us out from this issue.

Travis CI automatically builds and tests code changes, then provides immediate feedback on the success of the change and failure case also. Travis CI can also automate other parts of your development process by managing deployments (i.e. uploading to Testfairy) and notifications (i.e. sending a message to slack).

How Travis works?


When you run a build, Travis CI clones our GitHub repository into a brand new virtual environment and carries out a series of tasks to build and test your code. If one or more of those tasks fails, the build is considered broken. If none of the tasks fail, the build is considered passed, and then Travis CI can deploy your code to a web server, or application host.

This service is free for open source projects and so easy to use that you will wonder why didn’t you use it before.


Are you ready to kick-start Travis CI?

To start using Travis CI, make sure you have:
  • A GitHub account.
  • Owner permissions for a project hosted on GitHub.

  1. Go to Travis-ci.com and Sign up with GitHub.
  2. Accept the Authorization of Travis CI. You’ll be redirected to GitHub.
  3. Click the green Activate button, and select the repositories you want to use with Travis CI.
  4. Add a .travis.yml file to your repository to tell Travis CI what to do. The following example specifies Android project that should be built with jdk and the latest versions of JDK 8.
  5. Add the .travis.yml file to git, commit and push, to trigger a Travis CI build.
    Note: Travis only runs builds on the commits you push after you’ve added a .travis.yml file.
  6. Check the build status page to see if your build passes or fails, according to the return status of the build command by visiting the Travis CI and selecting your repository.


Enabling continuous integration on GitHub


  1. Once you have your repository created on GitHub click on Settings and Integrations & services. 
  2. From the Add service drop-down menu choose “Travis CI” then “Add service”.
  3. Navigate to https://travis-ci.org/profile and click on the switch next to the repository that you’d like the Travis builds to be run with.
Note: once you’ve switched on Travis builds on your repository a build will be triggered every a commit or a pull request is made. Without a .travis.yml file the build will fail. Configuring the .travis.yml will be done on the next step.


Setting up Travis builds

You need to add a .travis.yml file into the root of your project. This file will tell how Travis handles the builds.

At the beginning of your .yml file add the following parameters:

language: androidsudo: requiredjdk: oraclejdk8

sudo requirement is added because a license needs to be manually added later.

Specify the variables that are going to be used in the build. Set the ANDROID_BUILD_TOOLS and ANDROID_API to the same as specified in your projects build.gradle file.

env:global:- ANDROID_API=24- EMULATOR_API=21- ANDROID_BUILD_TOOLS=24.0.2- ADB_INSTALL_TIMEOUT=5 # minutes


Components 



The exact component names must be specified (filter aliases like the add-on or extra are also accepted). To get a list of available exact component names and descriptions run the command SDK manager --list.


android:components:- tools- platform-tools- build-tools-$ANDROID_BUILD_TOOLS- android-$ANDROID_API- android-$EMULATOR_API_LEVEL- extra-google-m2repository- extra-android-m2repository # for design library- addon-google_apis-google-19 # google play services- sys-img-armeabi-v7a-addon-google_apis-google-$ANDROID_API_LEVEL- sys-img-armeabi-v7a-addon-google_apis-google-$EMULATOR_API_LEVEL
licenses:- android-sdk-preview-license-.+- android-sdk-license-.+- google-gdk-license-.+


Before install part,

before_install:- mkdir "$ANDROID_HOME/licenses" || true- echo -e "\n8933bad161af4178b1185d1a37fbf41ea5269c55" >
"$ANDROID_HOME/licenses/android-sdk-license"- echo -e "\n84831b9409646a918e30573bab4c9c91346d8abd" > "$ANDROID_HOME/licenses/android-sdk-preview-license"- chmod +x gradlew- ./gradlew dependencies || true


The — ./gradlew dependencies || true is required if you get an error please install missing components using the SDK manager.

Script


- ./gradlew clean assembleAndroidAppRelease

The Gradle wrapper executes mentioned project at release build variant. If you intend to use Google Play Services with Travis, make sure you also use the Maven support library.

you will need to make sure to include the Maven repo in your root build.gradle file:

repositories {maven {url 'https://maven.google.com'}}


Setting up automatic builds


Travis can upload your project builds directly to other providers such as TestFairy. To be able to install a .apk file on an Android device the file needs to be signed.

Once the keystore file is created, place it in your project root. You’ll want to encrypt the file which is done with the Travis command-line command:

travis encrypt-file keystore.jks

After encrypting the file copy the generated script to the before_install section.Running the command will leave the old keystore file in place and will also generate a keystore.jks.enc file. Remove the original keystore file from the project and keep the encrypted one.

The keystore password and key password need to be added to the .travis.yml file, as they will be used in the .apk signing process. The passwords need to be encrypted though.




Copy the generated values to your .travis.yml in the environmental variables section (env). Do the same for both the keystore password and the key password.

The setup for the deployment is done in the before_deploy section of the .yml file. Here the jarsigner is used to sign the file with the keystore file provided, as well as to verify it.


before_deploy


- cp $TRAVIS_BUILD_DIR/.keystore $HOME- cd app/build/outputs/apk/- jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore $HOME/keystore.jks -storepass $storepass -keypass $keypass app-release-unsigned.apk yourapp_keystore
# Verification- jarsigner -verify app-release-unsigned.apk- "${ANDROID_HOME}/build-tools/24.0.2/zipalign -v 4 app-release-unsigned.apk yourapp.apk"

Next, it’s necessary to set up the deploy section of the .travis

deploy:provider: releasesfile: yourapp.apkskip_cleanup: trueon:repo: githubUsername/Repositorytags: truejdk: oraclejdk8api_key:secure: here goes the encrypted api key

You can generate the API key by going to your account settings on GitHub, Personal access tokens, Generate new token. Set the scope to public_repo and generate the token. Remember to copy the access token.





Encrypt the API key and add it to the deploy section under api_key. Remember to check the Travis WebLint before committing your changes.
When a commit is tagged the Travis deployment will be triggered.

Monday, 27 August 2018

Part 2 - Centralized Sonar Analysis - SonarCloud Android integration


Please refer Part 1 - Monitoring code quality of your Android application with SonarQube for better understanding,
https://akcjayaprakash.blogspot.com/2018/07/monitoring-code-quality-of-your-android.html

Instead of local Sonar, we are creating the project in “https://sonarcloud.io/” by clicking + icon at the top right corner.



Enter ‘Project name’ & ‘Project key’ then click ‘Create’. We must use the same given Project name & Project key in sonarqube.gradle

There is no change for adding Sonarqube plugin to the project & app level Gradle files. We should update the proper SonarCloud configuration in sonarqube.gradle

property "sonar.host.url", "https://sonarcloud.io"
property "sonar.projectKey", "Same project key from the SonarCloud project"
property "sonar.organization", "organization key from SonarCloud"
property "sonar.login", "Unique token created by SonarCloud"
property "sonar.projectName", "Same project name from the SonarCloud project"


Use remaining properties of the sonarqube.gradle from Local sonar implementation.


After building or syncing project, open a Command Prompt and navigate to the app module directory of your project where your Gradle file is located.

Execute gradlew sonarqube and wait until the build is completed. Here we go,



The Android project for Centralized Sonar Analysis is pushed to SonarCloud. The measures of Android project contains code smell, lines of code, issues, and etc.






Please feel free to post any queries,doubts or suggestions in the comments section.