Search code examples
androidlistview

Cannot resolve method .runOnUiThread


I found this example here on how to use the runOnUiThread method, but I don't understand how to use it.

I setup the list adapter in my main activity

    // Set a gobal reference to the list adapter and the list respectivly 

    ListAdapter listAdapter;
    static ArrayList<String> list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // some code

        adapter = new ListAdapter(getActivity(), R.layout.item_layout, list);
        listView.setAdapter(adapter);

        // some code

    }

I have the list adapter here calling a service handler class

public class ListAdapter {
    
    // some code

    ServiceHandler sh = new ServiceHandler();

    sh.run();
}

Here is .run() method in ServiceHandler class where I updated the list and the list adapter

public void run(Adapter listAdapter, ArrayList<String> list){
    
    // some code

    list[0] = "foo";
    listAdapter.notifyDataSetChanged;
}

But I get this error in run time

Only the original thread that created a view hierarchy can touch its views.

So I try to solve the error with .runOnUiThread

So here is .run() method in ServiceHandler class again, with runOnUiThread

public void run(Adapter listAdapter, ArrayList<String> list){
    
    // some code

    runOnUiThread(new Runnable() {
        @Override
        public void run() {

            list[0] = "foo";
            listAdapter.notifyDataSetChanged;
    }});
}
    

But I get

Cannot resolve method 'runOnUiThread(anonymous Java.lang.runnable)'


Solution

  • You can move service handler as private member class inside your activity like below to use Activity's this context.

    class MyActivity extends Activity {
    
        private class ServiceHandler /** Whichever class you extend */ {
            public void run() {
                MyActivity.this.runOnUiThread(new Runnable() {
    
                    @Override
                    public void run() {
                        mAdapter.notifyDataSetChanged();
                    }
    
                });
            }
        }
    
        private MyListAdapterTracks mAdapter;
    
        private ServiceHandler mHandler;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // Some code
    
            mAdapter = new MyListAdapterTracks(getActivity(), R.layout.item_layout, list);
            listView.setAdapter(mAdapter);
    
            // Some code
    
            ServiceHandler sh = new ServiceHandler();
            sh.run();
        }
    }
    

    EDIT:

    public class ServiceHandler /** Whichever class you extend */ {
    
        private final Activity mActivity;
    
        private final MyListAdapterTracks mAdapter;
    
        public ServiceHandler(Activity activity, MyListAdapterTracks adapter) {
            mActivity = activity;
            mAdapter = adapter;
        }
    
        @Override
        public void run() {
            mActivity.runOnUiThread(new Runnable() {
    
                @Override
                public void run() {
                    mAdapter.notifyDataSetChanged();
                }
    
            });
        }
    
        // More code
    
    }
    

    And then instanciate it in your activity like this:

    class MyActivity extends Activity {
    
        private MyListAdapterTracks mAdapter;
    
        private ServiceHandler mHandler;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // Some code
    
            ServiceHandler sh = new ServiceHandler(this);
            sh.run();
        }
    }