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?
CodePudding user response:
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);