我决定必须编写自己的语法荧光笔。到目前为止,它可以正常工作,但是它是实时的(您键入,突出显示),而且速度很慢。
我将尝试解释它是如何工作的。每次用户在EditText中键入内容时,它将运行荧光笔(通过TextWatcher)。荧光笔搜索文本直到找到单词的开头,然后搜索直到找到同一单词的结尾。找到单词后,它将搜索一组关键字,如果找到匹配项,则会在该位置设置跨度。它一直循环直到到达文档末尾。
同样,到目前为止,它仍然有效(只是在继续使用此方法之前尝试一下这个想法),但是它是如此缓慢。有时可能要花一秒钟才能完成几行。它减慢了文本在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;
}
}
“结构”资源(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>
任何人有任何建议如何使此搜索更快?我知道我有很多循环,但是我不确定还有其他方法。
非常感谢!
最佳答案
您可以在那里的分隔符上拆分字符串,而不是查看每个字符吗?这样可以加快速度。 (String.split())
关于android - 优化我的语法荧光笔,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7855587/