runOnUiThread dalam fragmen

122

Saya mencoba mengonversi Aktivitas menjadi fragmen. Tanda kesalahan aktif runOnUiThread. di masa lalu:

GoogleActivityV2 diturunkan dari Aktivitas. runOnUiThread di kelas ExecuteTask. class ExecuteTask bertingkat pada aktivitas.

(Jalankan ok) sekarang:

GoogleActivityV2 diturunkan dari Fragment. runOnUiThread di kelas ExecuteTask. class ExecuteTask bertingkat pada aktivitas. (Kesalahan saat runOnUiThread)

ini kode saya

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

kesalahannya mengatakan: Eclipse Error

bagaimana cara memperbaiki kesalahan ini?

Tai Dao
sumber
8
Kode yang Anda tulis di dalam onPostExecute sudah berjalan di dalam utas utama. Di sisi lain, Anda tidak perlu menagih runOnUiThread ().
rciovati
@rciovati "lakukan sesuatu" di dalam dan di luar onPostExecute berbeda
Tai Dao

Jawaban:

272

Coba ini: getActivity().runOnUiThread(new Runnable...

Ini karena:

1) implisit thisdalam panggilan Anda ke runOnUiThreadmerujuk ke AsyncTask, bukan fragmen Anda.

2) Fragmenttidak memiliki runOnUiThread.

Namun, Activityapakah.

Perhatikan bahwa Activityhanya mengeksekusi Runnablejika Anda sudah berada di utas utama, jika tidak menggunakan fileHandler . Anda dapat menerapkan aHandler di fragmen Anda jika Anda tidak ingin mengkhawatirkan konteksnya this, sebenarnya sangat mudah:

// 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 benar, Anda sudah masuk onPostExecute , itu sudah di utas utama.

bclymer.dll
sumber
3
Kadang getActivity (). RunOnUiThread menghasilkan NullPointerException. Bisakah Anda menjelaskan?
developer1011
1
@ developer1011 yang akan terjadi jika fragmen telah dilepaskan dari aktivitas. Ini umum terjadi pada tugas asinkron, karena aktivitas bisa saja dimusnahkan selama operasi yang berjalan lama, sehingga tidak ada lagi untuk get. Selalu periksa nol terlebih dahulu.
bclymer
4
Terima kasih. Aku dikelilingi getActivity().runOnUiThreaddengan if (isAdded())dan bekerja dengan baik
developer1011
1
@bclymer dengan jawaban ini adalah referensi de facto di Google untuk utas UI dalam fragmen, beberapa detail lebih lanjut di bagian terakhir (cara mengimplementasikan Penangan yang menyelesaikan pekerjaan yang sama) akan menyenangkan!
LS97
4

Di Xamarin.Android

Untuk Fragmen:

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

Untuk Aktivitas:

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

Selamat membuat kode :-)

Ripdaman Singh
sumber
4

Gunakan fungsi ekstensi Kotlin

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

Kemudian, di mana saja FragmentAnda bisa menelepon runOnUiThread. Ini membuat panggilan tetap konsisten di seluruh aktivitas dan fragmen.

runOnUiThread {
    // Call your code here
}

CATATAN : Jika Fragmenttidak lagi dilampirkan ke Activity, callback tidak akan dipanggil dan tidak terkecuali akan dilempar

Jika Anda ingin mengakses gaya ini dari mana saja, Anda dapat menambahkan objek umum dan mengimpor metode:

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

    fun runOnUiThread(action: () -> Unit) {
        if (Looper.myLooper() != Looper.getMainLooper()) {
            handler.post(action)
        } else {
            action.invoke()
        }
    }
}
Gibolt
sumber
1
Saya sangat menyukai fungsi ekstensi kotlin.
OhhhThatVarun
2

Saya menggunakan ini untuk mendapatkan Tanggal dan Waktu dalam sebuah fragmen.

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
sumber
1

Anda juga dapat memposting runnable menggunakan tampilan dari utas lainnya. Tetapi pastikan bahwa tampilan tersebut tidak null:

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

Menurut Dokumentasi:

"posting boolean (tindakan Runnable) Menyebabkan Runnable ditambahkan ke antrian pesan. Runnable akan dijalankan pada thread antarmuka pengguna."

Jawad Zeb
sumber