runOnUiThread in fragment

AndroidAndroid FragmentsAndroid Activity

Android Problem Overview


I'm trying to convert an Activity to fragment. The error mark on runOnUiThread. on the past:

> GoogleActivityV2 extends from Activity. runOnUiThread in class > ExecuteTask. class ExecuteTask nested on activity.

(Run ok) now :

> GoogleActivityV2 extends from Fragment. runOnUiThread in class > ExecuteTask. class ExecuteTask nested on activity. (Error on > runOnUiThread)

here is my code

public class GoogleActivityV2 extends SherlockMapFragment implements OnMapClickListener , OnMapLongClickListener , OnCameraChangeListener , TextWatcher {


	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
		View rootView = inflater.inflate(R.layout.activity_googlev2, container, false);
		Init();
		adapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_dropdown_item_1line);
		textView = (AutoCompleteTextView) getView().findViewById(R.id.autoCompleteTextView1);
		return rootView;
	}

	public void onCameraChange(CameraPosition arg0){
		// TODO Auto-generated method stub
	}

	public void onMapLongClick(LatLng arg0){
		llLoc = arg0;
		stCommand = "onTouchEvent";
		lp = new ExecuteTask();
		lp.execute();
	}

	public void onMapClick(LatLng arg0){
		// TODO Auto-generated method stub
	}

	class ExecuteTask extends AsyncTask<String, String, String> {
		@Override
		protected void onPreExecute(){
			super.onPreExecute();
			if(stCommand.compareTo("AutoCompleteTextView") != 0) {
				pDialog = new ProgressDialog(getActivity());
				pDialog.setMessage(Html.fromHtml("<b>Search</b><br/>Loading ..."));
				pDialog.setIndeterminate(false);
				pDialog.setCancelable(false);
				pDialog.show();
			}
		}

		protected String doInBackground(String ... args){
			do something
			return null;
		}

		@Override
		protected void onPostExecute(String file_url){
			if(stCommand.compareTo("AutoCompleteTextView") != 0) pDialog.dismiss();
			runOnUiThread(new Runnable() {
				public void run(){
					do something
				}
			});
		}
	}
	public void afterTextChanged(Editable s){
		// TODO Auto-generated method stub
	}

	public void beforeTextChanged(CharSequence s, int start, int count, int after){
		// TODO Auto-generated method stub
	}

	public void onTextChanged(CharSequence s, int start, int before, int count){
		// TODO Auto-generated method stub
	}
}

the error says: Eclipse Error

how can I fix this error?

Android Solutions


Solution 1 - Android

Try this: getActivity().runOnUiThread(new Runnable...

It's because:

  1. the implicit this in your call to runOnUiThread is referring to AsyncTask, not your fragment.

  2. Fragment doesn't have runOnUiThread.

However, Activity does.

Note that Activity just executes the Runnable if you're already on the main thread, otherwise it uses a Handler. You can implement a Handler in your fragment if you don't want to worry about the context of this, it's actually very easy:

// A class instance
private Handler mHandler = new Handler(Looper.getMainLooper());

// anywhere else in your code
mHandler.post(<your runnable>);
// ^ this will always be run on the next run loop on the main thread.

EDIT: @rciovati is right, you are in onPostExecute, that's already on the main thread.

Solution 2 - Android

Use a Kotlin extension function

fun Fragment?.runOnUiThread(action: () -> Unit) {
    this ?: return
    if (!isAdded) return // Fragment not attached to an Activity
    activity?.runOnUiThread(action)
}

Then, in any Fragment you can just call runOnUiThread. This keeps calls consistent across activities and fragments.

runOnUiThread {
    // Call your code here
}

> NOTE: If Fragment is no longer attached to an Activity, callback will not be called and no exception will be thrown

If you want to access this style from anywhere, you can add a common object and import the method:

object ThreadUtil {
    private val handler = Handler(Looper.getMainLooper())

    fun runOnUiThread(action: () -> Unit) {
        if (Looper.myLooper() != Looper.getMainLooper()) {
            handler.post(action)
        } else {
            action.invoke()
        }
    }
}

Solution 3 - Android

For Kotlin on fragment just do this

activity?.runOnUiThread(Runnable {
        //on main thread
    })

Solution 4 - Android

In Xamarin.Android

For Fragment:

this.Activity.RunOnUiThread(() => { yourtextbox.Text="Hello"; });

For Activity:

RunOnUiThread(() => { yourtextbox.Text="Hello"; });

Happy coding :-)

Solution 5 - Android

I used this for getting Date and Time in a fragment.

private Handler mHandler = new Handler(Looper.getMainLooper());
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    // Inflate the layout for this fragment
    View root = inflater.inflate(R.layout.fragment_head_screen, container, false);

    dateTextView =  root.findViewById(R.id.dateView);
    hourTv = root.findViewById(R.id.hourView);

        Thread thread = new Thread() {
        @Override
        public void run() {
            try {
                while (!isInterrupted()) {
                    Thread.sleep(1000);
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            //Calendario para obtener fecha & hora
                            Date currentTime = Calendar.getInstance().getTime();
                            SimpleDateFormat date_sdf = new SimpleDateFormat("dd/MM/yyyy");
                            SimpleDateFormat hour_sdf = new SimpleDateFormat("HH:mm a");

                            String currentDate = date_sdf.format(currentTime);
                            String currentHour = hour_sdf.format(currentTime);

                            dateTextView.setText(currentDate);
                            hourTv.setText(currentHour);
                        }
                    });
                }
            } catch (InterruptedException e) {
                Log.v("InterruptedException", e.getMessage());
            }
        }
    };
}

Solution 6 - Android

You can also post runnable using the view from any other thread. But be sure that the view is not null:

 tView.post(new Runnable() {
                    @Override
                    public void run() {
                        tView.setText("Success");
                    }
                });

According to the Documentation:

"boolean post (Runnable action) Causes the Runnable to be added to the message queue. The runnable will be run on the user interface thread."

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTai DaoView Question on Stackoverflow
Solution 1 - AndroidbclymerView Answer on Stackoverflow
Solution 2 - AndroidGiboltView Answer on Stackoverflow
Solution 3 - Androidpatel dhruvalView Answer on Stackoverflow
Solution 4 - AndroidRipdaman SinghView Answer on Stackoverflow
Solution 5 - AndroidIrving KennedyView Answer on Stackoverflow
Solution 6 - AndroidJawad ZebView Answer on Stackoverflow