提问人:KJEjava48 提问时间:12/6/2021 最后编辑:S_i_l_e_n_t C_o_d_e_rKJEjava48 更新时间:12/6/2021 访问量:4599
编舞: 跳过的帧 : 应用程序可能在其主线程上做了太多工作
Choreographer: Skipped frames : The application may be doing too much work on its main thread
问:
在我的 android 应用程序中,我收到“应用程序可能在其主线程上做了太多工作”作为警告,并且 api 调用需要花费大量时间才能做出响应。我用一个例子展示了它。我有一个带有 2 个案例的单选按钮,每个案例将在单击时进行 api 调用,结果将向用户显示数据列表。下面是我的代码。
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);
}
});
}
服务器身份验证服务.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;
}
}
下面是我得到的变暖。
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,
在我的应用程序中,我有很多 API 调用,大多数时候我都会收到此警告,我应该怎么做才能避免这种情况并使我的请求和应用程序工作得更快?
答:
如果我没记错的话,在调用回调时,至少在主 (UI) 线程上调用您的 方法一次。应改为将 Web API 调用移动到另一个线程,以便主线程不会“冻结”等待 Web API 调用的结果。ServerAuthenticateService
getClassTeacherList
onCheckedChange
从 https://developer.android.com/guide/components/processes-and-threads :
...如果一切都发生在 UI 线程中,则执行网络访问或数据库查询等长时间操作将阻塞整个 UI。当线程被阻塞时,无法调度任何事件,包括绘图事件。从用户的角度来看,应用程序似乎挂起。更糟糕的是,如果 UI 线程被阻塞超过几秒钟(目前约为 5 秒),用户将看到臭名昭著的“应用程序无响应”(ANR) 对话框。然后,如果用户不满意,他们可能会决定退出您的应用程序并卸载它。
编辑:也不应该在主线程上调用该方法。isServerReachable
编辑2:你可以尝试这种方式,尽管我不知道你的代码在另一个线程上被调用的所有含义:
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);
评论