Why I can't use runOnUiThread() to update an adapter?

旧巷老猫 提交于 2021-02-20 05:12:46

问题


I have an adapter and a spinner view which is set to use the adapter for it's entries. I'm adding items to adapter from a list of all files in /assets/ folder, I found that this task takes very long time (even about 2 seconds for a list of 2 files on a 1.5Ghz phone!). Then I came up to use a worker thread to gather my list and not block UI thread. here is my code:

@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(); 

}

but it causes an error and crash:

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.

Am I using runOnUiThread() correctly?! It's interesting that this code works perfectly when not using any thread, but it blocks UI (which is a pain).

any help on this please?


回答1:


As zapl mentioned, adapter.add(Object) has to be called from the UI thread.

You should use Android's AsyncTask class rather than a Thread object. You could, for instance, load the data from file in AsyncTask's doInBackground(Params...) method and update the list view in the onPostExecute(Result) method.

Furthermore, you don't need to call notifyDataSetChanged() explicitly; calls to adapter.add(Object) will notify the ListView that the adapter has changed.




回答2:


Instead of

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

Use the following instead (assuming fontsName is an ArrayList<String>):

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

The idea is to update the underlying data in the adapter (which is fine to be done on a different thread) and then notify the adapter about the change from the UI thread (using notifyDataSetChanged() as you have done).



来源:https://stackoverflow.com/questions/12003351/why-i-cant-use-runonuithread-to-update-an-adapter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!