今天學習的控件是MultiAutoCompleteTextView 。 提到MultiAutoCompleteTextView 我們就自然而然地想到AutoCompleteTextView ,就想知道他們之間到底有什麼區別。
[java]
public static class SelfDedineTokenizer implements Tokenizer {
private char mTokenizer = ',';
public SelfDedineTokenizer() {
}
public SelfDedineTokenizer(char token) {
mTokenizer = token;
}
public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len) {
if (text.charAt(i) == mTokenizer) {
return i;
} else {
i++;
}
}
return len;
}
public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (i > 0 && text.charAt(i - 1) != mTokenizer) {
i--;
}
while (i < cursor && text.charAt(i) == ' ') {
i++;
}
return i;
}
public CharSequence terminateToken(CharSequence text) {
int i = text.length();
while (i > 0 && text.charAt(i - 1) == ' ') {
i--;
}
if (i > 0 && text.charAt(i - 1) == mTokenizer) {
return text;
} else {
if (text instanceof Spanned) {
SpannableString sp = new SpannableString(text
+ String.valueOf(mTokenizer));
TextUtils.copySpansFrom((Spanned) text, 0, text.length(),
Object.class, sp, 0);
return sp;
} else {
return text + String.valueOf(mTokenizer);
}
}
}
public void setToken(char token) {
mTokenizer = token;
}
public char getToken() {
return mTokenizer;
}
}
這段代碼是自定義的Tokenizer , 默認使用 ‘ , ’ 作為分隔符, 若想用其他的符號替換 ‘ , ’ 使用setToken方法即可。
廢話也說了那麼多了,現在說說今天要做的事情
1、使用異步調用方法(Executors)加載MultiAutoCompleteTextView 中 Adapter 需要的數據(數據跟AutoCompleteTextView一樣,有疑問的可參見 點擊一步一步學android控件(之五) —— AutoCompleteTextView)
2、在MultiAutoCompleteTextView中使用自定義的Tokenizer而不是默認的Tokenizer。
下面就來實現這些功能,老規矩先准備資源文件
1、 創建布局文件 multi_auto_complete_textview.xml
[html]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<MultiAutoCompleteTextView
android:id="@+id/show_multi_complete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:layout_marginTop="20dp" />
</LinearLayout>
2、創建activity ——WidgetMultiAutoCompleteActivity.java
[java]
package com.xy.zt.selfdefinewieget;
import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.widget.ArrayAdapter;
import android.widget.MultiAutoCompleteTextView;
import android.widget.MultiAutoCompleteTextView.Tokenizer;
public class WidgetMultiAutoCompleteActivity extends Activity {
public static final String[] DEFAULT_DATAS = new String[] { "China",
"chengdu", "xueyu", "ting", "baba", "mama", "meimei" };
public static final int MSG_RECEIVE_TASK_DATA = 1024;
private ExecutorService mExecutor;
private ArrayAdapter<String> mMultiAdapter;
private MultiAutoCompleteTextView mShowMulti;
// private CommaTokenizer mComma = new CommaTokenizer();
private Future<List<String>> mListFileTask;
private static final Callable<List<String>> LIST_FILES = new Callable<List<String>>() {
public List<String> call() throws Exception {
File rootDir = Environment.getRootDirectory();
LinkedList<File> queue = new LinkedList<File>();
ArrayList<String> result = new ArrayList<String>(100);
queue.offer(rootDir);
File tmpFile, tmpDirAllFile[];
while ((tmpFile = queue.poll()) != null) {
if (tmpFile.isDirectory()) {
tmpDirAllFile = tmpFile.listFiles();
if (tmpDirAllFile != null) {
for (File f : tmpDirAllFile) {
queue.offer(f);
}
}
} else {
result.add(tmpFile.getName());
}
}
return result;
}
};
Handler mHandler = new Handler() {
@SuppressWarnings("unchecked")
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_RECEIVE_TASK_DATA:
List<String> datas;
try {
datas = (List<String>) msg.obj;
} catch (ClassCastException e) {
datas = useDefaultData();
}
mShowMulti.setEnabled(true);
mMultiAdapter = new ArrayAdapter<String>(
WidgetMultiAutoCompleteActivity.this,
R.layout.auto_complete_item, R.id.auto_item_file_name,
datas);
mShowMulti.setAdapter(mMultiAdapter);
break;
}
;
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.multi_auto_complete_textview);
init();
mExecutor = Executors.newCachedThreadPool();
mListFileTask = mExecutor.submit(LIST_FILES);
mExecutor.submit(new Runnable() {
@SuppressLint("HandlerLeak")
public void run() {
List<String> datas;
try {
datas = mListFileTask.get();
} catch (InterruptedException e) {
datas = useDefaultData();
} catch (ExecutionException e) {
datas = useDefaultData();
}
Message msg = mHandler.obtainMessage(MSG_RECEIVE_TASK_DATA);
msg.obj = datas;
mHandler.sendMessage(msg);
}
});
}
void init() {
mShowMulti = (MultiAutoCompleteTextView) findViewById(R.id.show_multi_complete);
mShowMulti.setEnabled(false);
mShowMulti.setTokenizer(mCustomerToken);
mShowMulti.setThreshold(1);
}
private List<String> useDefaultData() {
List<String> datas = new ArrayList<String>();
for (String s : DEFAULT_DATAS) {
datas.add(s);
}
return datas;
}
@Override
protected void onDestroy() {
super.onDestroy();
mExecutor.shutdown();
}
SelfDedineTokenizer mCustomerToken = new SelfDedineTokenizer(';');
public static class SelfDedineTokenizer implements Tokenizer {
private char mTokenizer = ',';
public SelfDedineTokenizer() {
}
public SelfDedineTokenizer(char token) {
mTokenizer = token;
}
public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
while (i < len) {
if (text.charAt(i) == mTokenizer) {
return i;
} else {
i++;
}
}
return len;
}
public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
while (i > 0 && text.charAt(i - 1) != mTokenizer) {
i--;
}
while (i < cursor && text.charAt(i) == ' ') {
i++;
}
return i;
}
public CharSequence terminateToken(CharSequence text) {
int i = text.length();
while (i > 0 && text.charAt(i - 1) == ' ') {
i--;
}
if (i > 0 && text.charAt(i - 1) == mTokenizer) {
return text;
} else {
if (text instanceof Spanned) {
SpannableString sp = new SpannableString(text
+ String.valueOf(mTokenizer));
TextUtils.copySpansFrom((Spanned) text, 0, text.length(),
Object.class, sp, 0);
return sp;
} else {
return text + String.valueOf(mTokenizer);
}
}
}
public void setToken(char token) {
mTokenizer = token;
}
public char getToken() {
return mTokenizer;
}
}
}
今天主要的內容就在這個文件中,先來看看
[java]
private static final Callable<List<String>> LIST_FILES = new Callable<List<String>>()
Callable接口類似於Runnable,只是他是有返回結果的Runnable , 在他的call方法中做搜索系統文件的工作。 在onCreat函數中有下面代碼:
[java]
mExecutor = Executors.newCachedThreadPool();
mListFileTask = mExecutor.submit(LIST_FILES);
這段代碼第一句創建了一個線程池,第二句將ListFILES提交到線程池進行處理。接下來的代碼:
[java]
mExecutor.submit(new Runnable() {
@SuppressLint("HandlerLeak")
public void run() {
List<String> datas;
try {
datas = mListFileTask.get();
} catch (InterruptedException e) {
datas = useDefaultData();
} catch (ExecutionException e) {
datas = useDefaultData();
}
Message msg = mHandler.obtainMessage(MSG_RECEIVE_TASK_DATA);
msg.obj = datas;
mHandler.sendMessage(msg);
}
});
這段代碼將一個Runnable提交到線程池執行,mListFileTask.get(); 這句在Callable中的call函數沒有執行完之前一直處於阻塞狀態(不可以放到主線程中),得到數據後發送消息更新UI。
在init函數中有這麼一句:
[java]
mShowMulti.setTokenizer(mCustomerToken);
表示使用的是自定義的Tokenizer,他的定義如下
[java]
SelfDedineTokenizer mCustomerToken = new SelfDedineTokenizer(';');
這樣看到的效果跟圖二的就有點不同了哦 ^_^......
3、 完善真個工程,下面滴內容也是不可少滴。也寫了幾個控件了,看看現在ViewData.java中的內容
[java]
package com.xy.zt.selfdefinewieget.data;
import java.util.ArrayList;
final public class ViewData {
public final static ArrayList<ViewData> View_Datas = new ArrayList<ViewData>();
public static final int TEXT_VIEW_ID = 90000;
public static final String TEXT_VIEW_NAME = "TextView";
public static final int BUTTON_ID = TEXT_VIEW_ID + 1;
public static final String BUTTON_NAME = "Button";
public static final int EDIT_TEXT_ID = BUTTON_ID + 1;
public static final String EDIT_TEXT_NAME = "EditText";
public static final int AUTO_COMPLETE_TEXTVIEW_ID = EDIT_TEXT_ID + 1;
public static final String AUTO_COMPLETE_TEXTVIEW_NAME = "AutoCompleteTextView";
public static final int MULTI_AUTO_COMPLETE_TEXTVIEW_ID = AUTO_COMPLETE_TEXTVIEW_ID + 1;
public static final String MULTI_AUTO_COMPLETE_TEXTVIEW_NAME = "MultiAutoCompleteTextView";
private static final ViewData mTextView = new ViewData(TEXT_VIEW_NAME,
TEXT_VIEW_ID);
private static final ViewData mButton = new ViewData(BUTTON_NAME, BUTTON_ID);
private static final ViewData mEditText = new ViewData(EDIT_TEXT_NAME,
EDIT_TEXT_ID);
private static final ViewData mAutoCompleteTextView = new ViewData(
AUTO_COMPLETE_TEXTVIEW_NAME, AUTO_COMPLETE_TEXTVIEW_ID);
private static final ViewData mMultiAutoCompleteTextView = new ViewData(
MULTI_AUTO_COMPLETE_TEXTVIEW_NAME, MULTI_AUTO_COMPLETE_TEXTVIEW_ID);
public final String mViewName;
public final int mViewId;
private ViewData(String name, int id) {
mViewName = name;
mViewId = id;
}
static {
View_Datas.add(mTextView);
View_Datas.add(mButton);
View_Datas.add(mEditText);
View_Datas.add(mAutoCompleteTextView);
View_Datas.add(mMultiAutoCompleteTextView);
}
}
最後在WidgetsAdapter的handleItemClicked函數中加入如下內容:
[java]
case ViewData.MULTI_AUTO_COMPLETE_TEXTVIEW_ID:
intent.setClass(mContext, WidgetMultiAutoCompleteActivity.class);
mContext.startActivity(intent);
break;
handleItemClicked 最新內容如下:
[java]
private void handleItemClicked(int action) {
Intent intent = new Intent();
switch (action) {
case ViewData.TEXT_VIEW_ID:
intent.setClass(mContext, WidgetTextView.class);
mContext.startActivity(intent);
break;
case ViewData.BUTTON_ID:
intent.setClass(mContext, WidgetButtonActivity.class);
mContext.startActivity(intent);
break;
case ViewData.EDIT_TEXT_ID:
intent.setClass(mContext, WidgetEditTextActivity.class);
mContext.startActivity(intent);
break;
case ViewData.AUTO_COMPLETE_TEXTVIEW_ID:
intent.setClass(mContext, WidgetAutoCompleteActivity.class);
mContext.startActivity(intent);
break;
case ViewData.MULTI_AUTO_COMPLETE_TEXTVIEW_ID:
intent.setClass(mContext, WidgetMultiAutoCompleteActivity.class);
mContext.startActivity(intent);
break;
}
}
MultiAutoCompleteTextView 就介紹到這裡了,下一個控件 Toast 。