Author

Surya

Browsing

In this blog, we’ll talk about coroutine scope. What is scope in the relation to coroutine? How does work and what possible types we can use in Kotlin?

What is coroutine scope

The scope simply provides lifecycle methods for coroutines and allows us to manage coroutines to start and stop them.

GlobalScope.launch { }

Now we have already seen the global scope when we run the hello word code in our previous article. So GlobalScope, simply means the scope of this coroutines is the entire application. It will not get finished, if it is running in the background it won’t stop unless the whole application stop.

The important this is a very large scope and it’s usually not used. we used it in HelloWord program because it’s very simple, very easy. It allows us to create a background thread. It is not very commonly used.

        GlobalScope.launch {
            delay(500L)
            println("Task from GlobalScope")
        }

runBlocking

The next stuff is run blocking, Now run runBlocking creates scope and run coroutine in a blocking way. so this again you would not use very often. You would use only use it when you want to stop the execution of a code and run your coroutines.

In other situations where you might want to use it If this is the only thing that your program does. We will use this quite extensively in our examples to start a scope for our coroutines when this is the only thing that you are trying to do.

    runBlocking {
        launch {
            delay(1000L)
            println("Task from runBlocking")
        }

coroutinesScope { }

Finally, we have coroutinesScope, It creates a new scope and does not complete until all children’s coroutines complete. So we are creating a scope, we are running coroutines and inside the scope, we can create other coroutines. This coroutine that starts here does not complete until all the inner coroutines complete as well.

 coroutineScope {
            launch {
                delay(1500L)
                println("Task from coroutineScope")
            }
        }

Coroutine Context

A context is very tightly related to the scope. So you can say Scope and Context are very similar. They are basically concepts but used in different ways.

A context is a set of data that related to the coroutine. In simple words, Context is a set of variables that you can access inside of the coroutine. All coroutine has an associate context

Scope and Context are very similar only difference is that scope used to create and manage coroutine. Whereas Context is the set of variables and data associate with that coroutine.

Important element of Coroutines Context

  • Dispatcher – It simply decides which thread the coroutine runs on. We’ll learn more about Dispatcher in the upcoming blog.
  • Job – It basically handle the coroutine lifecycle. This concept also I’ll write separate articles on that.

All right, So that is basic idea of a Coroutine Context. Now I’m taking one example of Coroutine Context.

Let go head and create a coroutine and we’ll access a peace of data from that coroutine.

import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main() {
    runBlocking {
        launch(CoroutineName("myCoroutine")) {
            println("This is run from ${coroutineContext.get(CoroutineName.Key)}")
        }
    }
}

In the above code snippets, Here I passed a function named is CoroutineName(“myCoroutine”). You can pass a name here in our launch. Inside the Coroutine, I simply print some message. Now run the code you will get like below. So here is a coroutine context.

This is run from CoroutineName(myCoroutine)

Summary

Let summarises what we learned in this tutorials

Scope – Provides lifecycle methods for coroutines and allow us to start and stop coroutines

GlobalScope.launch { } – the scope of the coroutine is the lifecycle of the entire application

runBlocking – creates a scope and runs a coroutine in a blocking way

coroutineScope { } – creates a new scope and does not complete until all children coroutines complete

Learn more about our coroutines series

In this blog, let’s briefly discuss what Coroutines, This blog dedicated to beginners, they can learn the basic concept of coroutines, Once you understand these concepts of coroutines. You can become a master Coroutines.

Why we should use coroutines

Very first let understand why we should Coroutines an instance of thread. What is the very basic difference between thread and Coroutines? and why we want to use it instance on Thread. So let started

Thread are resource intensive

So the main problem with threads is it very resource-intensive. So it takes a lot of resources to start a thread, stop a thread, coordinate between threads, and so on. Meanwhile, Coroutines are lightweight threads Infect is very very lightweight threads.

Coroutines are lightweight threads

So we have a program where we start about millions of Coroutines and no problem in memory. If you try to start maybe a thousand threads your program will run out of memory will crash. But Coroutines are very very lightweight so you can start as many as you like with no overhead with no problem.

Ok so basically Coroutines to use pulls a thread pool is, let’s think about it as a bunch of thread that you can use whenever you like. So you have a small Coroutines which small unit of executions. Then you assign it to as thread. When the Coroutines is finishes the thread is put back in the thread pool ready to reuse by another Coroutines that need it.

Okay so they reuse threads they use lightweight functionality so you can start as many as you like with absolutely no impact on performance

Simplify async code, callback and synchronisation

Now these simplify greatly async code, So callback and synchronization are very very easy to use in Coroutines and actually they make parallel programming look very likes of sequential programming

So you can start a Coroutines code and immediately access variables and methods in your program without any overhead. And that is how easy it is to do callback from a Coroutines to your program and synchronization is also very useful, just you have 2 or 3 methods that you to synchronize between Coroutines without any overhead.

Wheres thread is very complicated and if you’ve ever worked with the thread you know what headache they can be especially when you start a lot of them need a synchronization between them.

Simple syntax

Coroutines have very very simple common syntax. So they have few concept that we will discuss in this blog, that fit together very nicely and Once you understand those concept they are very easy to use to start Coroutines and execute code in parallel. Now they can pause and resume at any time and a coroutines is not bound to a thread.

A thread simply place to execute the coroutines but the coroutines itself can be stoped at any time and restarted at any time.

So In that way they are very light weight and can be reused as many times as you like.

Coroutines basic concept

Now let go through a basic concept of Coroutines and here I’m going to list them and the upcoming article we’re going through them one by one and see the implementation with example. So let started

Scope

So the first idea is a scope. The scope is what creates and runs coroutines. It provides life cycle event so things like pausing a coroutine stopping, cancelling a coroutine, is handled by a scope.

Context

Now the context is a concept that is very tied to the scope. So the scope itself provides a context and The Context is simply the state of coroutine. Basically, It provides some variable some functionality that you can use in your coroutine. So that is a context the scope and context are very tightly tied together.

Suspending functions

Suspending function are basically functions that can be run in a coroutine or can be suspended as we call them. So basically they provide functionality that you use to run in parallel that you want o run in parallel.

Jobs

So next stuff we have jobs. Now a job is basically a handle on a coroutine and you can use a job to access the lifecycle methods of a coroutine. Okay so when you create a coroutine in a certain way which we will see in upcoming articles cancel the coroutine

You will create a job and job can we used to let say cancel the coroutine, If you choose later on next up we have a deferred which is basically a call team that returns a result.

Deferred

The next thing we have deferred is basically a call team that returns a result but sends a coroutine run in parallel. You can not return the result immediately. The result can only be only returned when the coroutine finishes its execution.

So that means we need deferred which is a future result of a coroutine and what you can do with a deferred, basically tell the program to wait for the outcome of that coroutine. when you are at a point where you need that result.

Dispatchers

Next, we dispatchers, which simply says that dispatchers manage a certain number of threads, and whenever a coroutine needs to run, it will assign it to a thread and run in time that particular thread.

So dispatcher we have just a few of them that are more or less suited for certain tasks that we will discuss in this post.

Error handling

Error handling kind of self-explanatory. It basically provides a way to handle any errors that might come up in a coroutine.

Conclusion

So that’s it these are major concepts of the coroutine. I the blog we’ll discuss these concepts in detail one by one. Once you understand the basics idea of coroutines. You can easily play around will all these concepts to give you the functionality that you require.

Estimated reading time: 5 minutes

Hello folks! In this article, We’ll learn the best practices of SharedPreferences in Android(Kotlin). I’ll show you, how we can store and retrieve values in SharedPreferences. For better understanding, I’ll create an android SharedPreferences example (Sample app) and take an example of Writing and Reading Values in SharedPreferences. So let started

What are SharePreferences?

SharedPreferences is an android API that stores app data using key-value pairs and provides simple methods to read and write them.

Android system provides several options for you to save your data. These options are App-specific storage, Shared storage, Preferences, Databases. SharePreferences comes in Preference. It offers a framework to save private, primitive data in key-value pairs.

Why SharePreferences?

They’re mostly used to store user states when it comes to user settings or keeps a piece of small information(User details etc.) without needing storage permission. As per my opinion, you should store small primitive value in Preferences such as booleans, ints, longs, floats, and strings.

Modes in SharePreferences

SharedPreferences have different MODE these are below

1. Create a android application

Let take an example, open android studio, and create a new project. Now create a interface named is IPreferenceHelper. In this Interface we are defining some getter setter for storing or retrieving preference value. such as ApiKey and UserId etc.

package com.sharedpreferencesexample

interface IPreferenceHelper {

    fun setApiKey(apiKey: String)

    fun getApiKey(): String

    fun setUserId(userId: String)

    fun getUserId(): String

    fun clearPrefs()

}

2. Create a singleton class for managing Preferences

Ideally SharedPreferences store the app level value, So the SharedPreferences instance should be single threw out the app. It should be a singleton. Let create a Singletone class named is PreferenceManager and implement IPreferenceHelper. Just like below

open class PreferenceManager constructor(context: Context) : IPreferenceHelper {
    private val PREFS_NAME = "SharedPreferenceDemo"
    private var preferences: SharedPreferences

    init {
        preferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
    }

    override fun setApiKey(apiKey: String) {
        preferences[API_KEY] = apiKey
    }

    override fun getApiKey(): String {
        return preferences[API_KEY] ?: ""
    }

    override fun setUserId(userId: String) {
        preferences[USER_ID] = userId
    }

    override fun getUserId(): String {
        return preferences[USER_ID] ?: ""
    }

    override fun clearPrefs() {
        preferences.edit().clear().apply()
    }

    companion object {
        const val API_KEY = "api_key"
        const val USER_ID = "user_id"
    }
}

3. Write into your SharedPreferences

Normally, writing into SharedPreferences is simple. But I’m going to write a Kotlin extension, This extension is make writing very simple and reduce boilerplate code.

/**
 * SharedPreferences extension function, to listen the edit() and apply() fun calls
 * on every SharedPreferences operation.
 */
private inline fun SharedPreferences.edit(operation: (SharedPreferences.Editor) -> Unit) {
    val editor = this.edit()
    operation(editor)
    editor.apply()
}

/**
 * puts a key value pair in shared prefs if doesn't exists, otherwise updates value on given [key]
 */
private operator fun SharedPreferences.set(key: String, value: Any?) {
    when (value) {
        is String? -> edit { it.putString(key, value) }
        is Int -> edit { it.putInt(key, value) }
        is Boolean -> edit { it.putBoolean(key, value) }
        is Float -> edit { it.putFloat(key, value) }
        is Long -> edit { it.putLong(key, value) }
        else -> throw UnsupportedOperationException("Not yet implemented")
    }
}

4.  Read from SharedPreferences

Reading a value from SharedPreferences is also straightforward. I’m going to write another useful extension that provides more control over retrieving a value from SharedPreferences. Let check below code

/**
 * finds value on given key.
 * [T] is the type of value
 * @param defaultValue optional default value - will take null for strings, false for bool and -1 for numeric values if [defaultValue] is not specified
 */
private inline operator fun <reified T : Any> SharedPreferences.get(
    key: String,
    defaultValue: T? = null
): T? {
    return when (T::class) {
        String::class -> getString(key, defaultValue as? String) as T?
        Int::class -> getInt(key, defaultValue as? Int ?: -1) as T?
        Boolean::class -> getBoolean(key, defaultValue as? Boolean ?: false) as T?
        Float::class -> getFloat(key, defaultValue as? Float ?: -1f) as T?
        Long::class -> getLong(key, defaultValue as? Long ?: -1) as T?
        else -> throw UnsupportedOperationException("Not yet implemented")
    }
}

5. Finally your PreferenceManager class look like below

package com.sharedpreferencesexample

import android.content.Context
import android.content.SharedPreferences

open class PreferenceManager constructor(context: Context) : IPreferenceHelper {
    private val PREFS_NAME = "SharedPreferenceDemo"
    private var preferences: SharedPreferences

    init {
        preferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
    }

    override fun setApiKey(apiKey: String) {
        preferences[API_KEY] = apiKey
    }

    override fun getApiKey(): String {
        return preferences[API_KEY] ?: ""
    }

    override fun setUserId(userId: String) {
        preferences[USER_ID] = userId
    }

    override fun getUserId(): String {
        return preferences[USER_ID] ?: ""
    }

    override fun clearPrefs() {
        preferences.edit().clear().apply()
    }

    companion object {
        const val API_KEY = "api_key"
        const val USER_ID = "user_id"
    }
}


/**
 * SharedPreferences extension function, to listen the edit() and apply() fun calls
 * on every SharedPreferences operation.
 */
private inline fun SharedPreferences.edit(operation: (SharedPreferences.Editor) -> Unit) {
    val editor = this.edit()
    operation(editor)
    editor.apply()
}

/**
 * puts a key value pair in shared prefs if doesn't exists, otherwise updates value on given [key]
 */
private operator fun SharedPreferences.set(key: String, value: Any?) {
    when (value) {
        is String? -> edit { it.putString(key, value) }
        is Int -> edit { it.putInt(key, value) }
        is Boolean -> edit { it.putBoolean(key, value) }
        is Float -> edit { it.putFloat(key, value) }
        is Long -> edit { it.putLong(key, value) }
        else -> throw UnsupportedOperationException("Not yet implemented")
    }
}

/**
 * finds value on given key.
 * [T] is the type of value
 * @param defaultValue optional default value - will take null for strings, false for bool and -1 for numeric values if [defaultValue] is not specified
 */
private inline operator fun <reified T : Any> SharedPreferences.get(
    key: String,
    defaultValue: T? = null
): T? {
    return when (T::class) {
        String::class -> getString(key, defaultValue as? String) as T?
        Int::class -> getInt(key, defaultValue as? Int ?: -1) as T?
        Boolean::class -> getBoolean(key, defaultValue as? Boolean ?: false) as T?
        Float::class -> getFloat(key, defaultValue as? Float ?: -1f) as T?
        Long::class -> getLong(key, defaultValue as? Long ?: -1) as T?
        else -> throw UnsupportedOperationException("Not yet implemented")
    }
}

6. Access PreferenceManager into your presentation layers

Yes, Now your PreferenceManager class is ready for use. You can initialize PreferenceManager class into your ViewModel and Activity/Fragment, Make sure the context should be applicationContext.

7. Now open the activity_main.xml and paste below code.

For making interesting example I have added two edit text and one button in this layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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:padding="16dp"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Hello World!" />

    <EditText
        android:id="@+id/editText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="User Id"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/editText2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="API Key"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/editText" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="32dp"
        android:text="Show Preference Data"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/editText2" />

</androidx.constraintlayout.widget.ConstraintLayout>

8. Let access PreferenceManager class in your source file

Let’s check the below code This way you can easily read and write the value in SharePreferences

package com.sharedpreferencesexample

import android.annotation.SuppressLint
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    private val preferenceHelper: IPreferenceHelper by lazy { PreferenceManager(applicationContext) }

    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // display saved data
        textView.text =
            " API Key - > ${preferenceHelper.getApiKey()} \n User Id -> ${preferenceHelper.getUserId()}"
        button.setOnClickListener {
            // Update data in SharedPreference
            preferenceHelper.setApiKey(editText.text.toString())
            preferenceHelper.setUserId(editText2.text.toString())
            // display saved data
            textView.text =
                " API Key - > ${preferenceHelper.getApiKey()} \n User Id -> ${preferenceHelper.getUserId()}"
        }

    }
}

7. Build & Test

Let run the app, in a movement your app will up and run, Now enter few value these EditText and click button. The value will display on TextView. This way you can read and write small amount of data in key-value pairs!

Conclusion

In this android SharedPreferences example, we’ll learn how we can save and retrieve value in SharedPreferences. I try to follow best practices for android development. Still, you want to improve… Most Welcome

Follow this article to detect network change in Android!

In this blog, I’ll show how to check internet connection in android programmatically. While we are developing a professional app, you may need to check internet available or not. For example, while you are calling APIs you may need to check internet connection several times in an app. In this example, we’ll learn how we can check internet connections any place and anywhere.

I’m going to create a demo application, This app will automatically detect the internet changes using an internet connection listener. For the demonstration, I’ll create a sample app that app will capable of continuously check internet connection with android. So let started.

Create Android Project

Let move to Android Studio, and create a fresh project with some default template. We are going to use java 1.8 stuff in our project so lets set java version in app build.gradle file

  compileOptions {
        sourceCompatibility = 1.8
        targetCompatibility = 1.8
    }
    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_1_8.toString()
    }  

Add ACCESS_NETWORK_STATE permission in Manifest

For detecting network permission we required some permission so let open the AndroidManifest and add below permission.

  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Write a ConnectivityProvider interface

I’m going to write complete solution for check internet connection for pre and post LOLLIPOP devices solution in a single interface. Please have a look

package com.detectnetworkchange.connectivity.base

import android.content.Context
import android.content.Context.CONNECTIVITY_SERVICE
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkInfo
import android.os.Build
import androidx.annotation.RequiresApi
import com.detectnetworkchange.connectivity.ConnectivityProviderImpl
import com.detectnetworkchange.connectivity.ConnectivityProviderLegacyImpl

interface ConnectivityProvider {

    fun subscribe()

    fun getNetworkState(): NetworkState

    @Suppress("MemberVisibilityCanBePrivate", "CanBeParameter")
    sealed class NetworkState {
        object NotConnectedState : NetworkState()

        sealed class ConnectedState(val hasInternet: Boolean) : NetworkState() {

            @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
            data class Connected(val capabilities: NetworkCapabilities) : ConnectedState(
                    capabilities.hasCapability(NET_CAPABILITY_INTERNET)
            )

            @Suppress("DEPRECATION")
            data class ConnectedLegacy(val networkInfo: NetworkInfo) : ConnectedState(
                    networkInfo.isConnectedOrConnecting
            )
        }
    }

    companion object {
        @JvmStatic
        fun createProvider(context: Context): ConnectivityProvider {
            val cm = context.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                ConnectivityProviderImpl(cm)
            } else {
                ConnectivityProviderLegacyImpl(context, cm)
            }
        }
    }
}

Extend ConnectivityProvider interface

Now create a abstract class named ConnectivityProviderBaseImpl which extends ConnectivityProvider interface, like below

package com.detectnetworkchange.connectivity.base

import com.detectnetworkchange.CONNECTED
import com.detectnetworkchange.DISCONNECTED
import com.detectnetworkchange.NetWorkManger
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState

abstract class ConnectivityProviderBaseImpl : ConnectivityProvider {
    override fun subscribe() {
        subscribeListener()
        //init status
        dispatchChange(getNetworkState())
    }

    protected fun dispatchChange(state: NetworkState) {
        val networkState = if (state.hasInternet()) CONNECTED else DISCONNECTED
        if (networkState != NetWorkManger.networkStatus.value) {
            NetWorkManger.networkStatus.postValue(networkState)
        }
    }

    private fun NetworkState.hasInternet(): Boolean {
        return (this as? NetworkState.ConnectedState)?.hasInternet == true
    }

    protected abstract fun subscribeListener()
}

Write a actual implementation of ConnectivityProvider

package com.detectnetworkchange.connectivity

import android.net.ConnectivityManager
import android.net.ConnectivityManager.NetworkCallback
import android.net.Network
import android.net.NetworkCapabilities
import android.os.Build
import androidx.annotation.RequiresApi
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState.ConnectedState.Connected
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState.NotConnectedState
import com.detectnetworkchange.connectivity.base.ConnectivityProviderBaseImpl

@RequiresApi(Build.VERSION_CODES.N)
class ConnectivityProviderImpl(private val cm: ConnectivityManager) :
        ConnectivityProviderBaseImpl() {

    private val networkCallback = ConnectivityCallback()

    override fun subscribeListener() {
        cm.registerDefaultNetworkCallback(networkCallback)
    }

    override fun getNetworkState(): NetworkState {
        val capabilities = cm.getNetworkCapabilities(cm.activeNetwork)
        return if (capabilities != null) {
            Connected(capabilities)
        } else {
            NotConnectedState
        }
    }

    private inner class ConnectivityCallback : NetworkCallback() {

        override fun onCapabilitiesChanged(network: Network, capabilities: NetworkCapabilities) {
            dispatchChange(Connected(capabilities))
        }

        override fun onLost(network: Network) {
            dispatchChange(NotConnectedState)
        }
    }
}
package com.detectnetworkchange.connectivity

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.ConnectivityManager
import android.net.ConnectivityManager.CONNECTIVITY_ACTION
import android.net.ConnectivityManager.EXTRA_NETWORK_INFO
import android.net.NetworkInfo
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState.ConnectedState.ConnectedLegacy
import com.detectnetworkchange.connectivity.base.ConnectivityProvider.NetworkState.NotConnectedState
import com.detectnetworkchange.connectivity.base.ConnectivityProviderBaseImpl

@Suppress("DEPRECATION")
class ConnectivityProviderLegacyImpl(
        private val context: Context,
        private val cm: ConnectivityManager
) : ConnectivityProviderBaseImpl() {

    private val receiver = ConnectivityReceiver()

    override fun subscribeListener() {
        context.registerReceiver(receiver, IntentFilter(CONNECTIVITY_ACTION))
    }

    override fun getNetworkState(): NetworkState {
        val activeNetworkInfo = cm.activeNetworkInfo
        return if (activeNetworkInfo != null) {
            ConnectedLegacy(activeNetworkInfo)
        } else {
            NotConnectedState
        }
    }

    private inner class ConnectivityReceiver : BroadcastReceiver() {
        override fun onReceive(c: Context, intent: Intent) {
            // on some devices ConnectivityManager.getActiveNetworkInfo() does not provide the correct network state
            val networkInfo = cm.activeNetworkInfo
            val fallbackNetworkInfo: NetworkInfo? = intent.getParcelableExtra(EXTRA_NETWORK_INFO)
            // a set of dirty workarounds
            val state: NetworkState =
                    if (networkInfo?.isConnectedOrConnecting == true) {
                        ConnectedLegacy(networkInfo)
                    } else if (networkInfo != null && fallbackNetworkInfo != null &&
                            networkInfo.isConnectedOrConnecting != fallbackNetworkInfo.isConnectedOrConnecting
                    ) {
                        ConnectedLegacy(fallbackNetworkInfo)
                    } else {
                        val state = networkInfo ?: fallbackNetworkInfo
                        if (state != null) ConnectedLegacy(state) else NotConnectedState
                    }
            dispatchChange(state)
        }
    }
}

Let’s create a NetWorkManger class

In this class we have one live data object which hold the internet state, It can be accessible threw out the application.

package com.detectnetworkchange

import androidx.lifecycle.MutableLiveData


const val DISCONNECTED = 0
const val CONNECTED = 1

object NetWorkManger {
    val networkStatus = MutableLiveData<Int>()

    fun isDisconnected(): Boolean {
        return networkStatus.value == DISCONNECTED
    }
}

class NetWorkDisconnectedException : Throwable()

Finally subscribe the ConnectivityProvider instance in application class

package com.detectnetworkchange

import android.app.ActivityManager
import android.app.Application
import android.content.Context
import android.os.Build
import android.os.Process
import com.detectnetworkchange.connectivity.base.ConnectivityProvider

class DetectNetworkChangeDemoApp : Application() {
    override fun onCreate() {
        super.onCreate()
        if (isMainProcess()) {
            ConnectivityProvider.createProvider(this).subscribe()
        }
    }

    // your package name is the same with your main process name
    private fun isMainProcess(): Boolean {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            packageName == getProcessName()
        } else packageName == getProcessNameLegacy()
    }

    // you can use this method to get current process name, you will get
    private fun getProcessNameLegacy(): String? {
        val mypid = Process.myPid()
        val manager =
            getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        val infos = manager.runningAppProcesses
        for (info in infos) {
            if (info.pid == mypid) {
                return info.processName
            }
        }
        // may never return null
        return null
    }
}

This way you can observe network changes

package com.detectnetworkchange

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Suppose you want to check network status before calling APIs then use this way
        Log.d("MainActivity","Network connected "+!NetWorkManger.isDisconnected())
        // if you want observe network status then use this way
        NetWorkManger.networkStatus.observe(this, Observer {
            when (it) {
                CONNECTED -> status.text ="Internet is connected"
                DISCONNECTED -> status.text ="Internet disconnected"
            }
        })


    }
}

In this blog, we’ll learn FOR loop in kotlin Adnroid, will see the exact flow of for loop. How it will work, Will understand the working of FOR loop in detail with the help of an example. So let’s started

FOR LOOP SYNTAX

FOR loop the syntax is for followed by space, bracket open and close. Inside this I simply used the variable of i followed by in operator and defined the range.

for loop syntax
for (initializer in ranges) {
   // put your code here
}
Lets take a simple example
fun main(args: Array<String>) {
    // For loop
    for (i in 1..20) {
        println(i)
    }
}

FOR loop example

Let take a very basic example of FOR loop, Open the IDE and paste below code

fun main(args: Array<String>) {
    for (i in 1..3) {
        println("hi..")
    }
}

Now let us run the code, and see the output on the console

hi..
hi..
hi..
Process finished with exit code 0

So here we simply show that println() method has been executed three times. That is loop 1, loop 2 and loop3  has been executed. After the loop 3, loops actually terminated.

What is the exact flow of FOR loop.

For understanding the exact flow, let take an example, see below code

1 Iteration

In the first iteration( loop 1) the value of i is actually 1 (i=0)and next step comes to the condition check so 1 falls inside the 1 to 3 range. So the condition becomes true then we simply ‘print hi’, and finally at end of the loop simply increment the value of i by 1, So now value of i becomes 2 (i=2).

2 Iteration

Now value i=2 comes the vary initial point of 2 iterations. In the case in second iteration again we have to condition check 2 actually falls inside the range 1 to 3 range, and the condition become true again and again we ‘print hi’, at end of iteration simply increment the value of I and i become 3 (i=3)

for-loop-second-loop

Now, i=3 again come the initial value of loop 3, or you can say starting point of 3 loop. And gain condition becomes true. Because this 3 is actually present inside the 1 to 3 range right. 

So again we’ll print hello. And finally value of i becomes 4 (i=4). Now at the end of loop 3 when the value of i becomes 4, This will try to initiate 4 loop. Which will never happen, Because i=4 simply make the condition as false. The 4 does not lie inside the range. So finally the loop terminates right.

Overview of FOR loop

Finally, the the complete overview looks like below figure.

How for loop work in kotlin

FOR loop example

Let’s take another example for better understanding. Now suppose I ask to write a program using FOR loop print out all the even numbers starting from 1 to 20. For doing that I simply write if else condition. Such as below

fun main(args: Array<String>) {
    // For loop
    for (i in 1..20) {
        if (i % 2 == 0)
            println(i)
    }
}

So let us now run  the code. So here we go 2,4,6,8…,20. So we prints all event number using this for loop example.

2
4
..
..
18
20
Process finished with exit code 0

Conclusion

In this post, we have learned How does FOR loop works in the case of Kotlin. Thank for reading, Have a Good Day       

in this post, we’ll learn when as expression, Now this when is actually the replacement of switch case statement similar to java, So let us explore when expression in Kotlin

fun main(args: Array<String>) {
    val x = 2
}

Let the above code block, here we simply define one variable is x and it is final.

WHEN statement

Now instated of writing switch case statement that we used to in case of java, Here we have the when expression. Let us write code 

Let say the value of x is equal to 1, then simply put dash followed by arrow than simply write the code.  Similarly the value of x is equal to 2 then execute line of code. 

fun main(args: Array<String>) {
    val x = 2
    when (x) {
        1 -> print("x is 1")
        2 -> print("x is 2")
    }
}

Now let us run the code, so we get the output as “x is 2”. Now here notice we don’t have to write any break statement or the continue statement.

Default Statement

Now similar to java we also have a default statement in case of when clause. The default statement in the case of when actually represented with help of else. So we need to write else part here. Now again syntax is a dash followed by an arrow (->).

fun main(args: Array<String>) {
    val x = 7
    when (x) {
        1 -> print("x is 1")
        2 -> print("x is 2")
        else -> {
            print("x value is unknown")
        }
    }
}

Now let us change the x value is 7 and run the code then we get 

x value is unknown
Process finished with exit code 0

Just because value is 7 and we have written code just for 1 & 2, not for 7 that is why the else part is executed.

Multiple conditions in one statement

Now we can have also multiple conditions inside the statement. Means, In this block we can write multiple conditions Like below. 

Now suppose x value is 0, and you want to execute multiple condition in just one statement, what you can do is, you can do  simply use 0,5 ->

fun main(args: Array<String>) {
    val x = 5
    when (x) {
        1, 5 -> print("x is 1 or 5")
        2 -> print("x is 2")
        else -> {
            print("x value is unknown")
        }
    }
}

In this example you define like 1,2,4, in is single line statement. Now lets run the code in output console you have like below

x is 1 or 5
Process finished with exit code 0

Range uses when expression

Apart from this, we can also use range in case of value here. Let’s say x is equal to 12 right. Now suppose here I’m used range 1..15. How we do that

 fun main(args: Array<String>) {
    val x = 12
    when (x) {
        in 1..15 -> print("x is 1 or 5")
        2 -> print("x is 2")
        else -> {
            print("x value is unknown")
        }
    }
}

So this 1..15 is contains value 1 to 15, which also include value 12 as well , So this condition simply return true

Operator with Range

In the same way we can also use not(!) operator here, Just put this operator like below

fun main(args: Array<String>) {
    val x = 13
    when (x) {
        !in 1..15 -> print("x is 1 or 5")
        2 -> print("x is 2")
        else -> {
            print("x value is unknown")
        }
    }
}

In this block, when conditions become false here then compilers look for simple matches here. And again it won’t find the match then by default it will execute the else part here

Now let us run the code and see on console, Output will be like below . 

x value is unknown
Process finished with exit code 0
 

WHEN as Expression

Suppose if I define a variable, let say var result:String, Now let us change this when statement as expression, In this case simply we assign result wich when statement using the equal sign. 

fun main(args: Array<String>) {
    val x = 1
    val result = when (x) {
        1 -> "x is 1"
        2 -> "x is 2"
        else -> {
            "x value is unknown"
        }
    }
    print(result)
}

Now here, what is happening here when the condition is actually matched then it will simply return the match value. And this value will assign to result variable.

Multiple statement in a block

Now suppose If I will write two statements inside one block. In this situation what will happen because we have two string expressions inside the else block. Lets us run the code and see

fun main(args: Array<String>) {
    val x = 5
    val result = when (x) {
        1 -> "x is 1"
        2 -> "x is 2"
        else -> {
            "x value is unknown"
            "x is a magic number"
        }
    }
    print(result)
}

The output is

x is a magic number
Process finished with exit code 0

As you see we are getting a second expression. What happened is that whatever statement we have inside the code at the end, that actually returns. We saw the last expression is actually executed.

So always remember this, whatever you write the end of the code block it actually return.

Conclusion

This is all about when expression, here the when statement actually acting expression and returning some value, In Kotlin, forgot about switch statement and simply adapt to when expression. Thank for reading, Have a Good Day       

In this post, we’ll learn If else conditional statement in Kotlin. We’ll cover each small topic, that has related to IF-ELSE. will see If expression and if multiple conditions with the help of an example. So lets started

If else conditional Statement

Let’s see the below here we simply define two values. Now down the side, I want to get max value using if condition in Kotlin

fun main(args: Array<String>) {
    val a = 10
    val b = 15

    var result: Int
    if (a > b) {
        result = a
    } else {
        result = b
    }
    print("Greater value is $result")
}

Above expression, we simply wrote a code for get a max value. So let us run the code and see, here we find simply 15, So we had simply written code to find the maximum value of these two number .

Output is

 Greater value is 15
 Process finished with exit code 0

IF as Expression

The conditional statement is very similar to java. But in Kotlin we have If expression. What mean of that? We can use if condition as expression. How to do that let’s see  

fun main(args: Array<String>) {
    val a = 10
    val b = 15

    val result = if (a > b) {
        a
    } else {
        b
    }
    print("Greater value is $result")
}

As you see our code is more cleaner, So here what I’m doing is, this is the if as an expression. Now simply if a is greater than b then assign a to the result variable else assign b.

Means which is a maximum value that will be assigned to the result variable. In the end, simply print the result variables. Let us run the code the output will we same. So in Kotlin we can make if condition to the return some value, that called IF as Expression

Multiple if statements

Suppose I have multiple lines of code inside the if condition so which value will be return? and which will store in the result variable.

   fun main(args: Array<String>) {
    val a = 10
    val b = 15

    val result = if (a > b) {
        print("A is greater")
        a
    } else {
        print("B is greater")
        b
    }
    print("Greater value is $result")
}

Let see above code here I’m adding a block of code inside the if condition. In this condition where we have multiple lines of code with in the IF block also else block. So which of the following will be return 

 Now as per the rule, The last statement that is define inside the if condition will be returned.In this example last statement is a and b

Conclusion

So in this way we are actually using the if-else condition as an expression now this if the condition is returning some value. So that us why we calling IF expression

Read our new article switch statement in Kotlin

In this post, I’ll show you how we can write double tap listener in android. For doing that I’ll create one demo project and will implement it. So Lets started

Write a DoubleClickListener

Create an abstract class named is DoubleClickListener which extends native View.OnClickListener. Technically nothing we are doing. Simply observe the normal click If the second click happens with delta time then we triggered onDoubleClick event. Just like below

package com.doubletaplistener

import android.view.View

abstract class DoubleClickListener : View.OnClickListener {
    private var lastClickTime: Long = 0
    override fun onClick(v: View) {
        val clickTime = System.currentTimeMillis()
        if (clickTime - lastClickTime < DOUBLE_CLICK_TIME_DELTA) {
            onDoubleClick(v)
            lastClickTime = 0
        }
        lastClickTime = clickTime
    }

    abstract fun onDoubleClick(v: View)

    companion object {
        private const val DOUBLE_CLICK_TIME_DELTA: Long = 300 //milliseconds
    }
}

Lets come to the implementation

For implementation double tap listener just create an android sample project. You can apply double click listener is anywhere. In this demo, I’m taking one button. On this button, I will set double click listener, for verifying this I’ll show the toast.

package com.doubletaplistener

import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

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

        // handle double tap event
        doubleTap.setOnClickListener(object : DoubleClickListener() {
            override fun onDoubleClick(v: View) {
               Toast.makeText(applicationContext,"Double Clicked Attempts",Toast.LENGTH_SHORT).show()
            }
        })
    }
}

Conclusion

In this android app Example, I show you Double Tap Listener Android Example. I hope it’s helpful for you, then help me by sharing this post with all your friends who learning android app development.

Read our new article on Kotlin String Template

In this post, we’ll learn about string templates and in other words what is String Interpolation. in Kotlin we have a special type of concept String Interpolation. In this article, we’ll discuss in detail with example.

Let us start with some example, I’m going to define one variable and appends it with title val

        val website = "Android"
        val title = website + "Developer Blog"
        print(title)

Let print the title value, the output is as expected

Output -  AndroidDeveloper Blog

In Kotlin, we have a concept of String Interpolation, so no longer to use the + keyword or the String concatenation. Now, what is the String Interpolation? let change above statement with String Interpolation.

        // define some variables
        val website = "Android"
        val title = "$website Developer Blog"
        print(title)

Here we removed + sign and used $ keyword followed by the name. So Java compiler what it will do, It will simply evaluate name and then print it with other string.

The output will be the same, so let’s run the code here the output we get Android Developer Blog as expected.

So let’s take some more example, create an android project
        // define some variables
        val title = "Android"
        val name = "$title Developer Blog"

        textView.text = "The full statement is $name"
Now I want to add a number of characters in name value.
        // define some variables
        val title = "Android"
        val name = "$title Developer Blog"

        textView.text = "The full name is $name The length of name is ${name.length}"
Let’s take some numeric value example
        val a = 22
        val b = 23
        textView.text = "The sum of $a & $b => ${a + b}"
Output is - The sum of 22 & 23 => 45
Deal with class
   {     // create a object on rect
        val rect = Rect()
        print("The Rect width is ${rect.width} and height is ${rect.height} ")
    }

    class Rect {
        var width = 12
        var height = 14
    }
Conclusion

In this post, we learned string templates and concepts String Interpolation. This is the beauty of Kotlin, In the one statement, you can manage everything. That why we say Kotlin is more powerful then java and it is more expressive and concise.

Why we used Kotlin for Android Development

In this article, I’ll show how we can send an FCM message from an android device. in other words, you can say, will tell send android firebase push notifications device to device. How to do that, Let’s get started.

Create a new application.

Let’s open the Android Studio and create a new project with the default template.

Add libraries in app-level build.gradle file

In this example, we are using followings libraries for making network call

  //  Add these line in your project
  implementation 'com.squareup.retrofit2:retrofit:2.7.1'
  implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
  implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.1'
  implementation "com.squareup.okhttp3:logging-interceptor:4.3.1"
Add Base URL and FCM SERVER KEY in build config field your project build.gradle

Let add below variables inside gradle file. Now create a project on firebase. After that Replace FCM_SERVER_KEY ID with your server id.

buildTypes {
    debug {
      buildConfigField("String", "FCM_BASE_URL", "\"https://fcm.googleapis.com/\"")
      buildConfigField("String", "FCM_SERVER_KEY", "\"xxxxxxxxxxxxxxxxxxxxxxxx\"")
    }
    release {
      minifyEnabled false
      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
  }
Add Internet permission manifest

For sending the notification, we will need to internet permission, let’s open the android manifest and add below permission.

  <uses-permission android:name="android.permission.INTERNET" />
Write a network API client

Let’s create a network provider class, In this class, we are using Retrofit and OKHHTP client for debugging.

package com.sendinganotificationmessage;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class ApiClient {
  public static NotificationApiService getApiService() {
    return new Retrofit.Builder()
        .baseUrl(BuildConfig.FCM_BASE_URL)
        .client(provideClient())
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(NotificationApiService.class);
  }

  private static OkHttpClient provideClient() {
    HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
    interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    return new OkHttpClient.Builder().addInterceptor(interceptor).addInterceptor(chain -> {
      Request request = chain.request();
      return chain.proceed(request);
    }).build();
  }
}
Now create notification API service
package com.sendinganotificationmessage;

import com.google.gson.JsonObject;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Headers;
import retrofit2.http.POST;

public interface NotificationApiService {

  @Headers({
      "Authorization: key="+BuildConfig.FCM_SERVER_KEY ,
      "Content-Type: application/json"
  })
  @POST("fcm/send")
  Call<JsonObject> sendNotification(@Body JsonObject payload);
}
Modify your main activity layout file

For taking input from the user will update the layout file that contains a few text input item for capturing device token, title and message

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainActivity"
    >

  <com.google.android.material.textfield.TextInputLayout
      android:id="@+id/textInputLayout5"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginTop="16dp"
      android:layout_marginEnd="16dp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      >

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/textReceiverToken"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Receiver FCM Token"
        android:maxLines="1"
        android:text="fnn3DoqhPPM:APA91bHBDfHv0YC5Mpncu1Got_d28-FIRDEH1gwXj27HGB5_Qbn49cyE7M2zeKijq4FEuApsW6-lEbNGrIGwhhERKTTtGxLvz8Q5xvF_x1QlX3Um8DiKsnYjqeEMySrjAhQNeI8Kot7S"

        />
  </com.google.android.material.textfield.TextInputLayout>
  <com.google.android.material.textfield.TextInputLayout
      android:id="@+id/textInputLayout"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginTop="8dp"
      android:layout_marginEnd="16dp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textInputLayout5"
      >

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/textTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Title"
        />
  </com.google.android.material.textfield.TextInputLayout>
  <com.google.android.material.textfield.TextInputLayout
      android:id="@+id/textInputLayout2"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginTop="8dp"
      android:layout_marginEnd="16dp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textInputLayout"
      >

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/textMessage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Message"/>
  </com.google.android.material.textfield.TextInputLayout>
  <TextView
      android:id="@+id/textView"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginTop="16dp"
      android:text="Additional data you want to pass (In key-value pair)"
      android:textColor="@color/colorAccent"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textInputLayout2"
      />
  <com.google.android.material.textfield.TextInputLayout
      android:id="@+id/textInputLayout3"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginTop="16dp"
      app:layout_constraintEnd_toStartOf="@+id/textInputLayout4"
      app:layout_constraintHorizontal_bias="0.5"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textView"
      >

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/textKey"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Key"
        />
  </com.google.android.material.textfield.TextInputLayout>
  <com.google.android.material.textfield.TextInputLayout
      android:id="@+id/textInputLayout4"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginEnd="16dp"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintHorizontal_bias="0.5"
      app:layout_constraintStart_toEndOf="@+id/textInputLayout3"
      app:layout_constraintTop_toTopOf="@+id/textInputLayout3"
      >

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/textValue"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Value"
        />
  </com.google.android.material.textfield.TextInputLayout>
  <Button
      android:id="@+id/buttonSendNotification"
      android:layout_width="0dp"
      android:layout_height="wrap_content"
      android:layout_marginStart="16dp"
      android:layout_marginTop="24dp"
      android:layout_marginEnd="16dp"
      android:background="@color/colorAccent"
      android:text="Send Notification"
      android:textColor="#ffffff"
      app:layout_constraintEnd_toEndOf="parent"
      app:layout_constraintStart_toStartOf="parent"
      app:layout_constraintTop_toBottomOf="@+id/textInputLayout3"
      />


</androidx.constraintlayout.widget.ConstraintLayout>
Let’s move to main activity files

Let’s bind the views using id. As you see below code we taking the input from users and send notification using the retrofit client. We taking input like title, messaging and FCM token.

package com.sendinganotificationmessage;

import android.os.Bundle;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.textfield.TextInputEditText;
import com.google.gson.JsonObject;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class MainActivity extends AppCompatActivity {
  Button sendNotificationButton;
  TextInputEditText receiverFdmId;
  TextInputEditText title;
  TextInputEditText message;
  TextInputEditText key;
  TextInputEditText value;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initViews();
    sendNotificationButton.setOnClickListener(view -> {
      if (validateInput()) {
        JsonObject payload = buildNotificationPayload();
        // send notification to receiver ID
        ApiClient.getApiService().sendNotification(payload).enqueue(
            new Callback<JsonObject>() {
              @Override
              public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
                if (response.isSuccessful()) {
                  Toast.makeText(MainActivity.this, "Notification send successful",
                      Toast.LENGTH_LONG).show();
                }
              }

              @Override public void onFailure(Call<JsonObject> call, Throwable t) {

              }
            });
      }
    });
  }

  private JsonObject buildNotificationPayload() {
    // compose notification json payload
    JsonObject payload = new JsonObject();
    payload.addProperty("to", receiverFdmId.getText().toString());

    // compose data payload here
    JsonObject data = new JsonObject();
    data.addProperty("title", title.getText().toString());
    data.addProperty("message", message.getText().toString());
    data.addProperty(key.getText().toString(), value.getText().toString());
    // add data payload
    payload.add("data", data);
    return payload;
  }

  private boolean validateInput() {
    if (receiverFdmId.getText().toString().isEmpty()
        || title.getText().toString().isEmpty()
        || message.getText().toString().isEmpty()
        || key.getText().toString().isEmpty()
        || value.getText().toString().isEmpty()) {
      Toast.makeText(this, "Please fill all field correctly", Toast.LENGTH_LONG).show();
      return false;
    }
    return true;
  }

  private void initViews() {
    sendNotificationButton = findViewById(R.id.buttonSendNotification);
    receiverFdmId = findViewById(R.id.textReceiverToken);
    title = findViewById(R.id.textTitle);
    message = findViewById(R.id.textMessage);
    key = findViewById(R.id.textKey);
    value = findViewById(R.id.textValue);
  }
}

Let’s run the project and see your app will run and up. Lets put device token, title and message, finally tap on send.

Conclusion

In this android app tutorial, We have learned the implementation of sending FCM message from android. I hope it’s helpful for you, let’s do a favor for me, share this post with all your friends.

Get Solution Code

Keep in touch

If you want to keep in touch so let’s follow me on Facebook or Subscribe to us. Still, if you have any queries please put your comment below.