1

我有一个适配器和一个微调器视图,该视图设置为将适配器用于其条目。我正在从 /assets/ 文件夹中的所有文件列表中向适配器添加项目,我发现此任务需要很长时间(对于 1.5Ghz 手机上的 2 个文件列表,甚至大约需要 2 秒!)。然后我想使用一个工作线程来收集我的列表,而不是阻塞 UI 线程。这是我的代码:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.settings);

    adapter = new ArrayAdapter<String>(SettingsActivity.this, android.R.layout.simple_spinner_item, fontsName);       
    Spinner fontsSpinner = (Spinner) findViewById(R.id.settings_font_spinner);
    fontsSpinner.setAdapter(adapter);
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);         

    // The thread to gather font names from /assets/fonts/
    thread =  new Thread(){  
        @Override  
        public void run(){  
            try {
                String[] fileList = getAssets().list("fonts");
                if (fileList != null)
                    for (int i=0; i<fileList.length; i++) {
                        adapter.add(fileList[i]);               
                    }
            } catch (IOException e) {
            }                   
            runOnUiThread(new Runnable(){
                @Override
                public void run() {
                    adapter.notifyDataSetChanged();
                }
            });
        }  
    };        
    thread.start(); 

}

但它会导致错误和崩溃:

08-17 13:54:01.017: E/AndroidRuntime(17929): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

我是否正确使用了 runOnUiThread()?!有趣的是,这段代码在不使用任何线程时可以完美运行,但它会阻塞 UI(这很痛苦)。

请问有什么帮助吗?

4

2 回答 2

3

正如 zapl 提到的,adapter.add(Object)必须从 UI 线程调用。

您应该使用 Android 的AsyncTask 类而不是 Thread 对象。例如,您可以在 AsyncTask 的doInBackground(Params...)方法中从文件中加载数据并更新该onPostExecute(Result)方法中的列表视图。

此外,您不需要notifyDataSetChanged()显式调用;调用adapter.add(Object)将通知 ListView 适配器已更改。

于 2012-08-17T09:49:29.010 回答
0

代替

                for (int i=0; i<fileList.length; i++) {
                    adapter.add(fileList[i]);               
                }

请改用以下内容(假设fontsNameArrayList<String>):

                for (int i=0; i<fileList.length; i++) {
                    fontsName.add(fileList[i]);               
                }

这个想法是更新适配器中的基础数据(这可以在不同的线程上完成),然后通知适配器来自 UI 线程的更改(notifyDataSetChanged()就像你所做的那样使用)。

于 2012-08-17T09:59:15.107 回答