runOnUiThread in fragment


121

Sto cercando di convertire un'attività in frammento. Il segno di errore su runOnUiThread. sul passato:

GoogleActivityV2 si estende da Activity. runOnUiThread nella classe ExecuteTask. class ExecuteTask annidato sull'attività.

(Corri ok) ora:

GoogleActivityV2 si estende da Fragment. runOnUiThread nella classe ExecuteTask. class ExecuteTask annidato sull'attività. (Errore su runOnUiThread)

ecco il mio codice

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'errore dice: Errore di Eclipse

come posso correggere questo errore?


8
Il codice che scrivi in ​​onPostExecute è già stato eseguito nel thread principale. D'altra parte, non è necessario fatturare runOnUiThread ().
rciovati

@rciovati "fai qualcosa" dentro e fuori su PostExecute sono diversi
Tai Dao,

Risposte:


271

Prova questo: getActivity().runOnUiThread(new Runnable...

È perchè:

1) l'implicito thisnella tua chiamata a runOnUiThreadsi riferisce ad AsyncTask, non al tuo frammento.

2) Fragmentnon ha runOnUiThread.

Tuttavia, lo Activityfa.

Nota che Activityesegue solo il Runnablese sei già nel thread principale, altrimenti usa un file Handler. Puoi implementare unHandler nel tuo frammento se non vuoi preoccuparti del contesto di this, in realtà è molto semplice:

// 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 ha ragione, sei dentro onPostExecute, è già nel thread principale.


3
Alcune volte getActivity (). RunOnUiThread risulta in NullPointerException. Potresti spiegare?
sviluppatore

1
@ developer1011 che accadrà quando il frammento è stato scollegato dall'attività. Questo è comune nelle attività asincrone, perché l'attività avrebbe potuto essere distrutta durante l'operazione di lunga durata, quindi non esiste più get. Prima controlla sempre la presenza di null.
bclymer

4
Grazie. I circondato getActivity().runOnUiThreadcon if (isAdded())e funziona bene
developer1011

1
@bclymer data questa risposta è il riferimento de facto su Google per il thread dell'interfaccia utente in frammenti, qualche dettaglio in più sull'ultima sezione (come implementare un gestore che esegue lo stesso lavoro) sarebbe bello!
LS97

4

In Xamarin.Android

Per frammento:

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

Per attività:

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

Buona programmazione :-)


4

Usa una funzione di estensione Kotlin

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

Quindi, in ogni caso Fragmentpuoi semplicemente chiamare runOnUiThread. Ciò mantiene le chiamate coerenti tra attività e frammenti.

runOnUiThread {
    // Call your code here
}

NOTA : se Fragmentnon è più collegato a un Activity, la richiamata non verrà chiamata e non verrà generata alcuna eccezione

Se vuoi accedere a questo stile da qualsiasi luogo, puoi aggiungere un oggetto comune e importare il metodo:

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

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

1
Adoro le funzioni delle estensioni di kotlin.
OhhhThat Varun

2

L'ho usato per ottenere data e ora in un frammento.

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

1

Puoi anche post eseguibile utilizzando la vista da qualsiasi altro thread. Ma assicurati che la vista non sia nulla:

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

Secondo la documentazione:

"boolean post (Runnable action) Causa l'aggiunta del Runnable alla coda dei messaggi. Il runnable verrà eseguito sul thread dell'interfaccia utente."

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.