1

In my android application I am getting "The application may be doing too much work on its main thread" as warning and api call taking to much time to make response.I showed it with an example.I have a radio button with 2 cases each will make an api call on click and result will show a list of data to users.Below is my code.

protected void onCreate(Bundle savedInstanceState) {
    /**   Other code **/
    rdbGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(RadioGroup radioGroup, int checkedId) {
            pos = radioGroup.indexOfChild(findViewById(checkedId));
            switch (pos) {
                case 0:
                    if (screenType == 1) {
                        getClassTeacherList();
                    } else {
                        rcyTeachers.setVisibility(View.GONE);
                    }
                    fabAddClassTeacher.setTitle("Add class teacher");
                    return;
                case 2:
                    if (screenType == 1) {
                        getAcademicTeachersList();
                    } else {
                        rcyTeachers.setVisibility(View.GONE);
                    }
                    fabAddClassTeacher.setTitle("Add Teacher");
                    return;
                default:
            }
        }
    });

private void getClassTeacherList() {
    academicPeriod = (AcademicPeriod) mSpnPeriod.getItemAtPosition(keyPos);
    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);
            new Thread(new Runnable() {
                public void run() {
                    try {
                        Bundle bnd = (Bundle) future.getResult();
                        authtoken = bnd.getString("authtoken");
                        if (authtoken != null) {
                            classTeacherList = serverAuthenticateService.getClassTeacherList(selClass.getId(),academicPeriod.getId(), authtoken, getApplicationContext());
                            if (AppBackupCache.checkToken == 200) {
                                showClassTeacherList();
                                return;
                            } else {
                                getMsgBox("Error", "Something went wrong");
                                return;
                            }
                        }

                        getMsgBox("", "Token not refreshed....");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
        AppBackupCache.checkToken = 401;
        return;
    }
    getMsgBox("No connection", "No connection");
}

public boolean isServerReachable(Context applicationContext) {
    ConnectivityManager connMan = (ConnectivityManager) applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo netInfo = connMan.getActiveNetworkInfo();
    if (netInfo != null && netInfo.isConnected()) {
        try {
            URL urlServer = new URL(strUrl);
            HttpURLConnection urlConn = (HttpURLConnection) urlServer.openConnection();
            urlConn.setConnectTimeout(3000); //<- 3Seconds Timeout
            urlConn.connect();
            return urlConn.getResponseCode() == 200;
        } catch (MalformedURLException e1) {
            return false;
        } catch (IOException e) {
            return false;
        }
    }
    return false;
    //return true;
}


private void showClassTeacherList() {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (classTeacherList.size() > 0) {
                rcyTeachers.setVisibility(View.VISIBLE);
                linLayColor1.setVisibility(View.VISIBLE);
                linLaySub.setVisibility(View.GONE);
                classTeacherGridAdapter = new ClassTeacherGridAdapter(ClassTeacherActivity.this, classTeacherList, fontFamily, screenType, 1);
                rcyTeachers.setAdapter(classTeacherGridAdapter);
                ViewCompat.setNestedScrollingEnabled(rcyTeachers, true);
                return;
            }
            rcyTeachers.setVisibility(View.GONE);
            linLayColor1.setVisibility(View.GONE);
        }
    });
}

ServerAuthenticateService.java :

@Override
public List<ClassTeacher> getClassTeacherList(int classId, int academicId, String authtoken, Context applicationContext) {
    HttpHeaders headers = new HttpHeaders();
    headers.set("Authorization", "bearer " + authtoken);
    MultiValueMap<String, String> map = new LinkedMultiValueMap();
    map.add("classId", String.valueOf(classId));
    map.add("academicId", String.valueOf(academicId));
    ResponseEntity<String> restRes = this.restTemplate.exchange(apiUrl + "/getClassTeacherList", HttpMethod.POST, new HttpEntity(map, headers), String.class, new Object[0]);
    if (restRes.getStatusCode() == HttpStatus.OK) {
        AppBackupCache.checkToken = ItemTouchHelper.Callback.DEFAULT_DRAG_ANIMATION_DURATION;
        String resBody = (String) restRes.getBody();
        Type listType = new TypeToken<List<ClassTeacher>>() {}.getType();
        List<ClassTeacher> allActPgmMap = (List) this.gson.fromJson(resBody, listType);
        return allActPgmMap;
    } else if (restRes.getStatusCode() == HttpStatus.UNAUTHORIZED) {
        AppBackupCache.checkToken = 401;
        return null;
    } else {
        AppBackupCache.checkToken = 402;
        return null;
    }
}

Below is the warming i am getting.

I/Choreographer: Skipped 687 frames!  The application may be doing too much work on its main thread.
I/OpenGLRenderer: Davey! duration=11662ms; Flags=0, IntendedVsync=1315104621338, Vsync=1326554620880, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=1326567046366, AnimationStart=1326567174126, PerformTraversalsStart=1326567180324, DrawStart=1326747726176, SyncQueued=1326760565187, SyncStart=1326761318573, IssueDrawCommandsStart=1326761742323, SwapBuffers=1326766654823, FrameCompleted=1326767746542, DequeueBufferDuration=298000, QueueBufferDuration=332000, 

 I/Choreographer: Skipped 682 frames!  The application may be doing too much work on its main thread.
 I/OpenGLRenderer: Davey! duration=11418ms; Flags=0, IntendedVsync=1354296057548, Vsync=1365662723760, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=1365665791303, AnimationStart=1365665859063, PerformTraversalsStart=1365665871094, DrawStart=1365707384015, SyncQueued=1365711047505, SyncStart=1365711676880, IssueDrawCommandsStart=1365712054224, SwapBuffers=1365714258860, FrameCompleted=1365715220318, DequeueBufferDuration=243000, QueueBufferDuration=341000, 

In my application, I have lots of API calls and most of the time I am getting this warning, what should I do to avoid this and make my request and application work faster?

KJEjava48
  • 1,967
  • 7
  • 40
  • 69

1 Answers1

1

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);
        
Guido Cardinali
  • 366
  • 1
  • 13
  • So are u suggesting me to write the webapi call and isServerReachable code inside new Thread(new Runnable() { public void run() { } }).start(); ?? – KJEjava48 Dec 06 '21 at 08:33
  • @KJEjava48 Yep! – Guido Cardinali Dec 06 '21 at 08:37
  • If i write so how can i pass the result list to activity class from thread in ServerAuthenticateService. Can u show it in ur answer. – KJEjava48 Dec 06 '21 at 08:41
  • Ok... done. That should do. – Guido Cardinali Dec 06 '21 at 08:48
  • Now "The application may be doing too much work on its main thread" error gone but results are listing after a long time after the radiobutton switching.Users may get confused by the old list after switching the radiobutton.What should i do for that?? – KJEjava48 Dec 06 '21 at 09:21
  • I don't really think that's due to the change you made. That's normal, since you're calling a Web API, there's a response time to be waited. You should show a progress bar or something similar, until the results come back and the list is populated. – Guido Cardinali Dec 06 '21 at 09:24
  • Ok. Are u sure that new Thread(new Runnable() { public void run() { }}).start(); is the best thing to do here?? – KJEjava48 Dec 06 '21 at 09:25
  • Roughly, yes. Of course, there are better ways to handle web API calls, such as using a library (Retrofit, for instance), than creating a new thread each time. But I believe your code is now in a better state, and you're avoiding ANR issues, which aren't really great from the user's point of view. – Guido Cardinali Dec 06 '21 at 09:34
  • Sometimes i am getting ANR issues, mostly when making web api calls along with the background token refreshing service on run.Does using retrofit avoids ANR issues?? – KJEjava48 Dec 06 '21 at 09:39
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/239870/discussion-between-kjejava48-and-guido-c). – KJEjava48 Dec 06 '21 at 09:46