คุณแสดง Toast จากเธรดพื้นหลังบน Android ได้อย่างไร?


คำตอบ:


246

คุณสามารถทำได้โดยเรียกActivity's runOnUiThreadวิธีจากหัวข้อของคุณ:

activity.runOnUiThread(new Runnable() {
    public void run() {
        Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
    }
});

ฉันไม่แน่ใจว่าฉันเข้าใจวิธีการทำเช่นนี้ ฉันมีการรันโมฆะสาธารณะ () ที่มีอยู่แล้ว ฉันลองใส่รหัสนี้ที่นั่น ฉันรู้ว่ามันไม่ถูกต้องเพราะมันไม่ได้ผล แต่ฉันติดอยู่จริงๆ
SwimBikeRun

14
"activity" ถูกส่งต่อไปยัง non-ui-thread ในตัวสร้างหรือไม่ วิธีที่ถูกต้องในการรับวัตถุกิจกรรมที่คุณใช้จากภายในเธรดแยกคืออะไร?
snapfractalpop

ตั้งค่าThreadการอ้างอิงของวัตถุไปActivityใน'sActivity onResumeยกเลิกการกำหนดไว้ใน'sActivity onPauseทำทั้งสองอย่างภายใต้การsynchronizedล็อคที่ทั้งเคารพActivityและThreadเคารพ
JohnnyLambada

5
บางครั้งไม่มีการเข้าถึงActivityอินสแตนซ์คุณสามารถใช้คลาสตัวช่วยธรรมดาแทนได้ดูที่นี่: stackoverflow.com/a/18280318/1891118
Oleksii K.

5
ฉันมักจะพบว่าMyActivity.this.runOnUiThread()ผลงานได้ดีจากภายในภายใน/Thread AsyncTask
Anthony Atkinson

62

ชอบมีวิธีการในกิจกรรมที่เรียกว่าshowToastเรียกได้จากทุกที่ ...

public void showToast(final String toast)
{
    runOnUiThread(() -> Toast.makeText(MyActivity.this, toast, Toast.LENGTH_SHORT).show());
}

จากนั้นฉันมักจะเรียกมันจากภายในMyActivityในหัวข้อแบบนี้ ...

showToast(getString(R.string.MyMessage));

3
ขอบคุณตอนนี้ฉันกำลังเพิ่มกิจกรรมนี้มากที่สุด
Gene Myers

1
สำหรับ TOAST ให้ใช้ Application Context เสมอไม่ใช่ Activity Context!
Yousha Aleayoub

1
@YoushaAleayoub ทำไม?
OneWorld

1
@OneWorld บทพิสูจน์: 1- สำหรับข้อความขนมปังคู่มือนักพัฒนาของ Google ใช้บริบทของแอปพลิเคชันและบอกว่าจะใช้อย่างชัดเจน 2- stackoverflow.com/a/4128799/1429432 3- stackoverflow.com/a/10347346/1429432 4- groups.google.com/d/msg/android-developers/3i8M6-wAIwM/…
Yousha Aleayoub

@YoushaAleayoub มีการอภิปรายและการคาดเดามากมายในลิงค์ที่คุณให้มา เช่น RomainGuy บอกว่าไม่มีหน่วยความจำรั่วในหลักฐานของคุณ 4. ลิงก์บางส่วนมาจากยุคแรก ๆ ของ Android ในปี 2009 นอกจากนี้ผู้คนยังพูดในลิงก์อื่น ๆ ว่าคุณสามารถใช้ทั้งสองบริบทได้ กิจกรรมและการใช้งาน บางทีคุณอาจมีหลักฐานจริงที่เป็นปัจจุบันมากขึ้น? คุณมีลิงค์สำหรับ 1 หรือไม่?
OneWorld

28

สิ่งนี้คล้ายกับคำตอบอื่น ๆ อย่างไรก็ตามได้รับการอัปเดตสำหรับ apis ใหม่และสะอาดกว่ามาก นอกจากนี้อย่าถือว่าคุณอยู่ในบริบทกิจกรรม

public class MyService extends AnyContextSubclass {

    public void postToastMessage(final String message) {
        Handler handler = new Handler(Looper.getMainLooper());

        handler.post(new Runnable() {

            @Override
            public void run() {
                Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
            }
        });
    }
}

เมื่อบริบทที่คุณมีไม่ใช่กิจกรรมที่เป็นคำตอบที่สมบูรณ์แบบ ขอบคุณมาก!
francas

17

แนวทางหนึ่งที่ใช้ได้จากทุกที่รวมทั้งจากสถานที่ที่คุณไม่มีActivityหรือViewคือการหยิบHandlerไปที่เธรดหลักและแสดงขนมปังปิ้ง:

public void toast(final Context context, final String text) {
  Handler handler = new Handler(Looper.getMainLooper());
  handler.post(new Runnable() {
    public void run() {
      Toast.makeText(context, text, Toast.LENGTH_LONG).show();
    }
  });
}

ข้อดีของวิธีนี้คือการที่จะทำงานร่วมกับใด ๆContextรวมทั้งและServiceApplication


10

เช่นนี้หรือสิ่งนี้พร้อมกับRunnableที่แสดงไฟล์Toast. กล่าวคือ

Activity activity = // reference to an Activity
// or
View view = // reference to a View

activity.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        showToast(activity);
    }
});
// or
view.post(new Runnable() {
    @Override
    public void run() {
        showToast(view.getContext());
    }
});

private void showToast(Context ctx) {
    Toast.makeText(ctx, "Hi!", Toast.LENGTH_SHORT).show();
}

6

บางครั้งคุณต้องส่งข้อความจากที่อื่นThreadไปยังเธรด UI สถานการณ์ประเภทนี้เกิดขึ้นเมื่อคุณไม่สามารถเรียกใช้การดำเนินการเครือข่าย / IO บนเธรด UI

ตัวอย่างด้านล่างจัดการสถานการณ์นั้น

  1. คุณมีเธรด UI
  2. คุณต้องเริ่มการดำเนินการ IO และด้วยเหตุนี้คุณจึงไม่สามารถรันRunnableบนเธรด UI ได้ ดังนั้นโพสต์ของคุณRunnableเพื่อจัดการในHandlerThread
  3. รับผลลัพธ์จากRunnableและส่งกลับไปที่เธรด UI และแสดงToastข้อความ

สารละลาย:

  1. สร้างHandlerThreadและเริ่มต้น
  2. สร้างHandlerด้วยLooperจากHandlerThread:requestHandler
  3. สร้าง Handler ด้วย Looper จาก Main Thread: responseHandlerและ override handleMessagemethod
  4. postRunnableงานในrequestHandler
  5. ภายในRunnableงานโทรsendMessageบนresponseHandler
  6. sendMessageผลลัพธ์นี้เรียกใช้handleMessageในresponseHandler.
  7. รับแอตทริบิวต์จากMessageและประมวลผลอัปเดต UI

โค้ดตัวอย่าง:

    /* Handler thread */

    HandlerThread handlerThread = new HandlerThread("HandlerThread");
    handlerThread.start();
    Handler requestHandler = new Handler(handlerThread.getLooper());

    final Handler responseHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            //txtView.setText((String) msg.obj);
            Toast.makeText(MainActivity.this,
                    "Runnable on HandlerThread is completed and got result:"+(String)msg.obj,
                    Toast.LENGTH_LONG)
                    .show();
        }
    };

    for ( int i=0; i<5; i++) {
        Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                try {

                    /* Add your business logic here and construct the 
                       Messgae which should be handled in UI thread. For 
                       example sake, just sending a simple Text here*/

                    String text = "" + (++rId);
                    Message msg = new Message();

                    msg.obj = text.toString();
                    responseHandler.sendMessage(msg);
                    System.out.println(text.toString());

                } catch (Exception err) {
                    err.printStackTrace();
                }
            }
        };
        requestHandler.post(myRunnable);
    }

บทความที่เป็นประโยชน์:

handlerthreads และเหตุผลที่คุณควรจะกำลังจะใช้-พวกเขาในของคุณหุ่นยนต์ปพลิเคชัน

หุ่นยนต์ Looper จัดการ-handlerthread ฉัน


5
  1. รับอินสแตนซ์ UI Thread Handler และใช้งาน handler.sendMessage();
  2. post()วิธีการโทรhandler.post();
  3. runOnUiThread()
  4. view.post()

3

คุณสามารถใช้Looperเพื่อส่งToastข้อความ ดูรายละเอียดเพิ่มเติมผ่านลิงค์นี้

public void showToastInThread(final Context context,final String str){
    Looper.prepare();
    MessageQueue queue = Looper.myQueue();
    queue.addIdleHandler(new IdleHandler() {
         int mReqCount = 0;

         @Override
         public boolean queueIdle() {
             if (++mReqCount == 2) {
                  Looper.myLooper().quit();
                  return false;
             } else
                  return true;
         }
    });
    Toast.makeText(context, str,Toast.LENGTH_LONG).show();      
    Looper.loop();
}

และถูกเรียกในชุดข้อความของคุณ บริบทอาจได้Activity.getContext()รับจากการที่Activityคุณต้องแสดงขนมปังปิ้ง


2

ฉันทำแนวทางนี้ตามคำตอบของ mjaggard:

public static void toastAnywhere(final String text) {
    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(new Runnable() {
        public void run() {
            Toast.makeText(SuperApplication.getInstance().getApplicationContext(), text, 
                    Toast.LENGTH_LONG).show();
        }
    });
}

ทำงานได้ดีสำหรับฉัน


0

ฉันพบปัญหาเดียวกัน:

E/AndroidRuntime: FATAL EXCEPTION: Thread-4
              Process: com.example.languoguang.welcomeapp, PID: 4724
              java.lang.RuntimeException: Can't toast on a thread that has not called Looper.prepare()
                  at android.widget.Toast$TN.<init>(Toast.java:393)
                  at android.widget.Toast.<init>(Toast.java:117)
                  at android.widget.Toast.makeText(Toast.java:280)
                  at android.widget.Toast.makeText(Toast.java:270)
                  at com.example.languoguang.welcomeapp.MainActivity$1.run(MainActivity.java:51)
                  at java.lang.Thread.run(Thread.java:764)
I/Process: Sending signal. PID: 4724 SIG: 9
Application terminated.

ก่อน: ฟังก์ชัน onCreate

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        Toast.makeText(getBaseContext(), "Thread", Toast.LENGTH_LONG).show();
    }
});
thread.start();

After: ฟังก์ชัน onCreate

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        Toast.makeText(getBaseContext(), "Thread", Toast.LENGTH_LONG).show();
    }
});

มันได้ผล

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