The Application May Be Doing Too Much Work on Its Main Thread

How to fix The application may be doing too much work on its main thread in Android?

While performing long running or computation heavy tasks, you should prefer doing it on a background thread (i.e, separate from the UI thread).

You will see ANRs on the app if the UI thread is kept busy for more than 5 seconds, but even for less than 5 seconds there will be a noticeable lag and delay of user actions (click, scroll) and a similar message in logs as you are seeing (Choreographer : Skipped XXX frames! The application may be doing too much work on its main thread.).

Some of the ways to such perform tasks on background thread are :

  • AsyncTask
  • TimerTask
  • Java Thread / Android HandlerThread
  • IntentService

Also, be careful while updating the UI from a background thread as Android UI toolkit is not thread-safe.


Edit :

For off-loading tasks from main thread, you can also use :

  • Kotlin Coroutines
  • RxJava

Skipped x frames! The application may be doing too much work on its main thread. What does this error signify and how to solve this?

If you are not doing anything unnecessary in your main, you can just ignore it.

the number of skipped frames is dependent on:

  • The number of static and top-level variables that need initiation on startup.

  • Speed of the CPU that will be doing computational work, like parsing JSONs at startup.

  • Speed of the device storage for initiating databases and shared preferences.

  • Whether you're using a debug or release build of your app.

  • The speed of the network connection in case of needing some necessary data before the app starts up.

  • Whether you're using an emulator or a physical device.

  • The size of the widget tree in your home page.

Choreographer: Skipped frames : The application may be doing too much work on its main thread

If I'm not mistaken, at least once your ServerAuthenticateService's getClassTeacherList method is called on the main (UI) thread when the onCheckedChange callback is invoked. You should instead move the web API call to another thread, so that the main thread isn't "frozen" waiting for the result of the web API call.

From https://developer.android.com/guide/components/processes-and-threads :

... if everything is happening in the UI thread, performing long operations such as network access or database queries will block the whole UI. When the thread is blocked, no events can be dispatched, including drawing events. From the user's perspective, the application appears to hang. Even worse, if the UI thread is blocked for more than a few seconds (about 5 seconds currently) the user is presented with the infamous "application not responding" (ANR) dialog. The user might then decide to quit your application and uninstall it if they are unhappy.

EDIT: also the isServerReachable method shouldn't be invoked on the main thread.

EDIT2: You can try this way, although I don't know all the implications of your code being called on another thread:

private void getClassTeacherList() {
academicPeriod = (AcademicPeriod) mSpnPeriod.getItemAtPosition(keyPos);
new Thread(new Runnable() {
public void run() {
if (isServerReachable(getApplicationContext())) {
classTeacherList = serverAuthenticateService.getClassTeacherList(selClass.getId(),academicPeriod.getId(), authtoken, getApplicationContext());
if (AppBackupCache.checkToken == 200) {
showClassTeacherList();
} else if (AppBackupCache.checkToken == 401) {
manager.invalidateAuthToken("com.lss.loop", authtoken);
authtoken = null;
final AccountManagerFuture<Bundle> future = manager.getAuthToken(mAccount, AccountGeneral.AUTHTOKEN_TYPE_FULL_ACCESS, new Bundle(), true, null, null);

Android - The application may be doing too much work on its main thread - Fragment, RecyclerView

Looking at your code, the potential candidate to blame seems to the database query + iteration, so the next section:

class FragmentTrack : Fragment() {

....

var songCursor : Cursor? = activity?.contentResolver?.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
null, null, null, null)

while (songCursor != null && songCursor.moveToNext()) {
var songName = songCursor.getString(songCursor.getColumnIndex(MediaStore.Audio.Media.TITLE))
var songArtist = songCursor.getString(songCursor.getColumnIndex(MediaStore.Audio.Media.ARTIST))

trackList.add(DataItems(songName, songArtist))
}

....
}

To avoid blocking the UI, all potentially heavy operations (such as Database Access, IO, Networking), should be performed in a background thread or coroutine.

Try querying + loading the data asynchronously and update the adapter once it's ready.

Update answering your comments. Some links to get you started:

https://medium.com/androiddevelopers/coroutines-on-android-part-i-getting-the-background-3e0e54d20bb

https://developer.android.com/kotlin/coroutines

https://developer.android.com/kotlin/coroutines-adv

https://developer.android.com/guide/background/threading

https://developer.android.com/guide/background

Android application doing too much work on main thread

You need to make sure that the processImage method runs on a background (non-ui) thread. It is probably running on the UI thread now, and you get the warning because it is blocking the UI thread.

There are a number of ways to do work on a background thread, from simply spawning a new thread to creating a service - you will need to research this, and decide on the best method for your particular situation. Just remember that when your background processing is complete, you need to transfer the data to the UI thread, and update the UI from the UI thread, as attempting an update from another thread will cause a crash.

My only specific advice is to not use an AsyncTask. They sound great in theory, but unless you really know how they work, they can get you into a lot of trouble. And if you really know how they work, you're fully capable of doing something more reliable.

Android doing too much work on its main thread when collecting Flow

The performance can be improved if we somehow only process the latest data as in the above-mentioned case, we don't need each emitted list of users, we only required, the latest list of users. So that we don't waste resources on processing each emitted list.

Kotlin Flow has another operator known as collectLatest{} which is a bit different from collect{}.

  1. collect{} - This will collect each emitted data.
  2. collectLatest{} - This will cancel the collector when a new value is emitted.
viewModelScope.launch {
dao.getUsers().collectLatest {
userList.value = it
}
}

If we need to collect only the non-empty list, we can simply filter out the empty emitted list.

viewModelScope.launch {
dao.getUsers()
.filter { it.isNotEmpty() }
.collectLatest {
userList.value = it
}
}


Related Topics



Leave a reply



Submit