runOnUiThread dans un fragment

122

J'essaye de convertir une activité en fragment. La marque d'erreur sur runOnUiThread. Sur le passé:

GoogleActivityV2 s'étend de l'activité. runOnUiThread dans la classe ExecuteTask. class ExecuteTask imbriqué sur l'activité.

(Exécutez ok) maintenant:

GoogleActivityV2 s'étend de Fragment. runOnUiThread dans la classe ExecuteTask. class ExecuteTask imbriqué sur l'activité. (Erreur sur runOnUiThread)

voici mon 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
    }
}

l'erreur dit: Erreur Eclipse

comment puis-je corriger cette erreur?

Tai Dao
la source
8
Le code que vous écrivez dans onPostExecute est déjà exécuté dans le thread principal. D'un autre côté, vous n'avez pas besoin de facturer runOnUiThread ().
rciovati
@rciovati "faire quelque chose" dans et hors sur PostExecute sont différents
Tai Dao

Réponses:

272

Essaye ça: getActivity().runOnUiThread(new Runnable...

C'est parce que:

1) l'implicite thisdans votre appel runOnUiThreadfait référence à AsyncTask, pas à votre fragment.

2) Fragmentn'a pas runOnUiThread.

Cependant, le Activityfait.

Notez qu'il Activityexécute simplement le Runnablesi vous êtes déjà sur le thread principal, sinon il utilise un Handler. Vous pouvez implémenter aHandler dans votre fragment si vous ne voulez pas vous soucier du contexte de this, c'est en fait très simple:

// 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 a raison, vous y êtes onPostExecute, c'est déjà sur le fil principal.

bclymer
la source
3
Parfois, getActivity (). RunOnUiThread entraîne NullPointerException. Pourriez-vous expliquer?
developer1011
1
@ developer1011 qui se produira lorsque le fragment aura été détaché de l'activité. Ceci est courant dans les tâches asynchrones, car l'activité aurait pu être détruite pendant l'opération de longue durée, de sorte qu'elle n'existe plus get. Vérifiez toujours la valeur null en premier.
bclymer
4
Merci. J'entouré getActivity().runOnUiThreadavec if (isAdded())et il fonctionne très bien
developer1011
1
@bclymer étant donné cette réponse est la référence de facto sur Google pour les threads d'interface utilisateur en fragments, un peu plus de détails sur la dernière section (comment implémenter un gestionnaire qui fait le même travail) serait bien!
LS97
4

Dans Xamarin.Android

Pour le fragment:

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

Pour l'activité:

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

Bon codage :-)

Ripdaman Singh
la source
4

Utiliser une fonction d'extension Kotlin

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

Ensuite, dans tout Fragmentce que vous pouvez simplement appeler runOnUiThread. Cela maintient les appels cohérents entre les activités et les fragments.

runOnUiThread {
    // Call your code here
}

REMARQUE : si Fragmentn'est plus attaché à un Activity, le rappel ne sera pas appelé et aucune exception ne sera levée

Si vous souhaitez accéder à ce style de n'importe où, vous pouvez ajouter un objet commun et importer la méthode:

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

    fun runOnUiThread(action: () -> Unit) {
        if (Looper.myLooper() != Looper.getMainLooper()) {
            handler.post(action)
        } else {
            action.invoke()
        }
    }
}
Gibolt
la source
1
J'adore les fonctions d'extensions de kotlin.
OhhhThatVarun
2

J'ai utilisé ceci pour obtenir la date et l'heure dans un 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());
            }
        }
    };
}
Irving Kennedy
la source
1

Vous pouvez également publier des articles exécutables en utilisant la vue de n'importe quel autre fil de discussion. Mais assurez-vous que la vue n'est pas nulle:

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

Selon la documentation:

"Boolean post (action Runnable) Provoque l'ajout du Runnable à la file d'attente des messages. Le runnable sera exécuté sur le thread de l'interface utilisateur."

Jawad Zeb
la source