Categories
AWS Node React Web Development & Deployment

Deploy React Node Application in AWS Ubuntu Server from Putty or Linux

  1. Create a folder (key) in your home directory and save the AWS Public Key File in the folder and give permissions as given below

    chmod 500 /home/xxx/key
    chmod 400 /home/xxx/key/LightsailDefaultKey-ap-south-1.pem
    
  2. Connect to the server using SSH with user & ip

    ssh -i /home/xxxxxx/key/LightsailDefaultKey-ap-south-1.pem user@xxx.xxx.xxx.xxx
    

    Update & Upgrade

    sudo apt update
    sudo apt upgrade
    
  3. Check if Node & PM2 are installed

    Check the Node Version, If No Version is Displayed/Error Message, Install Node

    node -v
    

    Check the PM2 Version, If No Version is Displayed/Error Message, Install PM2

    pm2 -v
    
  4. Install NodeJS & NPM

    Download the latest Node Version

    curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
    

    Install Node

    sudo apt install -y nodejs
    

    Verify

    node -v
    
  5. Install PM2

    Install PM2 Globally

    sudo npm install pm2 -g
    

    Startup the Server

    pm2 startup ubuntu
    

    Verify

    pm2 -v
    pm2 list
    
  6. Setup Firewall

    Enable Firewall

    sudo ufw enable
    

    Allow HTTP, HTTPS & SSH access to the Server

    sudo ufw allow http
    sudo ufw allow https
    sudo ufw allow ssh
    

    PS: For the Lightsail server, you need to enable, SSH, HTTP, and HTTPS from the Networking tab in the Lightsail dashboard

  7. Install NGINX

    sudo apt install nginx
    
  8. NGINX Configuration

    Open the default configuration file using nano

    sudo nano /etc/nginx/sites-available/default
    

    Use CTRL+Shift+6 to mark the beginning of your block

    Move cursor with arrow keys to end of your block, the text will be highlighted.

    Use CTRL+K to cut/delete block.

    Copy and Paste the below content to the file

    server {
        listen 80 default_server;
        listen [::]:80 default_server;
        root /var/www/html;
        index index.html index.htm index.nginx-debian.html;
        server_name _;
        location / {
            try_files $uri $uri/ =404;
        }
    }
    

    Save CTRL+S & Exit CTRL+X

  9. Create the Server Configurations file

    sudo nano /etc/nginx/sites-available/MyServer.conf
    

    Copy and Paste the below content to the file

    server {
        root /var/www/html;
        index index.html index.htm index.nginx-debian.html;
        server_name api-myexampleserver.com;
            location / {
            proxy_pass http://localhost:3001;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }
    }
    

    Save CTRL+S & Exit CTRL+X

  10. Create the Client Configurations file

    sudo nano /etc/nginx/sites-available/MyClient.conf
    

    Copy and Paste the below content to the file

    server {
        root /var/www/html/myClient/build;
        index index.html index.htm index.nginx-debian.html;
        server_name myexampleclient.com;
        location / { try_files $uri /index.html; }
    }
    

    Save CTRL+S & Exit CTRL+X

  11. Enable & Check Configurations

    Setup Symbolic Links

    sudo ln -s /etc/nginx/sites-available/default /etc/nginx/sites-enabled
    sudo ln -s /etc/nginx/sites-available/MyServer.conf /etc/nginx/sites-enabled
    sudo ln -s /etc/nginx/sites-available/MyClient.conf /etc/nginx/sites-enabled
    

    Check Configurations,

    sudo nginx -t
    

    If everythink is setup correctly, you will get the below message

    Outputnginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful
    

    Restart NGINX Server

    sudo service nginx restart
    
  12. Clone, Setup & Start Server

    Navigate to the home cd ~

    Verify

    pwd
    

    Clone the Server Code to home

    git clone https://github.com/xxxxxx/myServer.git myServer
    

    navigate to the server folder and remove the node modules folder & install dependencies

    cd myServer
    rm-rf node_modules
    npm install
    

    Start the Server

    pm2 start index.js
    
    or
    
    pm2 start server.js
    

    Verify

    pm2 list
    

    the server should be running

  13. Clone, Setup & Start Client

    Navigate to the home
    cd ~
    

    Verify

    pwd
    

    Clone the Build Client Code to home

    git clone https://github.com/xxxxxx/myClient.git myClient
    

    navigate to the server folder and remove the node modules folder & install dependencies

    cd myClient
    rm-rf node_modules
    npm install
    

    Navigate to the VAR folder

    cd /var/www/html
    

    Move the client code to the html folder

    sodo mv ~/myClient .
    

    Restart NGINX

    sudo service nginx restart
    
  14. Setup SSL

    Update the package lists

    sudo apt update
    

    Install Certbot and it’s Nginx plugin

    sudo apt install certbot python3-certbot-nginx
    

    Obtain & Setup the SSL Certificate

    sudo certbot --nginx -d pi-myexampleserver.com
    sudo certbot --nginx -d myexampleclient.com
    

    If that’s successful, certbot will ask how you’d like to configure your HTTPS settings.

    Output
    Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    1: No redirect - Make no further changes to the webserver configuration.
    2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
    new sites, or if you're confident your site works on HTTPS. You can undo this
    change by editing your web server's configuration.
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Select the appropriate number [1-2] then [enter] (press 'c' to cancel):
    

    Select 2 then hit ENTER. The configuration will be updated, and Nginx will reload to pick up the new settings. certbot will wrap up with a message telling you the process was successful and where your certificates are stored:

    Output
    IMPORTANT NOTES:
    - Congratulations! Your certificate and chain have been saved at:
    /etc/letsencrypt/live/example.com/fullchain.pem
    Your key file has been saved at:
    /etc/letsencrypt/live/example.com/privkey.pem
    Your cert will expire on 2020-08-18. To obtain a new or tweaked
    version of this certificate in the future, simply run certbot again
    with the "certonly" option. To non-interactively renew *all* of
    your certificates, run "certbot renew"
    - If you like Certbot, please consider supporting our work by:
    
    Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
    Donating to EFF:                    https://eff.org/donate-le
    

    Your certificates are downloaded, installed, and loaded.

    Let’s Encrypt’s certificates are only valid for ninety days. This is to encourage users to automate their certificate renewal process. The certbot package we installed takes care of this for us by adding a systemd timer that will run twice a day and automatically renew any certificate that’s within thirty days of expiration.

    You can query the status of the timer with systemctl:

    sudo systemctl status certbot.timer
    

    Output:

    Output
    ● certbot.timer - Run certbot twice daily
        Loaded: loaded (/lib/systemd/system/certbot.timer; enabled; vendor preset: enabled)
        Active: active (waiting) since Mon 2020-05-04 20:04:36 UTC; 2 weeks 1 days ago
        Trigger: Thu 2020-05-21 05:22:32 UTC; 9h left
    Triggers: ● certbot.service
    

    To test the renewal process, you can do a dry run with certbot:

    sudo certbot renew --dry-run
    

If you see no errors, you’re all set.

  1. Restart NGINX & Test

    sudo service nginx restart
    

    Test the Client & Server

Preethi

Categories
Android

How to Implement Preferences Settings Screen in Android Using JetPack

In many situations we need a certain type of settings in our application, such as setting default language, different themes, Font Size etc…Moreover Android application often needs settings that allows the user to modify the preference in their app and it is also the best way to provide a better user experience. Android Provides a powerful Library called Android Preference Library (JetPack)to manage or handle user Preferences. In this Blog, we can discuss the basics implantation of Android Preference Library (JetPack) in our application by creating a basic Setting Screen.

Now let us see some attractive features of the Android Preference Library:

  • It provides an easy way to create a standard looking settings screen for any app.
  • Minimal coding is required
  • It automatically takes care of UI.
  • The set value of each item in the Preference Fragments automatically  save to a SharedPreference file and thereby  its scope becomes app-wide.

Now we can see How to create a standard Settings Screen using Preference Library?

Setting Up the Android Preference Library

To use the Preference Library first you need to include the required Library in Gradle file as shown in the screenshot.

Creating Menu on Action Bar.

Next, create a Menu in the Action bar and include Settings as a menu option. For that first create a menu directory  res-> new->AndroidResourceDirectory

add_directory
add_menu_dir_two

Create a menu file as shown below:

res->menu->

add_menu_file
add_menu_file_two

Include the following code inside it:

menuitem.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/settings"
        android:title="Settings" />
</menu>

Once you create the menu, the next step is to inflate the menu in the Activity and handle the menu click event.For that we override methods such as onCreateOptionMenu and onOptionItemselected as given below:

MainActivity.java

package com.xxxxxxxxxxxxxxx;

import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.preference.PreferenceManager;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    ActionBar action;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        action = getSupportActionBar();
        action.setTitle("Main");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menuitem,menu);
        return super.onCreateOptionsMenu(menu);
    }
    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        switch(item.getItemId())
        {
            case R.id.settings:
               startActivity(new Intent(this,SettingsActivity.class));
               break;
        }
        return super.onOptionsItemSelected(item);
    }
}

To inflate the menu  in Activity pass menu file name, in this case,  meuitem.xml  (use your menu file name )as an argument to the inflater method. Use the onOptionsItemSelected method to specify the on-click actions for each menu item. In this example, Clicking the item settings will navigate to a Second Activity (This Activity hosts the Preference Fragment) from MainActivity.

Note: You can either use an Actionbar or a Toolbar according to your preference. A Toolbar is more flexible than an Action bar.

Setting up a Preferences screen:

To create a Preference Screen, First, create a Preference Hierarchy in which we are going to define the preferences according to our app requirement, in other words, it is a kind of layout design for setting Screen.

We can create a preference hierarchy in two ways:

  1. Using XML file
  2. Include codes programmatically.

In this blog I am using the first approach, the second we can discuss in a future post.

Creating Hierarchy using xml:

To create preferences via an XML resource

1. Create an XML directory in res as shown below:

xml_add_dir
xml_two

2.Create a Preference Screen File inside the XML directory by XML->new –>XML Resource File.

Note: Keep Root Element as Preference Screen

3. Once we create the Preference Screen File next step is to include the required preference inside the file,  in other words, define the different settings ( widgets) that you wish to display within the preferences screen.

Preferences API provides a collection of widget-based preferences like Checkbox preference, switch preference etc… that can be used to configure the different settings items found within our applications.

preference.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <PreferenceCategory android:title="Sync Information">
        <CheckBoxPreference
            android:defaultValue="true"
            android:key="check"
            android:title="Synchronization"
            android:summary="Enable or Disable Syncronization 
            of data"/>

        <SwitchPreference
            android:defaultValue="false"
            android:dependency="check"
            android:key="switch"
            android:title="Wifi" />

    </PreferenceCategory>
    <PreferenceCategory android:title="Personal category">

        <EditTextPreference
            android:defaultValue="Username"
            android:dialogMessage="Enter your name"
            android:dialogTitle="Please Enter your Name"
            android:inputType="textCapWords"
            android:key="username"
            android:selectAllOnFocus="true"
            android:singleLine="true"
            android:summary="Enter the user name for the 
            application"
            android:title="Enter your Name" />
    </PreferenceCategory>
    <PreferenceCategory android:title="Language Setting" >
        <ListPreference
            android:defaultValue="en"
            android:entries="@array/langName"
            android:entryValues="@array/langCode"
            android:key="language_selection"
            android:summary="Set Language is : "
            android:title="Language" />
    </PreferenceCategory>
</PreferenceScreen>

Here we need to define three attributes for our Preference item:

  • key: This key is used to reference the preference value that is saved. This key will be used for the saving and retrieval of our preferences value
  • title: The title used for the display of the preference
  • summary: The description used to display on the preference

Moreover, we can define different Category and also define some dependency among preference item using a dependency tag.

From the above code snippets, you can observe that there are three Preference Category titled Sync Information, Personal category and Language Setting category ( you can choose any name for category based on your requirement)

We can provide some dependence among preference by using a dependency tag. For example, in the Sync Information Category, there are two preferences SwitchPreference and checkboxPreference. To set the dependency, Switch Preference use a dependency tag  and  set its value as  checkboxPreference key value.

Language Setting category  uses a ListPreference and uses an array (any name) value file to get its entries. For creating a Value File. res->values->New->Values Resource File

valuesfile

Then include the following code inside the File. Here I used three languages and corresponding code.

Setting the Preference in Activity:

Once you finished the layout of the preference screen next you need to inflate the preference.xml  file in the Activity.

For that create a new Java File  ( Setting Screen Fragment )and then extends it to PreferenceFragmentCompat then use override method onCreatePreferences and set the Preference screen XML file in it.

Note: Create a SecondActivity to host the Setting Screen Fragment 

SettingActivitytwo .java


import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentTransaction;
import androidx.preference.PreferenceManager;
import android.app.WallpaperColors;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.provider.CalendarContract;
import android.widget.FrameLayout;
import android.widget.Toast;

public class SettingsActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_settings);       
        getSupportFragmentManager().beginTransaction().
        add(R.id.fragment_container,new SettingsScreen()). 
        addToBackStack(null).commit();    
    }

    @Override
    public void onBackPressed() {

       if (getFragmentManager().getBackStackEntryCount() > 0 ) 
        {
            getFragmentManager().popBackStack();
        } else {
            super.onBackPressed();
        }
    }

}

SettingScreenone.java

import android.content.SharedPreferences;
import android.os.Bundle;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;

public class SettingsScreen extends PreferenceFragmentCompat {
    @Override
    public void onCreatePreferences(Bundle savedInstanceState, 
    String rootKey) {
        addPreferencesFromResource(R.xml.preferences);
    }
}
Reading the settings values:

The value of each item in the Preference Fragments usually save to a SharedPreference file. A Shared Preference allows us to read and write small amounts of primitive data as key/value pairs to a file on the device storage. When the user changes a setting, the system updates the corresponding value in the Shared Preferences file.

Let us say you need to change your application behaviour based on user settings, in this situation you want to read the associated Preference value. For that, we can use a method called PreferenceManager.getDefaultSharedPreferences() which takes the context and returns the Shared Preferences object containing all the key/value pairs that are associated with the Preference objects.

SettingActivityone.java

import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentTransaction;
import androidx.preference.PreferenceManager;
import android.app.WallpaperColors;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.provider.CalendarContract;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;

public class SettingsActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_settings);
        SharedPreferences sharedpref PreferenceManager.getDefaultSharedPreferences(getBaseContext());
Boolean check_value = sharedpref.getBoolean("check",true); String lang_select = sharedpref.getString("language_selection","en");

getSupportFragmentManager().beginTransaction().
add(R.id.fragment_container,new SettingsScreen()). addToBackStack(null).commit();

Toast.makeText(this,"Sync Status"+check_value,Toast.LENGTH_LONG).show();
Toast.makeText(this,"Language Selected :"+lang_select,Toast.LENGTH_LONG).show();
    }
    @Override
    public void onBackPressed() {
      if (getFragmentManager().getBackStackEntryCount() > 0 )
        {
            getFragmentManager().popBackStack();
        } else {
            super.onBackPressed();
        }
    }
}

The above code snippet uses PreferenceManager.getDefaultSharedPreferences(getBaseContext()) to get the settings as a SharedPreferences object (sharedpref).In order to read the preference value use the corresponding methods (getString(), getBoolean() etc.. ) on shared preference object and pass the corresponding key and default value(use the same key and  default value defined in the Preference hierarchy ).

Screen Recording one
Listening for a setting change:

In some situations we need to set a listener for settings, For example, you want to change the summary of your preferences according to the value of preference or display more options based on some settings value etc.

To listen to a setting change, use the Preference.OnPreferenceChangeListener interface, which includes the onPreferenceChange() method that returns the new value of the setting.

To register and unregister the Listener use the following code snippet.

register.java

  @Override
    public void onResume() {
        super.onResume();
getPreferenceScreen().getSharedPreferences().
registerOnSharedPreferenceChangeListener(preferenceChangeListener);
    }

    @Override
    public void onPause() {
        super.onPause();       getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
    }

Final code for Listener :

SettingsScreentwo.java

import android.content.SharedPreferences;
import android.os.Bundle;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;

public class SettingsScreen extends PreferenceFragmentCompat {

    public static final String languageSelected = "language";
    SharedPreferences.OnSharedPreferenceChangeListener 
    preferenceChangeListener;

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, 
    String rootKey) {

        addPreferencesFromResource(R.xml.preferences);
       preferenceChangeListener = new 
       SharedPreferences.OnSharedPreferenceChangeListener() {
            @Override
            public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
                if (key.equals("language_selection")) {
                    Preference languagePreference = 
                    findPreference(key);                  languagePreference.setSummary(sharedPreferences.getString(key, " ") + " - is the new language Selected ");
                }
            }
        };
    }

    @Override
    public void onResume() {
        super.onResume();      getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(preferenceChangeListener);
    }

    @Override
    public void onPause() {
        super.onPause();
        getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
    }
}
Screen

Hope you understood the concept of Android Preference and its usage. You can find the complete source code here.

Happy Coding

Preethi P G

Categories
Tableau

Adding Actions in Tableau Dash Board

Last Post was about creating Dashboard in Tableau.Now we can add some Actions to dashboard.Since it is a continuation of previous post I am using the same Data Source and sheets that were used in the Previous post. Let us say , you want to implement an action that will display each customers profitability by state in sheet 2 by selecting corresponding state in sheet 1 .

Basically Tableau has two main types of Actions:

Filters

HighLighting

In order to add Actions Go to Top Tab and Select Dashboard and select Actions as shown below:

Screenshot 2020-08-05 at 23.28.10_thumb[1]

Let us say you want to add a Filter Action For that Select the Add Action Select Filter, Then Give an action name after that specify the source sheet and Target sheet. Since sheet 2 value is changing according to the selection of sheet 1 value , in this case case Source sheet is sheet 1 and Target is sheet 2 .Next you need to specify when this action have to be executed ( that is selection of the value or Hover on the value like that).

Screenshot 2020-08-05 at 23.29.48_thumb[6]Screenshot 2020-08-05 at 23.34.22_thumb[3]

Finally we finish our Task:

Screen Recording 2020-08-05 at 23.45.45_thumb[1]

if you want to select multiple states either press CMD (CTRL in windows) + select states which you want to analyse or use the selection tool as shown below.

actiontwo

Thanks

Preethi.

Categories
Tableau

Creating Scatter Plot and Dashboard in Tableau

Last Post we implemented Hierarchy In Tableau.Here we can see How to create Scatter Plot and Dashboard in Tableau.

This was the worksheet that we worked on last project.Now we can start a new work sheet by clicking the new worksheet tab at the Bottom as shown in screen Shot:

Screenshot 2020-08-07 at 18.02.55

Next we can see how generate a Scatter Plot in Tableau.Let us say you need to calculate profit of each customer based on sales in different years.

For that First Drag and drop the Sales and Profit Columns and Rows respectively. Then drag Customer Name to details as shown below:

Screenshot 2020-08-05 at 22.55.16

Now we need to apply the Filter across all worksheets.That is all worksheet should show the same selected year data.For that Go to Filter then Right Click then select Apply to Worksheet then select All Using Data Source.

Screenshot 2020-08-05 at 22.52.39

Now you want to analyse both work sheet together in this case you can create a Dash Board and put both sheets together in it .In order to create Dash board go to Bottom tab select the Dashboard as shown in figure:

Screenshot 2020-08-07 at 18.06.01

Now Drag and drop the work sheets in to dash board as shown below:

Screenshot 2020-08-05 at 23.08.07

Now you can analyse both sheets data together using a dashboard.

scatterplot

Hope you enjoy the post.

Later,

Smile

Preethi

Categories
Tableau

Creating Join And Hierarchy in Tableau

Last Post we discussed Area Chart and Filters  in Tableau . This post is about creating Join , Map and working with hierarchy. we can discuss JOIN in detail in future post.As I already explained in previous post the First step is import your data sets then drag and drop the first table into space and double click on it after that drag the next table in to space Then you can choose the type of join as shown in the Figure:

Screenshot 2020-08-05 at 18.21.00

jointwo

These are the two table that we joined . Let us say I want to find out the total sales value of each State from these joined data :

First step is find out the data in a state level . Instead of drag the state field in to work space we can use a hierarchy. The hierarchy in Tableau is an arrangement where data fields are presented at various levels.The main advantage of hierarchy is , it helps to drill down the data easily.In this table we can see there are three geographical data city,state,country.In order to create a Hierarchy just move the city in to Country as shown in Figure

hirarchy

Give a name to your Hierarchy( Geography). In this project we are looking for a State Level data, So we want to include state in to Hierarchy. ,So move the state to Geography as explained above (drag and place inside the Hierarchy) in between the City &  Country in the Hierarchy.

Next drag and drop the Country to work space .You can see + sign on The country attribute if you click on that you will get the state level data.

According to our Problem we need to calculate the total sales of each state .just drag and drop the sales field to Size as shown in figure.You can see the Total Sales value in each state of each Year  by dragging the order date Field to Filters as shown in figure: Once you Right Click on the YEAR(Order Date) in Filter Field You can enable the Show Filter Field.

Screenshot 2020-08-05 at 20.59.23

Screenshot 2020-08-05 at 21.03.55

If you want to change the Filter View  Right Click on Filter field(Years).Then select options according to your requirement.

Screenshot 2020-08-05 at 21.06.45

Finally we successfully complete our task.

Screen Recording 2020-08-05 at 22.18.27

Later,

Preethi

Categories
Android

Use FileProvider to Share Image From RecyclerView

This is a continuation of my previous post  in which I explained in detail on how to share a Text (corresponding raw data) from RecyclerView to other application using share Intent . In this project we can extend the same concept to share the image from RecyclerView to other application using a FileProvider class.

This was the design of the page which we used  in the previous post:

Screenshot_1596478162

A FileProvider is a subclass of Content Provider..File Provider is used specifically for sharing the app’s internal Files ,While Content Provider is a component that enables you to securely share any type of data by providing third party apps access to the content that’s stored as file in internal storage space.

So Let’s see how to use this FileProvider to share data  from RecyclerView.

In order to use FileProvider in Project :

1. Define the FileProvider in your AndroidManifest file

2. Create an XML file that contains all paths that the FileProvider will share with other applications

Define the FileProvider in your AndroidManifest file:

The first step is  to include the File Provider in Android manifest file as shown in Figure:

Screenshot 2020-08-02 at 23.30.30

1.android:authorities

It is just like a unique identifier , Basically Android System keeps a list of Providers and the  Authority attribute helps to distinguish these providers . You can either use your package name as this attribute or  set the value as  ${applicationId}.  If you are using ${applicationId} then it automatically set project package name: ${applicationId}.myfileprovider as attribute value.

2.android:exported

This is the attribute which defines whether any other application can access the content provider or not. The default value for this attribute is TRUE. in order to control the access you have to set the attribute value as FALSE.

3.android:grantUriPermissions:

This attribute allows you to securely share your app’s internal storage to other applications, I.e This attribute defines a permission that controls both read and write access to the whole of the Content provider(storage space).Here we are specifying the permissions (read/write) that we enables to other applications .

After that define a meta-data tag which define the path to the XML file ( xml file that we are going to create in the next step ) which contains all data paths that the FileProvider can share with external apps.

Create an XML file that contains all paths that the FileProvider will share with other applications:

First Create XML Directory in res as shown in the Figure: res >New >Android Directory

Then select Resource Type as xml . After that create xml file inside the directory XML > NEW > Resource XML file:

Screen Shots Below,

Screenshot 2020-08-02 at 23.36.16
Screenshot 2020-08-02 at 23.36.48
Screenshot 2020-08-04 at 01.02.27

XML creation

After that write the following codes to file_path xml File.

file_provider_path.xml

<?xml version="1.0" encoding="UTF-8"?>
-
<paths>
    <cache-path path="/" name="cache"/>
    <files-path path="/" name="files"/>
</paths>

This code , allows the FileProvider to share all files that are inside the app’s internal cache and files directory.

After including the File Provider in project next we can use this to share data to other applications.In this project I will show you how to share image using FileProvider.As already explained in the previous post, in order to share data, you need to add  a share intent function. For that inside onBindViewHolder method make the share button clickable by using Android SetOnClickListener method.

image_share.java

@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
    final HashMap < String, String > Details = dataSet.get(position);

    holder.share.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            // create file from drawable image
            Bitmap bm = BitmapFactory.decodeResource(context.getResources(), Integer.parseInt(Details.get("Bimage")));

            File filesDir = context.getApplicationContext().getFilesDir();
            File imageFile = new File(filesDir, "birdimg.png");

            OutputStream os;
            try {
                os = new FileOutputStream(imageFile);
                bm.compress(Bitmap.CompressFormat.PNG, 100, os);
                os.flush();
                os.close();
            } catch (Exception e) {
                Log.e(getClass().getSimpleName(), "Error writing bitmap", e);
            }

            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_SEND);
            intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            Uri imageUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, imageFile);

            intent.putExtra(Intent.EXTRA_STREAM, imageUri);
            intent.setType("image/png");
            context.startActivity(intent);
        }
    });

}

Since we saved our  image as a drawable, we need to create a bitmap (Details.get(“Bimage”) is HashMap that hold current position of the image.) and compress the image as PNG and save to the app’s cache.

Specify the intent type that is Intent.ACTION_SEND type used to share data. then set flag to give temporary permission to external app to use your FileProvider and using the method FileProvider.getUriForFile we can generate a secure URI (therefore a unique identifier) pointing to our file.

we use PUTEXTRA method to pass data which we want to share (In this case image data ) & set the share type  specifying the  type of data we share ( Image/png )

Finally start the activity with Intent. createchooser which is used to get the list of installed application which you can use to share the data

complete code for  DataAdapter.java

package com.xxxxxxxxxxxxxxxxxxx.recyclerviewimageshare;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.FileProvider;
import androidx.recyclerview.widget.RecyclerView;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;

public class mDataAdapter extends RecyclerView.Adapter < mDataAdapter.MyViewHolder > {
    private ArrayList < HashMap < String,
    String >> dataSet;
    Context context;


    public mDataAdapter(Context context, ArrayList < HashMap < String, String >> dataSet) {
        this.dataSet = dataSet;
        this.context = context;

    }

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

    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
        final HashMap < String, String > Details = dataSet.get(position);
        holder.bName.setText(Details.get("Bname"));
        holder.bImage.setImageResource(Integer.parseInt((Details.get("Bimage"))));


        holder.visit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                final String website = Details.get("Burl");
                Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(website));
                context.startActivity(browserIntent);

            }
        });

        holder.share.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                // create file from drawable image
                Bitmap bm = BitmapFactory.decodeResource(context.getResources(), Integer.parseInt(Details.get("Bimage")));

                File filesDir = context.getApplicationContext().getFilesDir();
                File imageFile = new File(filesDir, "birds.png");

                OutputStream os;
                try {
                    os = new FileOutputStream(imageFile);
                    bm.compress(Bitmap.CompressFormat.PNG, 100, os); // 100% quality
                    os.flush();
                    os.close();
                } catch (Exception e) {
                    Log.e(getClass().getSimpleName(), "Error writing bitmap", e);
                }


                Intent intent = new Intent();
                intent.setAction(Intent.ACTION_SEND);
                intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                Uri imageUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, imageFile);
                intent.putExtra(Intent.EXTRA_STREAM, imageUri);
                intent.setType("image/*");
                context.startActivity(intent);
            }
        });

    }

    @Override

    public int getItemCount() {
        return (dataSet == null) ? 0 : dataSet.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {

        TextView bName;
        ImageView bImage;
        Button visit;
        Button share;

        MyViewHolder(@NonNull View itemView) {

            super(itemView);
            bName = (TextView) itemView.findViewById(R.id.bName);
            bImage = (ImageView) itemView.findViewById(R.id.bImage);
            visit = (Button) itemView.findViewById(R.id.website);
            share = (Button) itemView.findViewById(R.id.share);

        }
    }
}

Complete code for this project is available here.

Happy Coding Smile

Preethi

Categories
Android

Share Intent and Open URL from Recycler View

In the Previous Post we discussed about the basic concepts of RecyclerView and some basic animation techniques that can be used with it.Now we are going to see

  1. How to use Android Share Intent With Recyclerview
  2. Open separate URL by clicking item in RecyclerView.

Since this is a continuation from the previous post  I am using the  same layout as the previous project. Here I made a small change in design of the page  as shown below:

Screenshot_1596478162

Two buttons Visit and Share has been added with minor modifications. By clicking Visit Button you can visit the corresponding website and share button is used for sharing data  to other application such as WhatsApp, Gmail..etc..

The  main layout code and layout for each row in the List are shown below:

Activity.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:app="http://schemas.android.com/apk/res-auto"
	xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#8B4513"
    android:orientation="vertical"
    tools:context=".MainActivity">
	<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Birds"
        android:textColor="#FFFFFF"
        android:textSize="30dp"
        android:textStyle="bold|italic" />
	<androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"/>
</LinearLayout>

recyclerdata.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
	xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="2dp">
	<LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:background="#8B4513">
	<ImageView
            android:id="@+id/birdimage"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:padding="2dp" />
	<LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
		<TextView
                android:id="@+id/birdname"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:padding="3dp"
                android:textColor="#FFFFFF"
                android:textSize="20sp" />
		<Button
                android:id="@+id/website"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="#8B4513"
                android:gravity="center"
                android:padding="3dp"
                android:text="Visit"
                android:textAllCaps="false"
                android:textColor="#FFFFFF"
                android:textSize="20sp" />
		<Button
                android:id="@+id/share"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:background="#8B4513"
                android:gravity="center"
                android:padding="3dp"
                android:text="Share"
                android:textAllCaps="false"
                android:textColor="#FFFFFF"
                android:textSize="20sp" />
		</LinearLayout>
	</LinearLayout>
</androidx.cardview.widget.CardView>

Below code  is for main Activity. Java file which I already explained in the previous post . The only difference is here just changed the content in the Array List and add one more Array  List that contain the List of URLs  :

MainActivity.java :

package com.xxxxxxxxxxxxxxxxxxxxxxxx;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.Context;
import android.os.Bundle;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
import java.util.ArrayList;
import java.util.HashMap;

public class MainActivity extends AppCompatActivity {
  private RecyclerView recyclerView;
  String[] url = {
    "https://en.wikipedia.org/wiki/Mourning_dove",
    "https://en.wikipedia.org/wiki/Macaw",
    "https://en.wikipedia.org/wiki/Peafowl",
  };
  String[] birds = {
    "Dove Bird",
    "Macaw",
    "Peacock",
  };
  private RecyclerView.Adapter DataAdapter;
  int[] birds_image = {
    R.drawable.dove,
    R.drawable.macaw,
    R.drawable.peacock
  };
  static ArrayList < HashMap < String, String >> dataItem;
  HashMap < String,String > map;

  @Override
  protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    recyclerView = findViewById(R.id.recyclerView);
    LinearLayoutManager mLayoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false);
    recyclerView.setLayoutManager(mLayoutManager);
    dataItem = new ArrayList < >();

    for (int i = 0; i < birds.length; i++) {

      map = new HashMap < String , String > ();
      map.put("Bname", birds[i]);
      map.put("Bimage", birds_image[i] + "");
      map.put("Burl", url[i]);
      dataItem.add(map);
    }
    DataAdapter = new mDataAdapter(getApplicationContext(), dataItem);
    recyclerView.setAdapter(DataAdapter);

  }
}
  1. Open URL in Recycler View Item Click:

As already discussed in the previous post Adapter class Contains three Functions. I will restate the details below,

  1. getItemCount()  which returns the list size . The list values are passed by the constructor.

2. onCreateViewHolder() creates a new ViewHolder object       whenever the RecyclerView needs a new one.

This is the place where the row layout is inflated, passed to the ViewHolder object and each child view can be found and stored.

    3. onBindViewHolder() takes the ViewHolder object and sets the  proper list data for the particular row on the views inside.

In order to open URL in RecyclerView ,Open the Adapter.java file (mDataAdapter.java), inside the onBindViewHolder method create the Android SetOnClickListener method to corresponding Button (Visit). and Inside Android onClick Method write the code for Android Open URL Intent.

url.java

@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {

  final HashMap < String,
  String > Details = dataSet.get(position);
  holder.visit.setOnClickListener(new View.OnClickListener() {@Override
    public void onClick(View v) {
      final String website = Details.get("Curl");
      Log.i("Location , ", website);
      Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(website));
      context.startActivity(browserIntent);
    }
  });
}

You can see from  code, 

first create a Android Intent by passing the type of the intent as Intent.Action_View . The  Intent.Action_View type is used with startActivity() , when you have some information that an activity can show to the user in another activity or app, such as a photo to view in a gallery app, or an address to view in a map app etc. 

In this case, our content is a web page with  URL specified in a ArrayList .

Next use intent.setData to specify the destination (ie your website Link) by using Uri.parse and getting the correct link from the HashMap ( Here I am using HashMap you can use ArrayList dirctly if you want ) that we already created in the MainActivity file.

The method uri.parse merely creates a new uri object from a formatted String.

url

When you click on the visit button the intent call the web browser and the website opens as shown in the gif above.

2. Add Android share Intent for Share Data :

In order to share data to other application you need to add a share intent function. For that inside onBindViewHolder method make the share button clickable by using Android SetOnClickListener method.

In this project we are going to share some text data  to another application . In the next post we will discuss how to share image data using File Provider.

share.java

holder.share.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setAction(Intent.ACTION_SEND);
                intent.putExtra(Intent.EXTRA_TEXT , "Vist This Link more Details \n"  + Details.get("Burl"));
                intent.setType("text/plain");
                context.startActivity(intent);
            }
        });
    }

We are using Intent.ACTION_SEND to share some data which we want to share to other application  such as an email app or social sharing app.

Use PUTEXTRA method to pass data which we want to share.(In this case text data ).

Then set the share type that specifies the type of data you want to share ( in this case plain text).

Finally start the activity with Intent.createchooser which is used to get the list of installed application which you can use to share the data.You can refer here to get more detailed information on the Intent .

Please find the complete code for DataAdapter.java below:

mDataAdapter.java

package com.xxxxxxxxxxxxxxxxxxxxxxxx;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.FileProvider;
import androidx.recyclerview.widget.RecyclerView;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;

public class mDataAdapter extends RecyclerView.Adapter < mDataAdapter.MyViewHolder > {
  private ArrayList < HashMap < String,String >> dataSet;
  Context context;

  public mDataAdapter(Context context, ArrayList < HashMap < String, String >> dataSet) {
    this.dataSet = dataSet;
    this.context = context;

  }

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

  @Override
  public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
    final HashMap < String,String > Details = dataSet.get(position);
    holder.birdName.setText(Details.get("Bname"));
    holder.birdImage.setImageResource(Integer.parseInt((Details.get("Bimage"))));

    holder.visitLink.setOnClickListener(new View.OnClickListener() {@Override
      public void onClick(View v) {

        final String website = Details.get("Burl");
        Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(website));
        context.startActivity(browserIntent);

      }
    });

    holder.share.setOnClickListener(new View.OnClickListener() {@Override
      public void onClick(View v) {

        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_SEND);
        intent.putExtra(Intent.EXTRA_TEXT, "Vist This Link more Details \n" + Details.get("Burl"));
        intent.setType("text/plain");
        context.startActivity(intent);

      }
    });

  }

  @Override

  public int getItemCount() {
    return (dataSet == null) ? 0 : dataSet.size();
  }

  public class MyViewHolder extends RecyclerView.ViewHolder {
    TextView birdName;
    ImageView birdImage;
    Button visitLink;
    Button share;

    MyViewHolder(@NonNull View itemView) {
      super(itemView);
      birdName = (TextView) itemView.findViewById(R.id.birdname);
      birdImage = (ImageView) itemView.findViewById(R.id.birdimage);
      visitLink = (Button) itemView.findViewById(R.id.website);
      share = (Button) itemView.findViewById(R.id.share);

    }
  }
}
share

The Complete Code for this project can be found here

Happy Coding,

Preethi

Categories
Android

Recycler View & Animation Implementation in Android

In this post I will discuss about implementation of Recycler View in Android project and how to add different types of animation in Recycler View.

The Recycler View class is mainly used to display a collection of data. It is flexible and efficient version of List View class provided by the Android framework 

To implement a Recycler View we have to follow the three basic Steps ,

1.Create a Recycler View in our screen layout ,

2.Create a layout for each row in the list,

3.Create an adapter that holds the data and binds them to the list.

1. Create a Recycler View :

a) The First Step is to create a Recycler View in your screen layout. In order to create a Recycler View in your screen layout you have to includes the following support library gradle dependency to project build  gradle file. Remember to update the library version to the most recent one. You can refer it here.

include_library

Now we can add the Recycler View in our project .

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:app="http://schemas.android.com/apk/res-auto"
	xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#50C4D3"
    android:orientation="vertical"
    tools:context=".MainActivity">
	<TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="List"
        android:textColor="#FFFFFF"
        android:textSize="30dp"
        android:textStyle="bold|italic" />
	<androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
      />
</LinearLayout>

b) The next step is  create a Recycler View instance and set it in a Layout Manager. The Layout Manager is responsible for managing and creating the Recycler View behaviour, it is mainly used to decide how you are going to  organise the components . For example

You want to set the orientation of List i.e.  Vertical/Horizontal List –  you can use  Linear Layout Manager ,Similarly if you want a Uniform Grid List  you can use Grid Layout Manager etc which we will discuss in a future Post.

This Project I am using  Linear Layout manager you can choose different Layout Manager according to your requirement. Next step is set the Linear Layout to the  Recycler View instance. You can achieve this in multiple ways .

i) XML approach using androidx: Like this:

Screenshot 2020-07-30 at 13.48.18

If you are looking for a Horizontal Recycler View, change the orientation to horizontal.

ii) Another Way is to add the following cods in java file as shown in Figure:

Screenshot 2020-07-30 at 13.58.25
2. Create layout for each row in the list:

To create a Layout for each row in the list.In this project I am implementing a Recycler View layout as below, that is each row contains one Image View and Text View.

Please Note you can downloads the icons  from  FlatIcon

Screenshot 2020-07-29 at 18.39.47 - Copy
createlayout
createlayout2

Code for each row layout:

recycler_data.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
	xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    >
	<LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:background="#50C4D3">
		<ImageView
            android:id="@+id/flagname"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:padding="2dp" />
		<Space
            android:layout_width="2dp"
            android:layout_height="wrap_content" />
		<TextView
            android:id="@+id/countryname"
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:padding="3dp"
            android:textColor="#FFFFFF"
            android:textSize="20sp" />
	</LinearLayout>
	<Space
        android:layout_width="wrap_content"
        android:layout_height="10dp" />
</androidx.cardview.widget.CardView>
3. Create an adapter that holds the data and binds them to the list:

Define the Array List of items which we want to show in the Recycler View in your java file and pass this items to adapter , Since I want  to pass two Items i.e.  Image and corresponding text in each row I am using a Hash Map and i will add items to it  & add this Hash Map to the Array List.

MainActivity.java

package com.xxxxxxxxxxxxxx.recyclerview;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.Context;
import android.media.Image;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
import android.widget.Adapter;
import android.widget.LinearLayout;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    String[] countryName = {
        "INDIA",
        "USA",
        "UK",
        "FRANCE",
        "INDIA",
        "USA",
        "UK",
        "FRANCE"
    };
    private RecyclerView.Adapter DataAdapter;
    int[] flag = {
        R.drawable.india,
        R.drawable.usa,
        R.drawable.uk,
        R.drawable.france,
        R.drawable.india,
        R.drawable.usa,
        R.drawable.uk,
        R.drawable.france
    };
    static ArrayList < HashMap < String, String >> dataItem;
    HashMap < String, String > map;

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

        LinearLayoutManager mLayoutManager = new LinearLayoutManager(this,
            RecyclerView.VERTICAL, false);
        recyclerView.setLayoutManager(mLayoutManager);

        dataItem = new ArrayList < > ();

        for (int i = 0; i < countryName.length; i++) {

            map = new HashMap < String, String > ();
            map.put("CName", countryName[i]);
            map.put("Cflag", flag[i] + "");
            dataItem.add(map);
        }
        DataAdapter = new mDataAdapter(dataItem);
        recyclerView.setAdapter(DataAdapter);
    }
}

Make sure that you are placing the following codes after the loop.

DataAdapter = new mDataAdapter(dataItem);

recyclerView.setAdapter(DataAdapter); 

To add   the Adapter (mDataAdapter) create a new Class that extends RecyclerView.Adapter and this adapter implements an inner class (MyViewHolder) that extends Recycler.ViewHolder class. MyViewHolder is central to reuse and recycle feature.

Note: In RecyclerView Android includes inbuilt  ViewHolder pattern to improve performance.

If we consider the Base adapter of the ListView ,we know that high cost operations such as layout inflation, data binding of views happens in the same method called getViewMethod(). This approach will leads to unnecessary data binding and view creation.In order to avoid this or in other words improve the performance by using re-usability,  developers had to create Separate Custom View Holder class and manage the data binding efficiently. 

This issues were  well addressed in RecyclerView,

  • Including a Viewholder class as an inbuilt feature.
  • Separating view creation and data binding into different methods. 
javaclass_creation

mDataAdapter.java

package com.xxxxxxxxxxxxxxxx.recyclerview;

import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.HashMap;

import static android.graphics.drawable.Drawable.*;


public class mDataAdapter extends RecyclerView.Adapter < mDataAdapter.MyViewHolder > {
    private ArrayList < HashMap < String,
    String >> dataSet;

    public mDataAdapter(ArrayList < HashMap < String, String >> dataSet) {
        this.dataSet = dataSet;
    }

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

    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder holder, final int position) {
        HashMap < String, String > Details = dataSet.get(position);
        holder.country.setText(Details.get("CName"));
        holder.flag.setImageResource(Integer.parseInt((Details.get("Cflag"))));
    }

    @Override
    public int getItemCount() {
        return (dataSet == null) ? 0 : dataSet.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        TextView country;
        ImageView flag;

        MyViewHolder(@NonNull View itemView) {
            super(itemView);
            country = (TextView) itemView.findViewById(R.id.countryname);
            flag = (ImageView) itemView.findViewById(R.id.flagname);

        }
    }
}

RecyclerView is implemeted with the help of below:

  1. ViewHolder class (MyViewHolder) – Define and Initialize the views which we use to inflate the  each row item

2. getItemCount()  which returns the list size . The list values are passed in the constructor.

3. onBindViewHolder() takes the View Holder object and sets the list data for the particular row on the views. The method where the view binding take place. This helps to avoid unnecessary binding which occurs in the basic implementation of ListView Base Adapter.

4. onCreateViewHolder() row layout is inflated in this method. Note that the return type of this method is the ViewHolder class .

This completes the implementation of Recycler View In Our Project .

The Next step is to add animation to Recycler View.

fall_down

Create an animation Directory . Go to res->new –> Android Resource Directory

animation1
animation2

(Note that in Resource Type Selection if animation is available you can set Resource Type as Animation Otherwise set it as values).

Now create a Animation File (anim/New/Animation Resource File)

animation3

animation4

Now  start  with implementing the requirements in our Animation Resource File . I am implementing a Fall Down Animation. You can change the xml according to your requirement.The duration is the time in milliseconds of the animation.

falldown.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500">
    <translate
        android:fromXDelta="0%"
        android:fromYDelta="-20%"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator" />
    <alpha
        android:fromAlpha="0"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:toAlpha="1" />
    <scale
        android:fromXScale="105%"
        android:fromYScale="105%"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="100%"
        android:toYScale="100%"
      />
</set>

You can refer animation to know more details of animation.

In the next step you have to create another animation file and change the root to layout Animation as shown in Figure.

animation4

Then set android:animation attributes as our previous animation file ( item_fall_down ) .

layout_fall_down. xml

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/item_fall_down"
    android:animationOrder="normal"
    android:delay="15%">
</layoutAnimation>

Now  include this animation in java code . For that define a Layout Animation Controller which is used to animate a layout’s, or a view group’s, children. Each child uses the same animation but for every one of them, the animation starts at a different time. If you want to know more details you can refer Animation Controller .Please Refer the Complete Code below:

Final Code for MainActivity.java

package com.xxxxxxxxxxxxxx.recyclerview;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.content.Context;
import android.media.Image;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
import android.widget.Adapter;
import android.widget.LinearLayout;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    String[] countryName = {
        "INDIA",
        "USA",
        "UK",
        "FRANCE",
        "INDIA",
        "USA",
        "UK",
        "FRANCE"
    };
    private RecyclerView.Adapter DataAdapter;
    int[] flag = {
        R.drawable.india,
        R.drawable.usa,
        R.drawable.uk,
        R.drawable.france,
        R.drawable.india,
        R.drawable.usa,
        R.drawable.uk,
        R.drawable.france
    };
    static ArrayList < HashMap < String, String >> dataItem;
    HashMap < String, String > map;

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

        LinearLayoutManager mLayoutManager = new LinearLayoutManager(this,
            RecyclerView.VERTICAL, false);
        recyclerView.setLayoutManager(mLayoutManager);

        dataItem = new ArrayList < > ();

        for (int i = 0; i < countryName.length; i++) {

            map = new HashMap < String, String > ();
            map.put("CName", countryName[i]);
            map.put("Cflag", flag[i] + "");
            dataItem.add(map);
        }
        DataAdapter = new mDataAdapter(dataItem);
        recyclerView.setAdapter(DataAdapter);

        loadAnimation(recyclerView);
    }

    private void loadAnimation(RecyclerView recycler) {
        Context context = recycler.getContext();
        LayoutAnimationController layoutAnimationController =
            AnimationUtils.loadLayoutAnimation(context, R.anim.item_slide_layout);
        recycler.setLayoutAnimation(layoutAnimationController);
        recycler.getAdapter().notifyDataSetChanged();
        recycler.scheduleLayoutAnimation();
    }
}

highlight Layout animation Controller

If you want to add another animation like given below, the xml code is given

slide_right

item_slide_right.xml

<?xml version="1.0" encoding="utf-8"?>
<set
	xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500">
	<translate
        android:fromXDelta="100%p"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:toYDelta="0%" />
	<alpha
        android:fromAlpha="0.5"
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"
        android:toAlpha="1" />
</set>

item_slide_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/item_slide_right"
    android:animationOrder="normal"
    android:delay="15%">
</layoutAnimation>

Final codes for the app can be seen here

Happy CodingSmile

Preethi

Categories
Tableau

Tableau – How To Use Area Chart And Filters

In the  Previous Post  we were discussing , how to use time series data in Tableau.
Now We analyse our chart from the Previous Post  in more detail.
I am going to explain How to generate a Area Chart and to use some of the powerful features of the area chart to visualize our data in detail.
As I already explained earlier , We can Start by connecting Data Source. Here I am going to take the same  data source what we used.
After connecting the data source We start analysing our data using area Chart.

This was the Time Series Chart What we generated earlier.We Start here.

image4

In this chart we can easily Understand the Unemployment Statics Over a Time Period . Now We want to add more Granularity in this chart , that is we want to analyse in  more detail. For example you want to see the unemployment Statistics of different age group over a period.
how can we do that ? We can use multiple solutions.One of the solutions is to give some colours to different age groups, drag and drop the
AGE in to colours after which we will end up with a Chart like this:

areaChartOne

It is quite difficult to understand the details easily in this chart.,hence we go for an Area Chart. Select the area chart in  the Marked Section in Figure.  You can do the same in another way by using the Show Me Section and
select Area.

areaselection

For more detailed analysis like in the example,  You want to know the Unemployment Statistics of Men over a Period. To Solve these kind of problems we use Filters. You can drag and drop the GENDER into
Filters as shown in the Figure.

gender_drag

If you want to easily access the Filter Property enable the Show Filter Feature, after which you can see the Filter Property on the right Side of the Page.

filterdetail

this is an example of how to add the Area Chart and Filter Property tableau.

Later,
Preethi

Categories
Tableau

Tableau With Time Series Data

The previous post Tableau Visualization I explained how to start  analysing and visualization using Tableau.In this Post I will give you a brief idea of how to use Time Series data analysis with  Tableau.
We can Start our project by  importing data source as I  explained in the previous post.You can get sample data sets from Kaggle.
Consider a Data Sets Like this:

image1

This is a data sets for Long term unemployment statistics . As you can see , this datasets contains a lot of repeated data.Now we want
to analyse the unemployment statistics over a time period.As I already explained in the previous post. We want to drag and drop  Dimensions ( period) and Measures (Unemployment ) to Columns and Rows respectively.You will end up with a  Chart Like this:

image2

If you look the data source you can see that PERIOD field shows data at month level rather than year.But our resulted graph is aggregation of year level .
So we want to change our graph based on month level data. For that , Click on YEAR (Period) , you can see two sections responsible for time.

timeseriesoption

Let us say If you are selecting the First section Month , Then you will end up with a Chart Like this: which is not the chart we are looking for.

image5

Here Tableau is aggregating unemployment statistics based on only MONTH irrespective of AGE ,YEAR,GENDER.You can see
in the graph there is only one occurrence of each month but in our actual data sets same months appears multiple times. The reason is ,  Here Tableau is treating MONTH as Dimension variable. But we are looking for a Time Line variable,  So We have to  select the MONTH in the Second Section that is in the Measures Section as Shown in Figure . In Tableau Measures represents in Green Colour while Dimensions in Blue Colour.

timeseries

Finally We completed our task , and you will get a Chart Like below.If you want to add Colours and Labels to your graph according to
your requirement.(Explained In Previous Post)

image4

Hope You understood how to analyse Timeseries data in Tableau.

Happy AnalysisSmile

Thank You

Preethi