Monday 22 August 2022

Advanced Kotlin Coroutines : Introduction

 Hi, 

Today I am unwraping the topic in Kotin world i.e. Coroutine.

If you want to get started with Kotlin coroutine and ease your daily development tasks by using it , then this series is for you. 

In this post , I am starting with introduction , then in future posts we will read more interesting coroutine topics together :) 

So let's get started.

First question which comes in our mind is , 

What is the need of Coroutine?

All the components in an android application , use the same thread of execution i.e. our Main thread.

This main thread is responsible to perform many tasks like drawing the views, executing logical pieces of code in a sequential manner, etc.

So it's developers duty to make sure that main thread must not be blocked. For this reason multi threading comes in picture, with this approach the long or short running tasks which take time should run on a different worker thread to prevent the blocking of main thread and unresponsiveness of the app.

Multithreading in Android has always been a challenge due to it's callback mechanism ,switching between threads and resuming tasks. 

In android multithreading started with Async Task , then RxJava and now we have coroutine to achieve this.

What is Coroutine?

From Kotlin docs:

One can think of a coroutine as a light-weight thread. Like threads, coroutines can run in parallel, wait for each other and communicate. The biggest difference is that coroutines are very cheap, almost free: we can create thousands of them, and pay very little in terms of performance. True threads, on the other hand, are expensive to start and keep around. A thousand threads can be a serious challenge for a modern machine.

A coroutine is a function that can pause its execution to be resumed later. You can think of coroutines as lightweight threads.

Coroutine word is made of two words : co + routine 

Co means cooperate and routine means functions . So we can say coroutine means when functions cooperate, which states : 

  • Coroutines are nothing but lightweight threads. 
  • Coroutines provide us an easy way to do synchronous and asynchronous programming. 
  • Coroutines allow execution to be suspended and resumed later at some point in the future which is best suited for performing non-blocking operations in the case of multithreading.

There are few properties of coroutines

  • They are light-weight
  • Built-in cancellation support
  • Lower chances for memory leaks
  • Jetpack libraries provide coroutines support
It was added to Kotlin in version 1.1. 

Now we understood a little bit about coroutines. 

Also there are some important concepts related to coroutines which will be covered in next posts like :
suspend, Job, Dispatchers, CoroutineScope, CoroutineContext, etc. 


Wednesday 29 April 2020

Accessibility : Adding custom actions

In previous post , the introduction of custom accessibility actions/events was explained . But how it will be implemented ?, will cover it here.

Custom actions help the accessibility users to get all the clicks at one place. It provides a clear picture of the events and actions  of the focused view to the user. Since it is related to events and actions of one view only so all the actions will appear under Local Context Menu .


To understand the implementation , with an example , there is one list view , showing the employee list data , and grouping has already done for each list-view row (Please refer : this post) .

Now here one delete button has also been added, then in this case , there are 2 click listeners exist for each and every list-view row, that are :

  • Employee Details  click
  • Delete click


So here the problem is when the talkback is ON due to grouping of view-group , that delete button will not get focused separately , as it is the child of that view-group (list-view row).
To solve this problem , custom actions can be added. As there are 2 click listeners added , so two custom accessibility actions will be added :
  • Employee Details Action
  • Delete Action
In Adapter class :

setAccessibilityActions(holder.layoutParent)

Function body :
private fun setAccessibilityActions(view : View) {
       ViewCompat.setAccessibilityDelegate(view , object : AccessibilityDelegateCompat() {
           override fun onInitializeAccessibilityNodeInfo(
               host: View,
               info: AccessibilityNodeInfoCompat
           ) {
               super.onInitializeAccessibilityNodeInfo(host, info)
               info.addAction(AccessibilityNodeInfoCompat.AccessibilityActionCompat(R.id.layoutParent,
                   "Employee Details"))
               info.addAction(AccessibilityNodeInfoCompat.AccessibilityActionCompat(R.id.imageView,
                   "Delete"))

           }
           override fun performAccessibilityAction(
               host: View?,
               action: Int,
               args: Bundle?
           ): Boolean {
               super.performAccessibilityAction(host, action, args)
               if (action == R.id.layoutParent) {
                  Toast.makeText(context , "Employee Detail clicked!" , Toast.LENGTH_LONG).show()
               }
               if (action == R.id.imageView) {
                   Toast.makeText(context , "Delete clicked!" , Toast.LENGTH_LONG).show()
               }
               return true
           }
       })
    }

In this , two actions have been added in , onInitializeAccessibilityNodeInfo , which is used to add custom actions/events for the view.

Similarly , performAccessibilityAction , is overridden to perform the action clicks.

Here one thing is noticeable that actions are added in : info. addAction
(AccessibilityNodeInfoCompat.AccessibilityActionCompat(R.id.layoutParent, "Employee Details"))


. In AccessibilityNodeInfoCompat.AccessibilityActionCompat(R.id.layoutParent, "Employee Details") ,


  • The first argument is passed as actionId , which must be unique for each and every action which are added here. On the basis of this actionId , action will perform in performAccessibilityAction
  • In second argument , string is passed, which is the action label , which will appear under local context menu. 
Note : These changes will work only when the accessibility service is enabled. 

Here are the screenshots after adding the custom accessibility actions :








Accessibility : Introduction of custom views

While adding the grouping of views into a view-group , what if there are more than one click-lisnters added on views , how clicks are handled in accessibility grouping?

This can be done with the help of AccessibilityDelegateCompat , which is the part of accessibility api.
This class is helpful for adding the actions and events on any view. Actions will be listed under Local Context Menu and events will announce after the content announcement , like double tap to activate or double tap and hold to long press etc.

For example :

  • If it is required to add anything on double tap when talkback is on , then it will add in event.
  • when it is required to add any custom action like : detail or delete etc. then it will add in actions.
Note
  • All the events for that view will announce after the content announcement
  • All the action will appear under local context menu 
  • All the action names , should covey the exact meaning of that action , not like click here 
As per developer.android.com there are many methods defined , which can be overridden :

 dispatchPopulateAccessibilityEvent : Dispatches an AccessibilityEvent to the host view first and then to its children for adding their text content to the event.

 onInitializeAccessibilityEvent : Initializes an AccessibilityEvent with information about the host view which is the event source.

onInitializeAccessibilityNodeInfo : Initializes an AccessibilityNodeInfoCompat with information about the host view.

onPopulateAccessibilityEvent : Gives a chance to the host View to populate the accessibility event with its text content

onRequestSendAccessibilityEvent : Called when a child of the host view has requested sending an AccessibilityEvent and gives an opportunity to the parent (the host) to add the event.

sendAccessibilityEvent
: Sends an accessibility event of the given type. If accessibility is not enabled this method has no effect.

sendAccessibilityEventUnchecked : Sends an accessibility event. This method behaves exactly as sendAccessibilityEvent(View, int) but takes as an argument an
 empty AccessibilityEvent and does not perform a check whether accessibility is enabled.

getAccessibilityNodeProvider : Gets the provider for managing a virtual view hierarchy rooted at this View and reported to android.accessibilityservice.AccessibilityService
that explore the window content.

performAccessibilityAction : Performs the specified accessibility action on the view.


Tuesday 28 April 2020

Accessibility : Links

If one textview contains many links , that can be handled correctly using local context menu . Local context menu has already been covered in this post 

There are some specific rules , which should follow for links :

  • Links should have appropriate meaningful link text , not "click here"
  • All the links which are present in textview , should be listed in local context menu -> under Links category . 
  • Announcement for opening the local context menu should be correct like : "Links available , Swipe up and right to view"
Here are few screenshots , for the correct behaviour of links with accessibility : 


Correct Announcement of actions to open the list of links 
In this textview , 2 clickable links are added that are : SignUp ! & Sign In here!
So both should be listed under local context menu . 


Local Context Menu


Clickable Links under Local Context Menu


 

Accessibility : RecyclerView with grouping

Grouping in accessibility , means that , to add focus on parent layout , and no child layout will get the focus separately .

Traversing the child elements , one by another ,increases the steps , and also visually -impaired persons may face difficulty to understand the whole view-group , so to reduce these issues , grouping can be done.

RecyclerView , is a good example to understand the grouping scenario.

EmployeeData is showing in RecyclerView , having 3 textviews .When the grouping was not done , talkback will traverse each and every textview , like this :

Recycler View before grouping

  • To add grouping , all the child elements need to set android:importantForAccessibility="no" which will hide the child elements from talkback .
  • And add android:importantForAccessibility="yes" to container layout of  row_item , which will set focus to the container layout (ViewGroup) .
  • Also add appropriate content description to container layout .

<androidx.constraintlayout.widget.ConstraintLayout
    android:importantForAccessibility="yes"
    android:id="@+id/layoutParent">

    <ImageView
        android:id="@+id/image_emp"
        android:importantForAccessibility="no"/>

    <TextView
        android:id="@+id/textEmployeeName"
        android:importantForAccessibility="no"/>

    <TextView
        android:id="@+id/textEmployeeId"
        android:importantForAccessibility="no"
       />

    <TextView
        android:id="@+id/textJoining"
        android:importantForAccessibility="no"
        />
</androidx.constraintlayout.widget.ConstraintLayout>

And in adapter class :

textEmployeeName.text = "Employee Name : ${employee.empName}"
textEmployeeId.text = "Employee ID: ${employee.empId}"
textJoining.text = "Joining Date:  ${employee.empJoiningDate }"

layoutParent.contentDescription = textEmployeeName.text.toString()+" " +
                    textEmployeeId.text.toString()+" "+
                    textJoining.text.toString()+" "

Here in adapter class all the 3 textviews' text have been appended and set content description of  layoutParent  , which will look like this :


RecyclerView after grouping





Accessibility : Checkbox

Same as switches , checkbox should also covey all the information once get focused :

As per accessibility guidelines , checkbox should announce its State, its title , and action .

For Example  :

There are 2 example , 1 is incorrect accessibility  behaviour  and another one is correct accessibility behaviour :

Incorrect checkbox accessibility behaviour :

Incorrect checkbox accessibility behaviour 

Incorrect checkbox accessibility behaviour 


Correct checkbox accessibility behaviour :
Correct checkbox accessibility behaviour


























  • Checkbox with Grouping :

For grouping of checkboxes , each and every checkbox of that group should convey the information of it's group title as well , like : 
<Group_name> 
     < check_box1 />
     < check_box2 />  
</Group_name>

So check_box1 will announce like :  <State>  <Check box title +  Group title>  <Action>


For Example :

 <TextView
        android:id="@+id/textView"
        android:text="Preferred technical skills"/>

    <CheckBox
        android:id="@+id/check1"
        android:text="Java"
        android:contentDescription="Java , Preferred technical skills" />

    <CheckBox
        android:id="@+id/check2"
        android:text="Android"
        android:contentDescription="Android , Preferred technical skills" />

    <CheckBox
        android:id="@+id/check3"
        android:text="React Native"
        android:contentDescription="React Native , Preferred technical skills" 



 






Accessibility : Switches

As per the accessibility guidelines  , switches should implement with text , and with talkback it would get focused and announced altogether .

For Example :

 <Switch
        android:id="@+id/switch1"
        android:text="Switch with text"/>

    <LinearLayout
        android:orientation="horizontal">

        <TextView
            android:id="@+id/textView"
            android:text="Switch Without Text"/>
        <Switch
            android:id="@+id/switch2"/>

    </LinearLayout>

Screenshots :

Below is incorrect behaviour as per accessibility guidelines :

   
Incorrect
Incorrect 



Below example is correct behaviour as per accessibility guidelines :

Correct


Advanced Kotlin Coroutines : Introduction

 Hi,  Today I am unwraping the topic in Kotin world i.e. Coroutine . If you want to get started with Kotlin coroutine and ease your daily de...