优化我的语法荧光笔

时间:2011-10-21 21:40:37

标签: android optimization syntax-highlighting

我已经决定编写自己的语法荧光笔了。到目前为止,它是有效的,但它是实时的(你键入,它突出显示),而且它很慢。

我会尝试解释它是如何工作的。每次用户在EditText中输入内容时,它都会运行荧光笔(通过TextWatcher)。荧光笔搜索文本直到找到单词的开头,然后搜索直到找到相同单词的结尾。一旦找到一个单词,它就会搜索一系列关键字,如果找到一个匹配项,它会在该位置设置一个spannable。它会一直循环,直到到达文档的末尾。

同样,它到目前为止工作(在继续使用此方法之前尝试这个想法),但它太慢了。有时候只需经过几行即可花费一秒钟。它减慢了文本在EditText中显示的速度。 - 我还设置了在用户键入的最后一个位置输入文本后荧光笔开始的位置,这样每次都不需要通过整个文档,它有点但不多。

这是我的EditText的基础:

public class CodeView extends EditText {
    private int mTxtChangeStart;
    String mStructures[] = this.getResources().getStringArray(R.array.structures);

    public CodeView(Context context, AttributeSet attrs) {
        super(context, attrs);
        addTextChangedListener(inputTextWatcher);

                ...
        }

    TextWatcher inputTextWatcher = new TextWatcher() {

        @Override
        public void afterTextChanged(Editable s) {
            syntaxHighlight();
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
            //Set where we should start highlighting
            mTxtChangeStart = start;
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before,
                int count) {


        }

    };

    private void syntaxHighlight() {

        //Time how long it takes for debugging
        long syntime = System.currentTimeMillis();
        Log.d("", "Start Syntax Highlight");


        //Get the position where to start searching for words
        int strt = mTxtChangeStart;

        //Get the editable text
        Editable txt = getText();


        //Back up the starting position to the nearest space
        try {
            for(;;) {
                if(strt <= 0) break;
                char c = txt.charAt(strt);

                if(c != ' ' && c != '\t' && c != '\n' && c != '\r') {
                    strt--;
                } else {
                    break;
                }
            }
        } catch (IndexOutOfBoundsException e) {
            Log.e("", "Find start position failed: " + e.getMessage());
        }   

        //Just seeing how long this part took
        long findStartPosTime = System.currentTimeMillis();
        Log.d("", "Find starting position took " + String.valueOf(System.currentTimeMillis() - findStartPosTime) + " milliseconds");

        //the 'end of a word' position
        int fin = strt;

        //Get the total length of the search text
        int totalLength = txt.length();

        //Start finding words
        //This loop is to find the first character of a word
        //It loops until the current character isnt a space, tab, linebreak etc.
        while(fin < totalLength && strt < totalLength) {
            for(;;) {
                //Not sure why I added these two lines - not needed here
                //fin++;
                //if(fin >= totalLength) { break; } //We're at the end of the document

                //Check if there is a space at the first character.
                try {
                    for(;;) { //Loop until we find a useable character
                        char c = txt.charAt(strt);
                          if (c == ' ' || c == '\t' || c == '\n' || c == '\r'){
                            strt++; //Go to the next character if there is a space
                          } else {
                            break; //Found a character (not a space, tab or linebreak) - break the loop
                        }
                    }
                }catch(IndexOutOfBoundsException e) {
                    Log.e("", e.getMessage());
                    break;
                }

                //Make sure fin isnt less than strt
                if(strt > fin) { fin = strt; }

                //Now we search for the end of the word
                //Loop until we find a space at the end of a word
                try {
                    for(;;) {
                        char c = txt.charAt(fin);
                        if(c != ' ' && c != '\t' && c != '\n' && c != '\r') {
                            fin++; //Didn't find whitespace here, keep looking
                        } else {
                            break; //Now we found whitespace, end of a word
                        }
                    }
                    break;
                } catch (IndexOutOfBoundsException e) {
                    //If this happens it should mean it just reached the end of the document.
                    Log.e("", "End of doc? : " + e.getMessage());
                    break;
                }   
            }

            Log.d("", "It took " + String.valueOf(System.currentTimeMillis() - findStartPosTime) + " milliseconds to find a word");

            //Make sure fin isnt less that start, again
            if(strt > fin) { fin = strt; }

            //Debug time, how long it took to find a word
            long matchTime = System.currentTimeMillis();

            //Found a word, see if it matches a word in our string[]
            try {
                for(String mStruct : mStructures) {
                    if(String.valueOf(txt.subSequence(strt, fin)).equals(mStruct)) {
                        //highlight
                        Spannable s = (Spannable) txt;
                        s.setSpan(new ForegroundColorSpan(Color.RED), strt, fin, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                        //Can someone explain why this is still setting the spannable to the main editable???
                        //It should be set to txt right???

                        break;

                    } else {
                        /*Spannable s = (Spannable) txt;
                        s.setSpan(new ForegroundColorSpan(Color.BLACK), strt, fin, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
                        txt.removeSpan(s);*/
                    }
                }

            }catch (IndexOutOfBoundsException e) {
                e.printStackTrace();
                Log.e("", "word match error: " + e.getMessage());
            }

            //Finally set strt to fin and start again!
            strt = fin;
            Log.d("", "match a word time " + String.valueOf(System.currentTimeMillis() - matchTime) + " milliseconds");
        }//end main while loop

        Log.d("", "Syntax Highlight Finished in " + (System.currentTimeMillis() - syntime) + " milliseconds");
        mTextChanged = false;
    }


}

“structures”资源(php.xml)

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string-array name="structures">
            <item>if</item>
            <item>else</item>
            <item>else if</item>
            <item>while</item>
            <item>do-while</item>
            <item>for</item>
            <item>foreach</item>
            <item>break</item>
            <item>continue</item>
            <item>switch</item>
            <item>declare</item>
            <item>return</item>
            <item>require</item>
            <item>include</item>
            <item>require_once</item>
            <item>include_once</item>
            <item>goto</item>
        </string-array>

</resources>

有人建议如何更快地进行此搜索吗?我知道我有很多循环,但我不确定如何做到这一点。

非常感谢!

1 个答案:

答案 0 :(得分:1)

你可以在你那里的分隔符上拆分字符串而不是查看每个字符吗?这会加速一些。 (String.split())