เราจะใช้ runOnUiThread ใน Android ได้อย่างไร


157

ฉันใหม่สำหรับ Android และฉันพยายามใช้ UI-Thread ดังนั้นฉันจึงเขียนกิจกรรมทดสอบอย่างง่าย แต่ฉันคิดว่าฉันเข้าใจผิดบางอย่างเพราะเมื่อคลิกปุ่ม - แอพไม่ตอบสนองอีกต่อไป

public class TestActivity extends Activity {

    Button btn;
    int i = 0;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btn = (Button)findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                runThread();
            }
        });
    }

    private void runThread(){
        runOnUiThread (new Thread(new Runnable() {  
            public void run() {
                while(i++ < 1000){
                    btn.setText("#"+i);
                    try {
                        Thread.sleep(300);
                    } 
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
             }
        }));
    }
}

คำตอบ:


204

ด้านล่างได้รับการแก้ไขส่วนของrunThreadฟังก์ชั่น

private void runThread() {

    new Thread() {
        public void run() {
            while (i++ < 1000) {
                try {
                    runOnUiThread(new Runnable() {

                        @Override
                        public void run() {
                            btn.setText("#" + i);
                        }
                    });
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }.start();
}

นี่ไม่ใช่ขยะที่ถูกรวบรวมเกือบจะทันทีหรือ อาจเป็นไปได้ว่าคุณจำเป็นต้องอ้างอิงถึง Thread ()
Nick

14
@Nick: ตัวเก็บรวบรวมขยะจะเฝ้าดูสแต็กเช่นเมื่อเธรดกำลังทำงานจะไม่ได้รับ GC'ed
Miro Kropacek

@Vipul ฉันมีคำถามเกี่ยวกับการหมุนโทรศัพท์: ฉันต้องการเมื่อฉันหมุนโทรศัพท์ของฉันเธรดนี้จะทำงานและไม่มีการสร้างเธรดใหม่ คุณสามารถให้คำแนะนำเกี่ยวกับวิธีป้องกันการสร้างเธรดใหม่เมื่อหมุนโทรศัพท์ได้หรือไม่
user1836957

89

เพียงแค่ห่อเป็นฟังก์ชันแล้วเรียกใช้ฟังก์ชันนี้จากเธรดพื้นหลังของคุณ

public void debugMsg(String msg) {
    final String str = msg;
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mInfo.setText(str);
        }
    });
}

3
upvoted สำหรับแสดงวิธีการเข้าถึงข้อมูลในขอบเขตด้านนอก ( final)
mariotomo

27

คุณมีมันกลับไปด้านหน้า การคลิกปุ่มของคุณส่งผลให้มีการโทรถึงrunOnUiThread()แต่ไม่จำเป็นเนื่องจากตัวจัดการการคลิกทำงานอยู่บนเธรด UI แล้ว จากนั้นรหัสของคุณในrunOnUiThread()กำลังเรียกใช้เธรดพื้นหลังใหม่ซึ่งคุณพยายามทำการดำเนินการกับ UI ซึ่งจะล้มเหลว

เพียงแค่เปิดตัวเธรดพื้นหลังโดยตรงจากตัวจัดการการคลิกของคุณ จากนั้นตัดสายไปภายในการเรียกไปยังbtn.setText()runOnUiThread()


ในขณะที่เป็นจริงที่ตัวจัดการการคลิกอยู่ในเธรด UI อยู่แล้วการเรียกไปยังrunOnUiThread()ไม่จำเป็น แต่ก็ไม่เป็นอันตราย Javadoc สำหรับวิธีการนั้นระบุว่า "เรียกใช้การดำเนินการที่ระบุบนเธรด UI หากเธรดปัจจุบันคือเธรด UI การดำเนินการจะดำเนินการทันทีถ้าเธรดปัจจุบันไม่ใช่เธรด UI การดำเนินการจะถูกโพสต์ลงในคิวเหตุการณ์ ของเธรด UI "
k2col


10

มีหลายเทคนิคในการใช้ runOnUiThread () ให้ดูทั้งหมด

นี่คือเธรดหลักของฉัน (เธรด UI) เรียกว่าAndroidBasicThreadActivityและฉันจะอัปเดตจากเธรดผู้ปฏิบัติงานด้วยวิธีต่างๆ -

public class AndroidBasicThreadActivity extends AppCompatActivity
{
    public static TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_android_basic_thread);

        textView = (TextView) findViewById(R.id.textview);

        MyAndroidThread myTask = new MyAndroidThread(AndroidBasicThreadActivity.this);
        Thread t1 = new Thread(myTask, "Bajrang");
        t1.start();
    }
}

1. ) โดยผ่านอินสแตนซ์ของกิจกรรมเป็นอาร์กิวเมนต์บนเธรดผู้ปฏิบัติงาน

class MyAndroidThread implements Runnable
{
    Activity activity;
    public MyAndroidThread(Activity activity)
    {
        this.activity = activity;
    }
    @Override
    public void run()
    {

        //perform heavy task here and finally update the UI with result this way - 
        activity.runOnUiThread(new Runnable()
        {
            @Override
            public void run()
            {
                AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
            }
        });
    }
}

2. ) โดยใช้วิธีการโพสต์ของมุมมอง (Runnable runnable) ในเธรดผู้ปฏิบัติงาน

class MyAndroidThread implements Runnable
{
    Activity activity;
    public MyAndroidThread(Activity activity)
    {
        this.activity = activity;
    }
    @Override
    public void run()
    {
     //perform heavy task here and finally update the UI with result this way - 
       AndroidBasicThreadActivity.textView.post(new Runnable()
      { 
        @Override
        public void run()
        {
            AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
        }
    });

    }
}

3. ) โดยใช้คลาส Handler จากแพ็คเกจ android.os หากเราไม่มีบริบท (นี่ / getApplicationContext ()) หรืออินสแตนซ์ของกิจกรรม (AndroidBasicThreadActivity.this) จากนั้นเราต้องใช้คลาส Handler ด้านล่าง -

class MyAndroidThread implements Runnable
{
    Activity activity;
    public MyAndroidThread(Activity activity)
    {
        this.activity = activity;
    }
    @Override
   public void run()
  {
  //perform heavy task here and finally update the UI with result this way - 
  new Handler(Looper.getMainLooper()).post(new Runnable() {
        public void run() {
            AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread.");
        }
    });
  }
}

ขอบคุณ .. แทนที่จะทำซ้ำเกี่ยวกับ runOnUIT ข้อความกิจกรรมคุณได้พูดถึงวิธีการที่เป็นไปได้ทั้งหมดในการเรียกใช้ ..
arun

ขอบคุณ .. แทนที่จะทำซ้ำเกี่ยวกับ runOnUIT ข้อความกิจกรรมคุณได้พูดถึงวิธีการที่เป็นไปได้ทั้งหมดในการเรียกใช้ ..
arun

6

หากใช้ในส่วนแล้วก็เขียน

getActivity().runOnUiThread(new Runnable() {
    @Override
    public void run() {
        // Do something on UiThread
    }
});

1

เจ้านี้:

@UiThread
    public void logMsg(final String msg) {
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                Log.d("UI thread", "I am the UI thread");


            }
        });
    }

1

เราใช้เธรดผู้ทำงานเพื่อทำให้แอปราบรื่นและหลีกเลี่ยงการใช้ ANR เราอาจจำเป็นต้องอัปเดต UI หลังจากกระบวนการหนักในดอกยางของผู้ปฏิบัติงาน UI สามารถอัปเดตได้จาก UI Thread เท่านั้น ในกรณีเช่นนี้เราใช้ Handler หรือ runOnUiThread ทั้งคู่มีเมธอด Runnable ที่รันใน UI Thread เมธอด onClick ทำงานในเธรด UI ดังนั้นไม่จำเป็นต้องใช้ runOnUiThread ที่นี่

ใช้ Kotlin

ขณะที่อยู่ในกิจกรรม

this.runOnUiThread {
      // Do stuff
}

จากส่วน

activity?.runOnUiThread {
      // Do stuff
}

โดยใช้ Java ,

this.runOnUiThread(new Runnable() {
     void run() {
         // Do stuff
     }
});

0

คุณสามารถใช้จากตัวอย่างนี้:

ในตัวอย่างต่อไปนี้เราจะใช้เครื่องมือนี้เพื่อเผยแพร่ผลลัพธ์จากการค้นหาคำพ้องที่ประมวลผลโดยเธรดพื้นหลัง

เพื่อให้บรรลุเป้าหมายในระหว่างการเรียกกลับกิจกรรม OnCreate เราจะตั้งค่า onClickListener เพื่อรัน searchTask บนเธรดที่สร้างขึ้น

เมื่อผู้ใช้คลิกที่ปุ่มค้นหาเราจะสร้างคลาสที่ไม่ระบุชื่อ Runnable ที่ค้นหาคำที่พิมพ์ใน R.id.wordEt EditText และเริ่มด้ายเพื่อรัน Runnable

เมื่อการค้นหาเสร็จสิ้นเราจะสร้างตัวอย่างของ Runnable SetSynonymResult เพื่อเผยแพร่ผลลัพธ์กลับมาที่ synonym TextView บนเธรด UI

เทคนิคนี้บางครั้งไม่ใช่วิธีที่สะดวกที่สุดโดยเฉพาะเมื่อเราไม่สามารถเข้าถึงอินสแตนซ์ของกิจกรรมได้ ดังนั้นในบทต่อไปนี้เราจะหารือเกี่ยวกับเทคนิคที่ง่ายและสะอาดขึ้นเพื่ออัปเดต UI จากงานคำนวณพื้นหลัง

public class MainActivity extends AppCompatActivity {

    class SetSynonymResult implements Runnable {
        String synonym;

        SetSynonymResult(String synonym) {
            this.synonym = synonym;
        }

        public void run() {
            Log.d("AsyncAndroid", String.format("Sending synonym result %s on %d",
                    synonym, Thread.currentThread().getId()) + " !");
            TextView tv = (TextView) findViewById(R.id.synonymTv);
            tv.setText(this.synonym);
        }
    }

    ;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button search = (Button) findViewById(R.id.searchBut);
        final EditText word = (EditText) findViewById(R.id.wordEt);
        search.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Runnable searchTask = new Runnable() {
                    @Override
                    public void run() {
                        String result = searchSynomim(word.getText().toString());
                        Log.d("AsyncAndroid", String.format("Searching for synonym for %s on %s",
                                word.getText(), Thread.currentThread().getName()));
                        runOnUiThread(new SetSynonymResult(result));
                    }
                };
                Thread thread = new Thread(searchTask);
                thread.start();
            }
        });

    }

    static int i = 0;

    String searchSynomim(String word) {
        return ++i % 2 == 0 ? "fake" : "mock";
    }
}

ที่มา :

การเขียนโปรแกรม Android ไม่ตรงกัน Helder Vasconcelos



0
  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        gifImageView = (GifImageView) findViewById(R.id.GifImageView);
        gifImageView.setGifImageResource(R.drawable.success1);

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //dummy delay for 2 second
                    Thread.sleep(8000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                //update ui on UI thread
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        gifImageView.setGifImageResource(R.drawable.success);
                    }
                });

            }
        }).start();

    }

0

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

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

1) นัยนี้ในการเรียกใช้งานOnUiThreadของคุณหมายถึงAsyncTaskไม่ใช่ส่วนของคุณ

2) แฟรกเมนต์ไม่มี runOnUiThread

อย่างไรก็ตามกิจกรรมทำ

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

// คลาสของอินสแตนซ์

private Handler mHandler = new Handler(Looper.getMainLooper());

// ที่ไหนก็ได้ในรหัสของคุณ

mHandler.post(<your runnable>);

// ^ นี่จะถูกเรียกใช้เสมอในการวนรอบถัดไปบนเธรดหลัก

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