Monday 21 February 2022

AsyncTask Alternative using Executor & Handler

Adding a sample to demonstrate how to create AsyncTask replacement with Executor & Handler.

AsyncTask is deprecated and it is suggested to use Kotlin coroutines instead.

https://developer.android.com/reference/android/os/AsyncTask


The other alternative is suggested to use Executor and Handler which is kind of same as using AsyncTask and should be avoided but in case somebody want to use it they can implement it like below.

Executor executor = Executors.newSingleThreadExecutor(); 
Handler handler = new Handler(Looper.getMainLooper());

//Run any main thread task like launching progress bar
...
executor.execute(() -> {
        //Do some background operation here(e.g fetching data from server etc)     
        ...
        handler.post(() -> {
         //Do some main thread operation like stopping progress bar or updating UI with fecthed data 
         ...
        });
    }); 

I have implemented little bit generic way to do the above operation and instead of writing Executors and Handler everytime we can use the below class and also we can specify the response type of doInBackground.

public class CustomAsyncTask<ResponseType> {
    private final AsyncTaskCallback<ResponseType> asyncTaskCallback;
    private final ExecutorService executor;
    private final Handler handler;

    interface AsyncTaskCallback<ResponseType> {
        //Call it before executing background task
        void onPreExecute();

        //Execute background thread and call the below method
        ResponseType doInBackground();

        //Once the background thread finishes call this method on main thread
        void onPostExecute(ResponseType result);
    }

    public CustomAsyncTask(AsyncTaskCallback<ResponseType> asyncTaskCallback) {
        this.asyncTaskCallback = asyncTaskCallback;

        executor = Executors.newSingleThreadExecutor();
        handler = new Handler(Looper.getMainLooper());
    }

    public void execute() {
        //Executing on caller thread(Assuming that user is calling CustomAsyncTask on main thread)
        asyncTaskCallback.onPreExecute();

        executor.execute(() -> {
            //Background work here
            ResponseType res = asyncTaskCallback.doInBackground();

            //Execute on main thread
            handler.post(() -> {
                //UI Thread work here
                asyncTaskCallback.onPostExecute(res);
            });
        });
    }
}

We can call the above class like below, We can specify the return type while initializing class and it will provide type safety for doInBackground result.

new CustomAsyncTask<String>(new CustomAsyncTask.AsyncTaskCallback<String>() {
                @Override
                public void onPreExecute() {
                    
                }

                @Override
                public String doInBackground() {
                    return null;
                }

                @Override
                public void onPostExecute(String result) {

                }
            }).execute();


For more detail please download App source code from below URL:

https://github.com/dipenptl1/asynctask-replacement-java

Thursday 17 February 2022

Android : Contact picker using registerForActivityResult

Adding sample to demonstrate registerForActivityResult use for accessing CONTACT from device contact list.

Previously we were able to pick contact from device contact list using startActivityForResult, but startActivityForResult is deprecated now, instead google suggest to use registerForActivityResult. 

https://developer.android.com/training/basics/intents/result


We can open contact list and retrieve the URI of selected contact using below code.

private val resultLauncher =
    registerForActivityResult(ActivityResultContracts.PickContact()) { uri ->
        uri?.let {
            Log.d(TAG, "Selected contact URI: $uri")
            binding.contactResultTv.text = retrievePhoneNumber(uri)
        }
    }
resultLauncher.launch(null)

We can retrieve actual contact from URI using below function.

@SuppressLint("Range")
private fun retrievePhoneNumber(uri: Uri): String {
    var phoneNumber = String.empty()

    val phone: Cursor? = this.contentResolver?.query(uri, null, null, null, null)
    phone?.let {
        if (it.moveToFirst()) {

            val id = it.getString(it.getColumnIndex(ContactsContract.Contacts._ID))
            val hasNumber =
                (it.getInt(it.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)))

            if (hasNumber > 0) {
                val phoneCursor: Cursor? = this.contentResolver?.query(
                    ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                    null,
                    ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", arrayOf(id),
                    null
                )
                phoneCursor?.let {
                    if (phoneCursor.moveToNext()) {
                        phoneNumber = phoneCursor.getString(
                            phoneCursor.getColumnIndex(
                                ContactsContract.CommonDataKinds.Phone.NUMBER
                            )
                        )
                    }
                    phoneCursor.close()
                }
            }
        }
        it.close()
    }
    return phoneNumber
}



For more detail please download App source code from below URL:

https://github.com/dipenptl1/contact-picker-kotlin