Tuesday, February 20, 2018

Android Working with Butter Knife library Kotlin Tutorial

Hello friends, Today we will see how to use butter knife library in kotlin with a sample project.
Butter knife in java have many tutorials but in kotlin you need to struggle.

What is butter knife

- Butter knife is View Injection library

Why we need it.

Every time finding view by findViewById, declaring them and then perform events like setText, set color, Now using butter knife we can Bind View as @BindView and use them any where.

1. Adding Butter Knife Dependency.

Add this line to build.gradle at the top below apply plugin'com.android.application'
apply plugin: 'kotlin-kapt'
Add dependancy
     dependencies {
                  ...
                  implementation 'com.jakewharton:butterknife:8.8.1'     
                  kapt 'com.jakewharton:butterknife-compiler:8.8.1'    
     }

2.  Usage of View Binding

We will see it by example code with one activity and a fragment to it added dynamically.

Lets see MainActivity.ktl

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import butterknife.ButterKnife

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        ButterKnife.bind(this)

        val fragment = MainFragment.newInstance("MainFragment")
        supportFragmentManager.beginTransaction().add(R.id.container, fragment, "fragment").commit()

    }
}

Here with code you can see  ButterKnife.bind(this) statement keep it in mind and lets add xml layout for MainActivity as activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:id="@+id/container"
    tools:context="com.fd.butterknifesample.MainActivity">
</android.support.constraint.ConstraintLayout>


Now we will consider you know how to show fragment in activity in Kotlin, For those directly starting from this post just look at our previous blog how to add fragment in activity kotlin



Now we have to add fragment and xml layout for fragment so to cover maximum points of butter knife we have added few more widget components on xml layout of fragment 





TextView :- To show use of @BindView
ImageView :- To show use of @BindDrawable and set them to imageview
Button :- To show use of @onClick listener
5 TextView inside cardview :- To show usage of action.


Now we will see code of MainFragment to get whole picture. but first layout of fragment_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
 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"
    tools:context="com.fd.butterknifesample.MainActivity">

    <TextView
        android:id="@+id/textView" 
       android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:gravity="center"
        android:text="@string/label_demo"
        android:textSize="20sp"
        app:layout_constraintBottom_toTopOf="@+id/imageViewDemo"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button android:id="@+id/buttonDemo"
        android:layout_width="wrap_content"
        android:layout_height="51dp"
        android:layout_marginBottom="144dp"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textInputLayoutDemo" />

    <TextView android:id="@+id/textViewDemo"
        android:layout_width="208dp"
        android:layout_height="wrap_content"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:text="TextView"
        app:layout_constraintBottom_toTopOf="@+id/textInputLayoutDemo"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.247"
        app:layout_constraintStart_toEndOf="@+id/imageViewDemo"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        app:layout_constraintVertical_bias="0.2" />

    <ImageView android:id="@+id/imageViewDemo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="28dp"
        android:layout_marginStart="28dp"
        android:contentDescription="@string/imageView_contentDesc"
        android:src="@android:drawable/dialog_frame"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/textView"
        app:layout_constraintVertical_bias="0.1"
        tools:layout_editor_absoluteY="74dp" />

    <android.support.design.widget.TextInputLayout
        android:id="@+id/textInputLayoutDemo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:hint="Enter your name"
        app:layout_constraintBottom_toTopOf="@id/buttonDemo"
        app:layout_constraintTop_toBottomOf="@id/imageViewDemo"
        app:layout_constraintVertical_bias=".30"
        tools:layout_editor_absoluteY="169dp">
        <android.support.design.widget.TextInputEditText
            android:id="@+id/textInputEditDemo"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="hint" />
    </android.support.design.widget.TextInputLayout>

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/buttonDemo"
        tools:layout_editor_absoluteX="8dp"
        tools:layout_editor_absoluteY="400dp">

        <android.support.v7.widget.LinearLayoutCompat
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <TextView android:text="textView 1"
                android:id="@+id/textView1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="5dp" />

            <TextView android:text="textView 2"
                android:id="@+id/textView2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="5dp" />

            <TextView android:text="textView 3"
                android:id="@+id/textView3" 
               android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="5dp" />
            <TextView android:text="textView 4"
                android:id="@+id/textView4"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="5dp" />

            <TextView android:text="textView 5"
                android:id="@+id/textView5" 
               android:layout_width="match_parent" 
               android:layout_height="wrap_content"
                android:layout_marginBottom="5dp" />
        </android.support.v7.widget.LinearLayoutCompat>
    </android.support.v7.widget.CardView>
</android.support.constraint.ConstraintLayout>

In kotlin we can not keep any field as null like as Java to attain NullSafety so while binding views we use lateinit keyword of kotlin.

@BindView : -

    @BindView(R.id.textViewDemo)
    lateinit var mTextViewDemo: TextView
bind a single view to field "mTextViewDemo" and use it anywhere.

@BindViews :-

Similar to bindView but can be used to bind multiple view of same type to perform a comman operation like setText using butter knife ACTION
Bind 5 textview to a mutable list. If you are using normal list then use  @JvmField, when using @JvmField you can not use lateinit keyword.
    //BindViews    @BindViews(R.id.textView1, R.id.textView2, R.id.textView3, R.id.textView4, R.id.textView5)
    lateinit var labelArray: MutableList<TextView>

@onClick :-

@OnClick(R.id.buttonSample)
internal fun sayHello() {
    Toast.makeText(this, "Hello butter knife from kotlin", LENGTH_SHORT).show()
}


Bind ButterKnife library to your activity and fragment unless it is added you will get run time exceptions as lateinit field not initialized.

To bind it to fragment declare

            var mUnbinder: Unbinder? = null
Now bind it in onCreateView of Fragment as below
      //Bind this view to butterknife   
     mUnbinder = ButterKnife.bind(this, rootView!!)

Unbind it to avoid memory leaks like as below.
 override fun onDestroyView() {
        super.onDestroyView()

        //unbind view from butterknife to avoid any memory leak  
       mUnbinder!!.unbind()
    }

ACTION :-

actions are used to perform repeating task.  like we have multiple textview and they need to populated with sum text run time so instead of binding them to field and assign values them one by one
bind those multiple textviews to a mutable list and keep all the text in array which is going to assing and create one action like below.

 //Create action to set values to list of textView
val action_set_text = ButterKnife.Action<TextView?> { view, index -> view.setText(mLabel[index]) }

ButterKnife.apply(labelArray, action_set_text)


Now see at complete source code of MainFragment

MainFragment.ktl


package com.fd.butterknifesample

import android.content.Context
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.support.annotation.ColorIntimport android.support.design.widget.TextInputEditText
import android.support.design.widget.TextInputLayout
import android.support.v4.app.Fragment
import android.support.v4.text.TextUtilsCompat
import android.text.TextUtils
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 android.widget.Toast
import butterknife.*

/** * Created by Jayesh on 2/19/2018. */class MainFragment : Fragment() {


    var mUnbinder: Unbinder? = null
    var mParam: String? = null

    // BindView    @BindView(R.id.textViewDemo)
    lateinit var mTextViewDemo: TextView

    @BindView(R.id.textInputEditDemo)
    lateinit var mTextInputLayoutDemo: TextInputEditText

    @BindView(R.id.imageViewDemo)
    lateinit var mImageViewDemo: ImageView

    //BindViews    @BindViews(R.id.textView1, R.id.textView2, R.id.textView3, R.id.textView4, R.id.textView5)
    lateinit var labelArray: MutableList<TextView>

    //Bind Color    @JvmField    @BindColor(android.R.color.white)
    @ColorInt    internal var mColor: Int = 0

    //Bind Drawable    @JvmField    @BindDrawable(R.mipmap.ic_launcher)
    var mDrawable: Drawable? = null

    @JvmField    @BindView(R.id.buttonDemo)
    var mButton: Button? = null

    var mLabel = arrayOf<String>("One", "Two", "Three", "Four", "Five")
    var mLabelColor = arrayOf<Int>(Color.BLACK, Color.BLUE, Color.GREEN, Color.MAGENTA, Color.YELLOW)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (arguments != null) {
            mParam = arguments.getString(ARG_PARAM)
        }
    }


    override fun onDestroyView() {
        super.onDestroyView()

        //unbind view from butterknife to avoid any memory leak        mUnbinder!!.unbind()
    }


    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View {
        val rootView: View? = inflater?.inflate(R.layout.fragment_main, container, false);

        //Bind this view to butterknife        mUnbinder = ButterKnife.bind(this, rootView!!)

        //Create action to set values to list of textView        val action_set_text = ButterKnife.Action<TextView?> { view, index -> view.setText(mLabel[index]) }        ButterKnife.apply(labelArray, action_set_text)


        val action_change_color = ButterKnife.Action<TextView> { view, index -> view.setTextColor(mLabelColor[index]) }
        ButterKnife.apply(labelArray, action_change_color)

        // Set Drawable to ImageView        mImageViewDemo?.setImageDrawable(mDrawable!!)

        mButton?.setOnClickListener {
            if (!TextUtils.isEmpty(mTextInputLayoutDemo?.text.toString()))
                mTextViewDemo?.text = mTextInputLayoutDemo?.text.toString()
            else                Toast.makeText(activity!!, "Type some text first", Toast.LENGTH_SHORT).show()
        }
        //Now assign ONCLICK        @OnClick(R.id.buttonDemo)
        fun onButtonClick() {
            if (!TextUtils.isEmpty(mTextInputLayoutDemo?.text.toString()))
                mTextViewDemo?.text = mTextInputLayoutDemo?.text.toString()
            else                Toast.makeText(activity!!, "Type some text first", Toast.LENGTH_SHORT).show()
        }


        return rootView!!;

    }


    override fun onAttach(context: Context?) {
        super.onAttach(context)
    }


    companion object {

        val ARG_PARAM: String = "PARAM1"

        fun newInstance(param: String): MainFragment {

            val fragment = MainFragment()
            var arg: Bundle = Bundle()
            arg.putString(ARG_PARAM, param)

            fragment.arguments = arg
            return fragment


        }

    }

    @OnClick(R.id.buttonSample)
    internal fun sayHello() {
        Toast.makeText(this, "Hello butter knife from kotlin", LENGTH_SHORT).show()
    }


}


Like @BindView and @BindViews there are more tags like
@BindInt
@BinfString
@BindDrawable
@BindFloat
@BindFont
@BindBitmap
@BindAnim
@BindDimen
 @BindColor

These are all similar to @BindView try them by yourself. and enjoy.



Monday, February 19, 2018

How to initialize array in kotlin

Hello friends today we will see how to initialize array in Kotlin.

1. Lets have a String array.


//In Java
String[] mLabel={"One","Two","Three","Four","Five"}
// In Kotlin 
var mLabel = arrayOf<String>("One", "Two", "Three", "Four", "Five")

2. Lets have int array


// In Java
int[] numbers = {1,2,3,4,5}
// In Kotlin


val numbers : IntArray = intArrayOf(1,2,3,4,5) 
3. Create array of size and initialize with value lambda

 val nu : IntArray =kotlin.IntArray(5) 
  val num : IntArray = kotlin.IntArray(5,{i->1})
     Create int array of size 5 and initializes with 1

Understand Polymorphism to solve A a =new B() problem

Hi friends today I come across that many people stumble on a common question asked in JAVA/Android interview many time.

Problem states that if there is class as A and B and C. B extends A and in class C we have something like



A a =new B();
          B b= new A();



Ok So question is whether above statements are valid or not.

To validate it remember Polymorphism in Java - like biology term species (object) can have many forms - stages.

Means SuperClasses can be initialized with SubClasses. but reverse is not true.

If class B is extending class A, so here class A is superclass and class B is subclass.

Now by this statement

          // is valid 
A a= new B();
But reverse is not true.

B b= new A(); // will not compile and gives error - incompatible types
now call method on
  a.someMethod();

if both class A and B have same method like someMethod(); which method will be called.


No doubt class B's method will be called as B's instance is assigned to a.

A a =new B();
       a.someMethod();  ///calls class B 's method.


Now complete picture is here.

***************************************************************************
import java.util.*;
class Test{
      public static void main(String args[]){
             Test test=new Test ();
              test.run();
       }
       public void run(){
               // Valid class A's object assign to  A
              A a =new A();
             // Valid as class B's object assign to B
              B b=new B();
            // Call display method of class A
            a.display();
           // Call display method of class B
           b.display();
           // Valid as object of B class is assign to a 
           a=new B();
          // Here call display method of class B???
          a.display();
         //??Why because now A a holds object of class B
         // Now call to this method?  What will Happen
         b=new A();                
         // throws runtime exception "incompatible types -                 // class A can not be converted to  B"          
        // So this method won't work.
        b.display();
        // Then why A a =new B(); is valid.
       // By the property of polymorphism 
}
             class A{
                      public void display(){
                                System.out.println("Method of A");
                      }
              }


          class B extends A{
                   public void display(){
                               System.out.println("Method of B");
                   }
          }
}
*****************************OUTPUT**************************************

Method of A
Method of B
Method of B



 That't it copy above program to save as Test.java  modify it according your doubt and clear them. 

Tuesday, February 13, 2018

How to add Fragment in Activity - Kotlin

Today we are going to see how to add fragment in activity dynamically using kotlin
Kotlin is statically types programming language and can be run on jvm and JavaScript.

Since Android Studio 3.0 Kotlin is fully supported

Some Bits of Kotlin.


1. Variables in kotlin are immutable declared as val
val arg : String="Immutable"
And mutable variables declared as var
var sum : Int
         sum=5 +5

2. Semicolon in kotlin is optional

Now lets see in step by step approach of how to add fragment to the activity.

Step 1: Start Android Studio 3.0.1 or latest

Start new  "Android Studio Project" Enter Project name as "FragmentInKotlin" change package name
Make sure to check "Include kotlin support" Click next

Step 2: Do not add any Activity

We will create our activity and fragments by ourself, Click next and Finish.


Step 3: Create MainActivity by adding new kotlin class

Once project is opened in  Android Studio right click on your package choose new kotlin class
Enter name as "MainActivity" as below


Step 4: Create main.xml layout for main activity

As below or copy below code



<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/container" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:tools="http://schemas.android.com/tools" tools:context="com.droidtech.fragmentinkotlin.MainActivity"> </LinearLayout>


Here we have added id to our layout as it is going to behave as container of our Fragment.
Now set this layout to our MainActivity.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // set main.xml as view    setContentView(R.layout.main)
} 

Step 5: Create Fragment and layout of Fragment
To add fragment step 3 will be same.

Create MainFragment as follow.                   
Now you must have some basic syntax of kotlin.

class MainFragment : Fragment() {

    var mParam: String? = null    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (arguments != null)
            mParam = arguments.getString(ARG_PARAM)

    }
   

    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater!!.inflate(R.layout.fragment_main, container, false)

        val button = view.findViewById<Button>(R.id.button)
        button.setOnClickListener  { mListener!!.onInteractionHappened("button Clicked") }        return view
    }

    companion object {

        val ARG_PARAM: String = "param"
        fun neInstance(param: String): MainFragment {
            val fragment = MainFragment()
            val args = Bundle()
            args.putString(ARG_PARAM, param)
            fragment.arguments = args
            return fragment
        }
    }

Now Create fragment_main.xml in layout folder as below.


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"           android:layout_width="match_parent" android:layout_height="match_parent"  android:orientation="vertical">

  <TextView android:layout_width="wrap_content" android:layout_height="wrap_content"     
    android:gravity="center" android:text="@string/label_welcome" 
    android:textColor="@color/colorAccent" android:textSize="20dp" />

 <Button android:onClick="onClick" android:layout_marginTop="20dp" android:id="@+id/button" 
    android:layout_width="match_parent" android:layout_height="wrap_content" 
    android:text="Button" />

 </LinearLayout>


 Step 6: Add fragment to our MainActivity

As below.
// Now add this MainFragment to contaner layoutval fragment = MainFragment.neInstance("Main Fragment")
val ft: FragmentTransaction = supportFragmentManager.beginTransaction()
ft.add(R.id.container, fragment, "MAINFRAGMENT")
ft.commit()
Step 7: Manifest entry of MainActivity

We have added our fragment to MainActivity now add MianActivity entry to manifest.xml file as below.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.droidtech.fragmentinkotlin">

   <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" 
      android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" 
      android:supportsRtl="true" android:theme="@style/AppTheme">

 <activity android:name=".MainActivity" android:configChanges="orientation|keyboardHidden" 
     android:launchMode="standard"> 

<intent-filter>
         <action android:name="android.intent.action.MAIN" /> 
<category   android:name="android.intent.category.LAUNCHER" /> 
</intent-filter>

 </activity>

 </application>

 </manifest>Step 8: Interface in fragment for callback from interface to acivity.

In kotlin interface creation is similar to java as

interface OnMainFragmentInteractionListener {
    fun onInteractionHappened(arg: String)
}

Declare interface as
var mListener: OnMainFragmentInteractionListener? = null

we have declared interface object as var because at time of declaration we don't know it's value later we will assign to it so it makes it mutable.

override fun onAttach(context: Context?) {
    super.onAttach(context)
    if (context is OnMainFragmentInteractionListener) {
        mListener = context
    } else {
        throw ClassCastException(context.toString() +
            " must implement OnMainFragmentInteractionListener")
    }
}                                                          
 Now activity must implement this interface as below full code for mainActivity is as below.

package com.droidtech.fragmentinkotlin

import android.os.Bundle
import android.support.v4.app.FragmentTransaction
import android.support.v7.app.AppCompatActivity
import android.widget.Toast

/** * Created by Jayesh on 2/12/2018. */class MainActivity : AppCompatActivity(), MainFragment.OnMainFragmentInteractionListener {
    override fun onInteractionHappened(arg: String) {
        Toast.makeText(baseContext, "event fired" + arg, Toast.LENGTH_SHORT).show()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // set main.xml as view        setContentView(R.layout.main)
        // Now add this MainFragment to contaner layout        val fragment = MainFragment.neInstance("Main Fragment")
        val ft: FragmentTransaction = supportFragmentManager.beginTransaction()
        ft.add(R.id.container, fragment, "MAINFRAGMENT")
        ft.commit()

    }

    override fun onRestart() {
        super.onRestart()
    }

    override fun onStart() {
        super.onStart()
    }

    override fun onResume() {
        super.onResume()
    }

    override fun onPause() {
        super.onPause()
    }

    override fun onStop() {
        super.onStop()
    }


    override fun onDestroy() {
        super.onDestroy()
    }

}


Build and run your project.

Stay cool have beers.