Android AsyncTask API deprecating in Android 11. Here is another way? in JAVA (java.util.concurrent)

Android AsyncTask API deprecating in Android 11. Here is another way? in JAVA



Google is deprecating Android AsyncTask API in Android 11 and suggesting to use java.util.concurrent instead. If you’re maintaining an older codebase with asynchronous tasks in Android, you’re likely going to have to change it in future. Concurrency is widely regarded as one of the most difficult challenges among all fields of computation.

If you are still wondering how it works under the hood then I suggest that as a learning goal, but we will not be going that low level today. Instead we will look at a practical way to write concurrent code which gives us more control than AsyncTask, but requires orders of magnitude less configuration (barely any at all) than a very expansive library like RxJava. It also requires no 3rd party libraries

Alternative of AsyncTask

The officially recommended alternative is Kotlin Coroutines, that you must use of writing Asynchronous Code in your project. But if you are a beginner and you just started learning android development then jumping directly into Kotlin Coroutine is not recommended. So in this post I will show you something that do not requires any dependency.

Using Executors

We have java.util.concurrent; that we can use in place of AsyncTask if you do not wish to use Kotlin Coroutines.

Here is an example how you can use it.

activity_test.xml

<?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=".TestActivity">

<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" />
</com.google.android.material.appbar.AppBarLayout>

<TextView
android:id="@+id/textview_executors_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
android:text="Executors Count"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appBarLayout" />

<TextView
android:id="@+id/textview_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textview_executors_count" />

<androidx.appcompat.widget.SwitchCompat
android:id="@+id/switch_test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
android:text="Just to test Main UI working "
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textview_result" />

<Button
android:id="@+id/button_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
android:text="Start"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/switch_test" />

<Button
android:id="@+id/button_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="100dp"
android:enabled="false"
android:text="Stop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button_start" />

</androidx.constraintlayout.widget.ConstraintLayout>

TestActivity.java

package com.bignotify.testthreadexecutor;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.bignotify.testthreadexecutor.databinding.ActivityTestBinding;

public class TestActivity extends AppCompatActivity {
private static final String TAG = "TestActivity";
private volatile boolean stopExecutor = false;
private int executorCount = 0;
private ActivityTestBinding binding;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

binding = ActivityTestBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

setSupportActionBar(binding.toolbar);

binding.buttonStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
binding.buttonStop.setEnabled(true);
stopExecutor = false;
ExampleRunnable runnable = new ExampleRunnable(10);
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorCount++;
executorService.execute(runnable);
}
});

binding.buttonStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopExecutor = true;
}
});
}

class ExampleRunnable implements Runnable {
int seconds;

ExampleRunnable(int seconds) {
this.seconds = seconds;
}

@Override
public void run() {
for (int i = 0; i < seconds; i++) {
if (stopExecutor) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
executorCount--;
binding.buttonStop.setEnabled(false);
binding.textviewResult.setText("Stopped Executor");
}
});
return;
}

Log.d(TAG, "run: " + i);
if (stopExecutor) return;

try {
Thread.sleep((1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
int finalI = i;

// Do something on UI
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
binding.textviewExecutorsCount.setText("Executors Count : " + executorCount);
binding.textviewResult.setText("Seconds : " + finalI);
}
});
}

// Handles post excecution
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
executorCount--;
binding.textviewExecutorsCount.setText("Executors Count : " + executorCount);
if (executorCount == 0)
binding.textviewResult.setText("Finished Executor");
}
});
}
}
}

It is pretty much the same thing that you do using AsyncTask


Author:
Rajneesh Vishwakarma

Comments