18

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)'

Tobias K.
  • 2,997
  • 2
  • 12
  • 29
the_prole
  • 8,275
  • 16
  • 78
  • 163

2 Answers2

19

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();
    }
}
VPZ
  • 741
  • 8
  • 19
11

I have the same problem, and I replaced runOnUiThread() with getActivity().runOnUiThread(). And it worked.

Victoria Klimova
  • 2,795
  • 1
  • 11
  • 12