Android:尽管使用了AsyncTask,主线程也被阻止了

时间:2017-03-18 23:25:42

标签: android android-asynctask ui-thread

我有一个包含100多个复杂视图的Activity(包含图像,文本视图等)。如果没有一个以异步方式加载视图的Thread,那么显示这些视图就很难做到。所以我试着用AsyncTask做到这一点。我不确定这是否是正确的方法,因为"辛苦的员工"是在UI线程中完成的事情。

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

doInBackground触发所有publishProgress调用,之后主线程被阻塞(活动冻结,加载栏不再旋转)。有没有办法实现我想拥有的东西?我寻找解决方案,但总是最终得到使用AsyncTask的想法,没有人必须做视图的东西作为"辛苦的员工"。我没有使用"得到"在AsyncTask中,似乎是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();
    }
}

}

1 个答案:

答案 0 :(得分:1)

请注意,document.addEventListener('copy', function (e) { var nodesInRange = getRangeSelectedNodes(window.getSelection().getRangeAt(0)); /* Takes all <rb> within the selected range, ie. for <ruby><rb>振</rb><rt>ふ</rt></ruby> */ var payload = nodesInRange.filter((node) => node.nodeName === "RB").map((rb) => rb.innerText).join(""); /* Alternative for when <rb> isn't used: take all textNodes within <ruby> elements, ie. for <ruby>振<rt>ふ</rt></ruby> */ // var payload = nodesInRange.filter((node) => node.parentNode.nodeName === "RUBY").map((textNode) => textNode.textContent ).join(""); e.clipboardData.setData('text/plain', payload); e.preventDefault(); /* Utility function for getting an array of references to all the nodes in the selection area, * from: http://stackoverflow.com/a/7784176/5951226 */ function getRangeSelectedNodes(range) { var node = range.startContainer; var endNode = range.endContainer; if (node == endNode) return [node]; var rangeNodes = []; while (node && node != endNode) rangeNodes.push(node = nextNode(node)); node = range.startContainer; while (node && node != range.commonAncestorContainer) { rangeNodes.unshift(node); node = node.parentNode; } return rangeNodes; function nextNode(node) { if (node.hasChildNodes()) return node.firstChild; else { while (node && !node.nextSibling) node = node.parentNode; if (!node) return null; return node.nextSibling; } } } }); 运行时会重复调用onProgressView()。因此,应尽可能缩短。这也意味着您当前的代码正在创建批次视图并将其添加到UI。相反,您应该只添加一次视图,然后在AsyncTask中更新其数据。

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