Android:尽管使用了 AsyncTask,但主线程仍被阻塞

Android: Main Thread blocked despite using AsyncTask

我有一个 Activity,其中包含 100 多个复杂视图(包括图像、文本视图等)。如果没有异步加载视图的线程,很难显示这些视图。所以我试着用 AsyncTask 来做。我不确定这是否是正确的方法,因为 "hard staff" 是必须在 UI 线程中完成的事情。

现在我遇到了 UI 冻结的问题,尽管我使用 onProgressUpdate 将视图添加到父视图中。我认为这会导致单个加载视图在父视图中连续出现。但这种情况并非如此。

doInBackground 触发所有 publishProgress 调用,之后主线程被阻塞(activity 冻结,loadbar 不再旋转)。有没有办法实现我想要的?我寻找解决方案,但总是以使用 AsyncTask 的想法告终,而且没有人必须像 "hard staff" 那样做视图工作。我没有在 AsyncTask 中使用 "get" 这似乎是 AsyncTask 的问题。

这是我的代码。如果您需要任何进一步的信息,请告诉我!

请问还有其他方法可以解决这个问题吗?我的 AsyncTask 实现不正确吗?我正在寻找一种在不阻塞主线程的情况下将这些复杂视图异步加载到父视图的方法。

提前致谢!

public class LoadKraut extends AsyncTask<Integer,Kraut,Void> {

private Context context;
private LinearLayout parent;
private HashMap<String,HeadlineAlphabet> headlinesAlphabet = new HashMap<String, HeadlineAlphabet>();
private long time;
private Integer kategorie;
private char letter = 'X';
private int counter = 0;
private ProgressDialog dialog;


public LoadKraut(Context context) {

    /**
     * Kategorie:
     * 1 - A-Z
     * 2 - Notiz
     * 3 - Favorit
     * 4 - Giftig
     */

    Log.i("Kraut", "Start thread" + (System.currentTimeMillis()-time) + "ms");

    this.context = context;
    this.dialog = new ProgressDialog(context);
    this.time = System.currentTimeMillis();
}

@Override
protected void onPreExecute() {

    dialog.setMessage("Lade Kräuter. Dieser Vorgang kann einen Moment dauern.");
    dialog.show();

}

@Override
protected Void doInBackground(Integer... params) {

    this.kategorie = params[0];

    //Create overview
    try {
        DatabaseHelper databaseHelper = new DatabaseHelper(context);
        Dao<Kraut,Integer> dao = databaseHelper.getKrautDAO();

        parent = (LinearLayout) ((Activity) context).findViewById(R.id.ll_conainter_sv_uebersicht_kraeuter);

        //setKraeuter(list, linearLayout, giftig)

        long test = System.currentTimeMillis();

        List<Kraut> list = new ArrayList<>();

        switch (kategorie) {

            case 1:
                list = dao.queryForAll();
                break;

            case 2:
                list = dao.queryBuilder().where().ne("notiz","").query();
                break;

            case 3:
                list = dao.queryBuilder().where().eq("favorit",true).query();
                break;

            case 4:
                list = dao.queryBuilder().where().eq("toedlichBunny",true).query();
                break;

        }

        Log.i("Kraut","Fetching duration: " + String.valueOf(System.currentTimeMillis() - test));

        Iterator<Kraut> iterator = list.iterator();

        while(iterator.hasNext()) {

            Kraut kraut = iterator.next();
            Log.i("Kraut","called pp for" + kraut.getName());
            publishProgress(kraut);

        }
    } catch (SQLException e) {
        e.printStackTrace();
    }

    Log.i("Kraut", "End " + (System.currentTimeMillis()-time) + "ms");

    return null;
}

@Override
protected void onProgressUpdate(Kraut... value) {

    //Set all Krauts and headlines A-Z

    long test = System.currentTimeMillis();

    Kraut kraut = value[0];

    Log.i("Kraut", String.valueOf(counter));


    if((kategorie==1 || kategorie==4) && kraut.getName().charAt(0)!=letter) {
        letter = kraut.getName().charAt(0);

        HeadlineAlphabet letterHeadline = new HeadlineAlphabet(context);
        letterHeadline.setText(String.valueOf(kraut.getName().charAt(0)));
        headlinesAlphabet.put(String.valueOf(letterHeadline.getText()),letterHeadline);

        parent.addView(letterHeadline);

    }

    KrautView krautView=null;

    if(kategorie==1 || kategorie==3) {
        krautView = new KrautUebersicht(context,kategorie);
    } else if(kategorie==2) {
        krautView = new KrautUebersichtNotiz(context);
    }

    if(krautView!=null) {
        krautView.setKraut(kraut);
        parent.addView((LinearLayout) krautView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    }

    parent.getRootView().invalidate();

    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    counter++;

    Log.i("Kraut","Kraut View creation duration: " + String.valueOf(System.currentTimeMillis() - test));

}

@Override
protected void onPostExecute(Void aVoid) {
    super.onPostExecute(aVoid);

    if(kategorie==1) {
        //Set Alphabet Column right side
        ArrayList<String> anfangsbuchstaben = Kraut.getAnfangsbuchstaben(context);

        // Do this with an xml !
        for (int i = 1; i <= 26; i++) {

            //Log.i("Kraut", String.valueOf(i));

            String currentLetter = Helper.getCharForNumber(i);

            int id = context.getResources().getIdentifier("tv_"+currentLetter.toLowerCase(),"id",context.getPackageName());
            TextView textView = (TextView) ((Activity) context).findViewById(id);

            //If no Kraut contains Letter
            if (!anfangsbuchstaben.contains(currentLetter)) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    textView.setTextColor(context.getResources().getColor(R.color.darkgrey, context.getTheme()));
                } else {
                    textView.setTextColor(context.getResources().getColor(R.color.darkgrey));
                }
                //Make clickable to jump to A-Z Headlines
            } else {

                textView.setOnClickListener(new JumpToLetterOnClickListener(headlinesAlphabet));

            }
        }
    }

    parent.invalidate();

    if(dialog.isShowing()) {
        dialog.dismiss();
    }
}

}

请注意,onProgressView() 在您的 AsyncTask 运行时被重复调用。因此,它应该尽可能短。这也意味着您当前的代码正在创建 lots 视图并将它们添加到 UI。相反,您应该只添加一次视图,然后在 onProgressView().

中更新其数据

此外,正如 Mike M. 在评论中所述,您不应在 onProgressView() 中调用 Thread.sleep(),因为它在 UI 线程上运行。这很可能是您的应用冻结的主要原因。