我有一個AutoCompleteTextView動態填充。我動態地做到這一點,因爲我有大約10000個提案(街道)要顯示,所以我按照他們的第一個字母拆分了列表。假設有人輸入「a」,我將適配器填入所有以「a」開頭的街道。這種方法在仿真器中足夠快,在我的舊手機Android 2.1上足夠快。突然間,我意識到名單的填寫非常緩慢。大約需要10秒來填充。但我認爲這不是我的代碼問題,而是我的手機問題。前段時間我用CyanogenMod 7.2.0-blade升級到Android 2.3.7。我絕對相信我之前從未遇到過這個問題,因爲我從來沒有對生產做過一些落後的實施。我在追蹤時識別出一些奇怪的東西。所有的表演都被稱爲TextUtils.hasArabicCharacters()
的方法。見青色條...填充AutoCompleteTextView時Android性能問題
我不覺得這個方法什麼。 TextUtils沒有hasArabicCharacters,所以我想這是一些專有的東西 - > CyanogenMod? 如果我在任何仿真器上跟蹤相同的代碼,則不會調用任何名爲'hasArabicCharacters'的方法,並且自動填充行爲非常快。在Android 2.1,2.3.3和4.1.2仿真器下測試。
這是調用鏈(向上):
TextUtils.hasArabicCharacter() - > TextUtils.reshapeArabic() - > Paint.measureText() - > Styled.drawDirectionalRun() - > 樣式化.measureText() - > BoringLayout.isBoring() - > TextView.onMeasure() - > View.measure() - > ListView.measureScrapChild() - > ListView.measureHeightOfChildren() - > AutoCompleteTextView.buildDropdown() AutoCompleteTextView.showDropDown() - > AutoCompleteTextView.updateDropDownForFilter() - > AutoCompleteTextView.acces US $ 1700 - > AutoCompleteTextView $ PopulateDataSetObserver $ 1.run() - > Handler.handleCallback() - > Handler.dispatchMessage()
這是我如何填充我的適配器。也許我可以應用一些解決方法。有任何想法嗎?
活動:
final StreetArrayAdapter adapter = new StreetArrayAdapter(this, R.layout.simple_dropdown_item_1line);
autoCompleteTextView.setAdapter(adapter);
autoCompleteTextView.setValidator(new Validator());
autoCompleteTextView.setThreshold(0);
autoCompleteTextView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
streetInfoField.setText("");
}
});
autoCompleteTextView.addTextChangedListener(new StreetTextWatcher(adapter));
......
class Validator implements AutoCompleteTextView.Validator {
@Override
public CharSequence fixText(CharSequence invalidText) {
return "";
}
@Override
public boolean isValid(CharSequence text) {
Log.v(TAG, "Checking if valid: " + text);
String[] streets = StreetNameFactory.getStreetsWithLetter(text.subSequence(0, 1).toString().toUpperCase(Locale.US));
Arrays.sort(streets);
if (Arrays.binarySearch(streets, text.toString()) >= 0) {
return true;
}
return false;
}
}
StreetNameFactory.getStreetsWithLetter
public static String[] getStreetsWithLetter(String letter) {
Log.i(StreetNameFactory.class.getSimpleName(), "letter:" + letter);
if ("A".equals(letter)) {
return StreetNames.STREETS_A;
}
if ("Ä".equals(letter)) {
return StreetNames.STREETS_A;
}
if ("B".equals(letter)) {
return StreetNames.STREETS_B;
}
.....
StreetTextWatcher:
public class StreetTextWatcher implements TextWatcher {
private final StreetArrayAdapter adapter;
private boolean alreadyAdded = false;
public StreetTextWatcher(StreetArrayAdapter adapter) {
this.adapter = adapter;
}
@Override
public void afterTextChanged(Editable s) {
//not used
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if (s.length() < 1) {
adapter.clear();
alreadyAdded = false;
}
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.length() == 1) {
populateAdapter(s);
alreadyAdded = true;
}
}
private synchronized void populateAdapter(CharSequence s) {
String charSequence = s.toString().toUpperCase(Locale.US);
if (charSequence.startsWith("A") && !alreadyAdded) {
adapter.addAll(StreetNames.STREETS_A);
}
if (charSequence.startsWith("Ä") && !alreadyAdded) {
adapter.addAll(StreetNames.STREETS_A);
}
if (charSequence.startsWith("B") && !alreadyAdded) {
adapter.addAll(StreetNames.STREETS_B);
}
if (charSequence.startsWith("C") && !alreadyAdded) {
adapter.addAll(StreetNames.STREETS_C);
}
if (charSequence.startsWith("D") && !alreadyAdded) {
adapter.addAll(StreetNames.STREETS_D);
}
if (charSequence.startsWith("E") && !alreadyAdded) {
adapter.addAll(StreetNames.STREETS_E);
}
//more code....
if (charSequence.startsWith("Z") && !alreadyAdded) {
adapter.addAll(StreetNames.STREETS_Z);
}
if (Pattern.matches("[1-9]", s.toString()) && !alreadyAdded) {
adapter.addAll(StreetNames.STREETS_NUMBERS);
}
}
}
StreetArrayAdapter:
public class StreetArrayAdapter extends ArrayAdapter<String> {
private final String TAG = StreetArrayAdapter.class.getSimpleName();
public StreetArrayAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
}
public void addAll(String[] streets) {
Log.i(TAG, "BEGIN LIST FILL at: " + new Date(System.currentTimeMillis()).toString());
for (String street : streets) {
add(street);
}
Log.i(TAG, "END LIST FILL at: " + new Date(System.currentTimeMillis()).toString());
}
}
STREETS_A,STREETS_B,STREETS_C只是字符串數組我分配。
[更新]
我能找到一個很好的解決方法。輸入第一個字母時,我不能加載列表。當我輸入至少3個字母(StreetTextWatcher.onTextChange)後加載列表時,我沒有凍結,下拉菜單又很快。此外,用戶可能甚至不認識到這一變化。
'TextUtils.hasArabicCharacters()'是從'TextUtils.reshapeArabic()'中調用的。什麼方法調用'TextUtils.reshapeArabic()'(在traceview中的「Parents」下)? –
我添加了調用鏈。查看更新的發佈。 – Bevor
哪個版本的CyanogenMod? –