0

在我的 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);
        }
    });
}

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;
    }
}

下面是我得到的变暖。

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 调用,并且大多数时候我都会收到此警告,我应该怎么做才能避免这种情况并使我的请求和应用程序运行得更快?

4

1 回答 1

1

如果我没记错的话,至少在调用回调时在主(UI)线程上调用你ServerAuthenticateService的方法。相反,您应该将 Web API 调用移动到另一个线程,这样主线程就不会“冻结”等待 Web API 调用的结果。getClassTeacherListonCheckedChange

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

...如果一切都发生在 UI 线程中,执行长时间操作(例如网络访问或数据库查询)将阻塞整个 UI。当线程被阻塞时,不能调度任何事件,包括绘图事件。从用户的角度来看,应用程序似乎挂起。更糟糕的是,如果 UI 线程被阻塞超过几秒(目前大约 5 秒),用户会看到臭名昭著的“应用程序无响应”(ANR)对话框。如果他们不满意,用户可能会决定退出您的应用程序并卸载它。

编辑:也不isServerReachable应该在主线程上调用该方法。

EDIT2:您可以尝试这种方式,尽管我不知道在另一个线程上调用您的代码的所有含义:

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);
        
于 2021-12-06T08:29:04.070 回答