runOnUiThread ในแฟรกเมนต์


122

ฉันกำลังพยายามแปลงกิจกรรมเป็นส่วนย่อย runOnUiThreadเครื่องหมายข้อผิดพลาดใน ในอดีต:

GoogleActivityV2 ขยายจากกิจกรรม runOnUiThread ในคลาส ExecuteTask คลาส ExecuteTask ซ้อนอยู่บนกิจกรรม

(รันตกลง) ตอนนี้:

GoogleActivityV2 ขยายจาก Fragment runOnUiThread ในคลาส ExecuteTask คลาส ExecuteTask ซ้อนอยู่บนกิจกรรม (ข้อผิดพลาดใน runOnUiThread)

นี่คือรหัสของฉัน

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

ข้อผิดพลาดระบุว่า: ข้อผิดพลาด Eclipse

ฉันจะแก้ไขข้อผิดพลาดนี้ได้อย่างไร


8
โค้ดที่คุณเขียนภายใน onPostExecute ทำงานอยู่แล้วภายในเธรดหลัก ในทางกลับกันคุณไม่จำเป็นต้องเรียกใช้ runOnUiThread ()
rciovati

@rciovati "do something" in and out onPostExecute are different
Tai Dao

คำตอบ:


272

ลองสิ่งนี้: getActivity().runOnUiThread(new Runnable...

มันเป็นเพราะว่า:

1) นัยthisในการโทรของคุณrunOnUiThreadหมายถึง AsyncTask ไม่ใช่ส่วนของคุณ

2) Fragmentไม่มี runOnUiThread

อย่างไรก็ตามActivityไม่

โปรดทราบว่าActivityเพียงดำเนินการRunnableถ้าคุณอยู่ในเธรดหลักอยู่แล้วมิฉะนั้นจะใช้ไฟล์Handler. คุณสามารถใช้งานHandlerในส่วนของคุณได้หากคุณไม่ต้องการกังวลเกี่ยวกับบริบทของthisมันจริง ๆ แล้วมันง่ายมาก:

// 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.

แก้ไข: @rciovati ถูกต้องคุณอยู่ในonPostExecuteหัวข้อหลักแล้ว


3
บางครั้ง getActivity (). runOnUiThread ส่งผลให้เป็น NullPointerException คุณช่วยอธิบายได้ไหม
พัฒนา

1
@ developer1011 ที่จะเกิดขึ้นเมื่อชิ้นส่วนถูกแยกออกจากกิจกรรม นี้เป็นเรื่องธรรมดาในงาน async getเพราะกิจกรรมจะได้รับการทำลายในระหว่างการดำเนินการระยะยาวดังนั้นจึงไม่มีอยู่อีกต่อไป ตรวจสอบค่าว่างก่อนเสมอ
bclymer

4
ขอบคุณ ฉันล้อมรอบไปgetActivity().runOnUiThreadด้วยif (isAdded())และทำงานดี
developer1011

1
@bclymer ให้คำตอบนี้เป็นการอ้างอิงโดยพฤตินัยบน Google สำหรับเธรด UI ในส่วนย่อยรายละเอียดเพิ่มเติมบางส่วนในส่วนสุดท้าย (วิธีใช้ Handler ที่ได้งานเดียวกัน) จะดีมาก!
LS97

4

ใน Xamarin Android

สำหรับ Fragment:

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

สำหรับกิจกรรม:

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

มีความสุขในการเข้ารหัส :-)


4

ใช้ฟังก์ชันส่วนขยาย Kotlin

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

จากนั้นFragmentคุณสามารถโทรrunOnUiThreadได้ทุกเมื่อ สิ่งนี้ช่วยให้การโทรสอดคล้องกันในกิจกรรมและส่วนต่างๆ

runOnUiThread {
    // Call your code here
}

หมายเหตุ : หากFragmentไม่ได้เชื่อมต่อกับ an อีกต่อไปจะไม่มีการActivityโทรกลับและจะไม่มีข้อยกเว้นใด ๆ เกิดขึ้น

หากคุณต้องการเข้าถึงสไตล์นี้จากทุกที่คุณสามารถเพิ่มวัตถุทั่วไปและนำเข้าวิธีการ:

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

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

1
ฉันชอบฟังก์ชั่นส่วนขยายของ kotlin มาก
OhhhThatVarun

2

ฉันใช้สิ่งนี้เพื่อรับวันที่และเวลาในส่วนย่อย

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

คุณยังสามารถโพสต์รันได้โดยใช้มุมมองจากเธรดอื่น แต่ต้องแน่ใจว่ามุมมองนั้นไม่เป็นโมฆะ:

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

ตามเอกสาร:

"boolean post (Runnable action) ทำให้ Runnable ถูกเพิ่มลงในคิวข้อความ runnable จะถูกรันบนเธรดส่วนต่อประสานผู้ใช้"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.