Friday, June 8, 2018

Communication between View and ViewModel

June 08, 2018

Welcome to this post.

In this post, I am going to talk about, how to communicate between view and viewModel.

Let's take a look on ViewModel

ViewModel was introduced on Google I/O 17, a part of Lifecycle extensions. Now it's released version is 1.1.0.
lifecycle
Src: Medium

From the picture, you can see that it launch with the creation of activity. And it will be cleared only when the activity is finished. The biggest advantage is that it can survive configuration changes.
You should not put any view reference in the viewModel. Why?
The answer is so simple When activity recreated the also. So if you pass view to ViewModel then it creates a leak, because, on the recreation of activity, all the views are brand new, but your ViewModel is still holding the older view that already destroyed.
Don't do this.

Now a question, so how to communicate between view and ViewModel?

Case Study:
Imagine you build an app that has an option for the user signup. When the user clicks signup button then
you can show a dialog and after successful signup, we have to show a notification or perform any task. In this case how you contact view and ViewModel.

Let's start-
To solve this problem I create a class that inherited Mutable Live Data Class.
class SingleLiveEvent<T> : MutableLiveData<T>() {

    private val pending = AtomicBoolean(false)

    @MainThread
    override fun observe(owner: LifecycleOwner, observer: Observer<T>) {

        if (hasActiveObservers()) {
            //Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
        }

        // Observe the internal MutableLiveData
        super.observe(owner, Observer<T> { t ->
            if (pending.compareAndSet(true, false)) {
                observer.onChanged(t)
            }
        })
    }

    @MainThread
    override fun setValue(t: T?) {
        pending.set(true)
        super.setValue(t)
    }

    /**
     * Used for cases where T is Void, to make calls cleaner.
     */
    @MainThread
    fun call() {
        value = null
    }

    companion object {
        private const val TAG = "SingleLiveEvent"
    }
}

This is the sample from google, it is the blueprint of architecture component. Check this.
But If you want to set a value from the main thread then it's ok. you can use this without changing anything.

But what about the background thread?
If you want to set a value from a background thread, then you have to override postValue() method.
override fun postValue(value: T) {
    pending.set(true)
    super.postValue(value)
}
If you have any confuse, then check GitHub

Create a status class
enum class Status{
    LOGIN,
    SIGNUP,
    FAILED
}

Now come on ViewModel Code:
create an instance of SingleLiveEvent
val observableEvent = SingleLiveEvent<Status>()

I create 3 mock methods, just with a thread that wait for 2 seconds and set the value on the variable, observableEvent.

mockLogin()
just set value from the main thread and start a new background thread.
fun mockLogin(){
    observableEvent.value = Status.LOGIN
    background()
}

mockSignup()
start a thread and wait for 2s and set value. and also start a new background thread.
fun mockSignUp(){
        Thread({
            try {
                Thread.sleep(2000) //2 sec wait
            } catch (e:Exception){
                //nothing
            } finally {
                observableEvent.postValue(Status.SIGNUP)
                //do some task from background
                background()
            }
        }).start()
    }

background()
start a background thread and with the handler and wait for 2s
private fun background(){
        val thread = HandlerThread("Background")
        thread.start()

        Handler(thread.looper).post({

            //wait for 2 sec
            Thread({
                try {
                    Thread.sleep(2000) //2 sec wait
                } catch (e:Exception){
                    //nothing
                } finally {
                    observableEvent.postValue(Status.FAILED)
                }
            }).start()
        })
    }

Now time for activity code:
I have 3 view
  • progress bar
  • login button
  • signup button
First, hide the progress bar
val progressBar:ProgressBar = progressBar
progressBar.gone()
Note, here I use an extension function. see here 

set onclick event for every button and also called the method from ViewModel

Login:
hide progress bar
button.setOnClickListener {
    progressBar.vis()
    viewModel.mockLogin()
}

Sign up:
hide progress bar
button2.setOnClickListener {
    progressBar.vis()
    viewModel.mockSignUp()
}

now observe that event and show toast message. see the code
viewModel.observableEvent.observe(this, Observer {
    if (it == Status.LOGIN){
        progressBar.gone()
        "Login Successful".showToast()
    } else if (it == Status.SIGNUP) {
        progressBar.gone()
        "Sign up Successful".showToast()
    }

    if (it == Status.FAILED){
        "Job Failed from background thread".showToast()
    }
})
here, showToast is another extension function
private fun String.showToast(){
    Toast.makeText(context, this, Toast.LENGTH_SHORT).show()
}

Now run the code and click the button see the toast message.

So, that's it.
you can find this project on GitHub

Thanks for reading.
Hope this tutorial will help you a lot.

Happy coding.

Read More

Monday, October 2, 2017

Android Common Code

October 02, 2017

All the common android code list that used almost every android project.

Here is the list of all code in this post:
  • Support vector drawable
  • PreferenceFragment support
  • Java 8 support
Support vector drawable:
to support vector drawable add below line on the build.gradle file
compile 'com.android.support:support-vector-drawable:26.1.0'
also adds below line on those activities where you use vector drawable.
static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

PreferenceFragment support:
add the following line on the build.gradle file
compile 'com.android.support:preference-v14:26.1.0'
adds also add below line on the style.XML file
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
note: This line is for Material Theme support.

Java 8 support:
to support Java 8 add following line on the build.gradle file
// Keep the following configuration in order to target Java 8.
compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}












Read More

Wednesday, August 30, 2017

How to set sign in anonymously in Firebase

August 30, 2017

welcome to firebase series tutorial.

In this post, we are going learn about how to sign in anonymously in firebase.
But before starting, I am providing you some ideas why we need sign in anonymously?
If you are using real-time database and storage you need to create a rule for access database and storage.
By default the rule is
{


  "rules": {

    ".read": "auth != null",

    ".write": "auth != null"

  }

}
here auth means Authentication. So if your app hasn't any login option you sign in anonymously sign in from your app. So by doing this, that database and storage can be access only from your app. so you can protect your database. Or if you change the rule to access everyone there is a possibility to lose your database. anyone can delete your database with in a single request.

So we sign in anonymously in Firebase from our app to protect database and storage.

Let's start,
you already know how to connect Firebase for your project.
now go to firebase console and select authentication.
click this to go directly Firebase Console.
Now go to sign in method

firebase-auth

and click anonymous and enable it.
firebase-auth1

that's the ending of the configuration of firebase console
now time for coding
Note: I use kotlin as a default language.

add below line to your build.gradle file
implementation 'com.google.firebase:firebase-auth:11.2.0'
Now create an instance of FirebaseAuth class
see the code-
val mAuth = FirebaseAuth.getInstance()
use signInAnonymously() method and add a complete listener. if the task is successful we show a message that Authentication is successful and also user id. if failed then we will show a fail message.
mAuth.signInAnonymously()
     .addOnCompleteListener(this, { task ->
         if (task.isSuccessful) {
                val user = mAuth.currentUser
                Toast.makeText(this, "Authentication successful. user id ${user.uid}",
                                Toast.LENGTH_SHORT).show()

            } else {
                // If the sign in fails displays a message to the user.
                Toast.makeText(this, "Authentication failed.",
                                Toast.LENGTH_SHORT).show()

                    }
                })
That's it coding see the final screen short in the firebase console
firebase-auth android sketchpad
you find some details about your user
1. creation date
2. signed in date
3. user id

That's it from this post hope this will help you to understand this concept.
and you will implement anonymous login option for your app and make a better security for your Firebase database and storage.
Happy coding

Read More