ไม่สามารถสร้างตัวจัดการภายในเธรดที่ไม่ได้เรียกว่า Looper.prepare ()


981

ข้อยกเว้นต่อไปนี้หมายความว่าอย่างไร ฉันจะแก้ไขได้อย่างไร

นี่คือรหัส:

Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);

นี่คือข้อยกเว้น:

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
     at android.os.Handler.<init>(Handler.java:121)
     at android.widget.Toast.<init>(Toast.java:68)
     at android.widget.Toast.makeText(Toast.java:231)

8
ตรวจสอบไลบรารี่นี้compile 'com.shamanland:xdroid-toaster:0.0.5'มันไม่จำเป็นต้องมีrunOnUiThread()หรือContextเปลี่ยนแปลงรูทีนทั้งหมดหายไป เพียงแค่เรียกToaster.toast(R.string.my_msg);นี่คือตัวอย่าง: github.com/shamanland/xdroid-toaster-example
Oleksii K.

120
ข้อความแสดงข้อผิดพลาดโง่อะไร! มันอาจเป็นเรื่องง่ายเหมือน - ไม่สามารถเรียกสิ่งนี้จากเธรดที่ไม่ใช่ UI ได้เช่นเดียวกับเมื่อมีการแตะมุมมองจากเธรดที่ไม่ใช่ UI
Dheeraj Bhaskar

11
สำหรับผู้ที่ได้รับข้อความข้อยกเว้นเดียวกันจากรหัสที่แตกต่างกัน: ข้อความข้อยกเว้นหมายความว่าคุณกำลังเรียกใช้รหัสผ่านทางเธรดที่ไม่ได้เตรียม Looper โดยปกติแล้วหมายความว่าคุณไม่ได้โทรจากเธรด UI แต่คุณควร (กรณีของ OP) - เธรดปกติไม่ได้เตรียม Looper แต่เธรด UI จะทำเสมอ
Helin Wang

@OleksiiKropachov การติดตั้งไลบรารี่ที่คุณกล่าวถึงนั้นคล้ายกับการทำ runOnUiThread ()
Helin Wang

ใช่ แต่มันเป็นเสื้อคลุมที่มีประโยชน์มาก
Oleksii K.

คำตอบ:


696

คุณกำลังโทรจากเธรดผู้ปฏิบัติงาน คุณต้องโทรToast.makeText()(และฟังก์ชั่นอื่น ๆ ส่วนใหญ่ที่เกี่ยวข้องกับ UI) จากภายในเธรดหลัก คุณสามารถใช้ตัวจัดการตัวอย่างเช่น

ค้นหาการสื่อสารกับ UI Threadในเอกสารประกอบ โดยสังเขป:

// Set this up in the UI thread.

mHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message message) {
        // This is where you do your work in the UI thread.
        // Your worker tells you in the message what to do.
    }
};

void workerThread() {
    // And this is how you call it from the worker thread:
    Message message = mHandler.obtainMessage(command, parameter);
    message.sendToTarget();
}

ตัวเลือกอื่น:

คุณสามารถใช้AsyncTaskซึ่งทำงานได้ดีสำหรับสิ่งที่ทำงานส่วนใหญ่ในพื้นหลัง มีตะขอที่คุณสามารถโทรเพื่อระบุความคืบหน้าและเมื่อเสร็จแล้ว

นอกจากนี้คุณยังสามารถใช้Activity.runOnUiThread ()


สิ่งที่เกี่ยวกับปัญหาดั้งเดิม (ไม่เกี่ยวกับ AlertDialog)
Ivan G.

5
เพียงแค่เพิ่มสองเซ็นต์ของฉันในสิ่งที่ Cleggy พูด มันจะดีกว่าที่จะให้การสาธิตสั้น ๆ เกี่ยวกับสิ่งที่คุณหมายถึง (contrived แต่) เป็นตัวอย่างรหัสมักจะสามารถพูดไดรฟ์สำหรับตัวเอง
cdata

5
หาคำตอบทางเทคนิคเต็มเห็นนี้prasanta-paul.blogspot.kr/2013/09/...
tony9099

3
ในเกือบทุกภาษาการเขียนโปรแกรม AFAIK ที่สนับสนุน GUI หากคุณอัปเดต / เปลี่ยน / แสดง / โต้ตอบกับ GUI โดยตรงควรทำในเธรดหลักของโปรแกรม
อาเหม็ด

(and most other functions dealing with the UI)ตัวอย่างของฟังก์ชั่น UI ที่ใช้งานได้จากพื้นหลังคือandroid.support.design.widget.Snackbar- ฟังก์ชั่นของมันจะไม่ลดน้อยลงเมื่อไม่ได้โทรจากเธรด UI
Scruffy

852

คุณต้องโทรToast.makeText(...)จากเธรด UI:

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

นี่เป็นสำเนาวางจากอื่น (ซ้ำ) ดังนั้นคำตอบ


13
คำตอบที่ดี สิ่งนี้ทำให้ฉันสับสนในขณะที่ เพิ่งทราบว่าฉันไม่ต้องการกิจกรรม ก่อนเรียกใช้ OnUiThread
Cen92

448

อัพเดท - 2016

ทางเลือกที่ดีที่สุดคือการใช้RxAndroid(ผูกที่เฉพาะเจาะจงสำหรับRxJava) สำหรับPในMVPการใช้ค่าใช้จ่ายสำหรับข้อมูล

เริ่มต้นด้วยการกลับมาObservableจากวิธีการที่คุณมีอยู่

private Observable<PojoObject> getObservableItems() {
    return Observable.create(subscriber -> {

        for (PojoObject pojoObject: pojoObjects) {
            subscriber.onNext(pojoObject);
        }
        subscriber.onCompleted();
    });
}

ใช้สิ่งนี้ที่สังเกตได้เช่นนี้ -

getObservableItems().
subscribeOn(Schedulers.io()).
observeOn(AndroidSchedulers.mainThread()).
subscribe(new Observer<PojoObject> () {
    @Override
    public void onCompleted() {
        // Print Toast on completion
    }

    @Override
    public void onError(Throwable e) {}

    @Override
    public void onNext(PojoObject pojoObject) {
        // Show Progress
    }
});
}

-------------------------------------------------- -------------------------------------------------- ------------------------------

ฉันรู้ว่าฉันมาช้าไปหน่อย Android ทำงานบนพื้นสองประเภท ได้แก่ ด้ายUI ด้ายและพื้นหลังด้าย ตามเอกสาร Android -

อย่าเข้าถึงชุดเครื่องมือ Android UI จากภายนอกเธรด UI เพื่อแก้ไขปัญหานี้ Android เสนอวิธีเข้าถึงเธรด UI จากหลายเธรดได้หลายวิธี นี่คือรายการวิธีการที่สามารถช่วยได้:

Activity.runOnUiThread(Runnable)  
View.post(Runnable)  
View.postDelayed(Runnable, long)

ขณะนี้มีวิธีการต่าง ๆ เพื่อแก้ไขปัญหานี้

ฉันจะอธิบายด้วยตัวอย่างโค้ด:

runOnUiThread

new Thread()
{
    public void run()
    {
        myactivity.this.runOnUiThread(new Runnable()
        {
            public void run()
            {
                //Do your UI operations like dialog opening or Toast here
            }
        });
    }
}.start();

Looper

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

class LooperThread extends Thread {
    public Handler mHandler;

    public void run() {
        Looper.prepare();

        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // process incoming messages here
            }
        };

        Looper.loop();
    }
}

AsyncTask

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

public void onClick(View v) {
    new CustomTask().execute((Void[])null);
}


private class CustomTask extends AsyncTask<Void, Void, Void> {

    protected Void doInBackground(Void... param) {
        //Do some work
        return null;
    }

    protected void onPostExecute(Void param) {
        //Print Toast or open dialog
    }
}

ผู้ดำเนินการ

ตัวจัดการช่วยให้คุณสามารถส่งและประมวลผลข้อความและวัตถุที่เรียกใช้ที่เชื่อมโยงกับ MessageQueue ของเธรด

Message msg = new Message();


new Thread()
{
    public void run()
    {
        msg.arg1=1;
        handler.sendMessage(msg);
    }
}.start();



Handler handler = new Handler(new Handler.Callback() {

    @Override
    public boolean handleMessage(Message msg) {
        if(msg.arg1==1)
        {
            //Print Toast or open dialog        
        }
        return false;
    }
});

7
นี่คือว่าสิ่งที่ผมกำลังมองหา โดยเฉพาะอย่างยิ่งตัวอย่างแรกกับrunOnUiThread
Navin

5
ขอบคุณ 5 ปีของการเขียนโปรแกรม Android และฉันไม่เคยรู้ว่าViewมีวิธีการpost(Runnable)และpostDelayed(Runnable, long)! ตัวจัดการจำนวนมากไร้ประโยชน์ :)
Fenix ​​Voltres

สำหรับผู้ที่สับสนโดยตัวอย่าง Handler: อะไรคือเธรดที่ "new handler (callback)" ผูกไว้กับอะไร? มันถูกผูกไว้กับเธรดที่สร้างตัวจัดการ
Helin Wang

1
ทำไมถึงเป็นทางเลือกที่ดีที่สุด ?
IgorGanapolsky

ฉันใช้ข้อมูลพื้นหลังและต้องการรับ ArrayList กลับมา แต่ฉันพบข้อผิดพลาดเสมอ: ไม่สามารถสร้างตัวจัดการภายในเธรดที่ไม่ได้เรียก Looper.prepare () ดูนี่คือคำถามของฉันstackoverflow.com/questions/45562615/แต่ฉันไม่สามารถหาคำตอบจากคำตอบนี้ได้ที่นี่
WeSt

120

Toast.makeText()ควรถูกเรียกจากเธรดหลัก / UI เท่านั้น Looper.getMainLooper ()ช่วยให้คุณบรรลุเป้าหมาย:

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
    }
});

ข้อดีของวิธีนี้คือคุณสามารถใช้ได้โดยไม่มีกิจกรรมหรือบริบท


2
ขอบคุณคำตอบอื่น ๆ ไม่ได้ทำงานให้ฉัน ฉันใช้ระเบียนห้องสมุดน้ำตาลเพื่อจัดการการติดตา และข้างในนั้นฉันไม่มีกิจกรรม แต่มันใช้งานได้อย่างยอดเยี่ยม
cabaji99

91

ลองสิ่งนี้เมื่อคุณเห็น runtimeException เกิดขึ้นเนื่องจาก Looper ไม่ได้เตรียมไว้ก่อนจัดการ

Handler handler = new Handler(Looper.getMainLooper()); 

handler.postDelayed(new Runnable() {
  @Override
  public void run() {
  // Run your task here
  }
}, 1000 );

ตัวจัดการเป็นคลาสนามธรรม สิ่งนี้ไม่ได้รวบรวม
Stealth Rabbi

2
@StealthRabbi นำเข้า Handler จากเนมสเปซที่ถูกต้องเช่นandroid.os.Handler
NightFury

นี่อาจไม่เป็นปัญหา Looper อาจไม่มีอยู่ในคลาสการโทรระยะเวลา
IgorGanapolsky

42

ฉันพบปัญหาเดียวกันและนี่คือวิธีที่ฉันแก้ไข:

private final class UIHandler extends Handler
{
    public static final int DISPLAY_UI_TOAST = 0;
    public static final int DISPLAY_UI_DIALOG = 1;

    public UIHandler(Looper looper)
    {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg)
    {
        switch(msg.what)
        {
        case UIHandler.DISPLAY_UI_TOAST:
        {
            Context context = getApplicationContext();
            Toast t = Toast.makeText(context, (String)msg.obj, Toast.LENGTH_LONG);
            t.show();
        }
        case UIHandler.DISPLAY_UI_DIALOG:
            //TBD
        default:
            break;
        }
    }
}

protected void handleUIRequest(String message)
{
    Message msg = uiHandler.obtainMessage(UIHandler.DISPLAY_UI_TOAST);
    msg.obj = message;
    uiHandler.sendMessage(msg);
}

ในการสร้าง UIHandler คุณจะต้องทำสิ่งต่อไปนี้:

    HandlerThread uiThread = new HandlerThread("UIHandler");
    uiThread.start();
    uiHandler = new UIHandler((HandlerThread) uiThread.getLooper());

หวังว่านี่จะช่วยได้


ฉันพยายามใช้รหัสของคุณ แต่ฉันทำหายไปและไม่แน่ใจว่าจะโทรจากonCreate methodหรือจาก AsyncTask ในสถานการณ์ของฉันคุณจะกรุณาโพสต์รหัสทั้งหมดเพื่อเรียนรู้ว่าสิ่งต่าง ๆ ทำงานอย่างไร
นิคคาห์น

2
บรรทัดสุดท้ายนั้นไม่ควรอ่าน uiHandler = new UIHandler(uiThread.getLooper()); ใช่ไหม
Beer Me

36

เหตุผลข้อผิดพลาด:

หัวข้อคนทำงานมีความหมายสำหรับการทำงานพื้นหลังและคุณไม่สามารถแสดงอะไรใน UI ภายในด้ายคนจนกว่าคุณจะเรียกวิธีการเช่นrunOnUiThread ถ้าคุณพยายามที่จะแสดงอะไรในหัวข้อ UI โดยไม่ต้องโทร runOnUiThread, java.lang.RuntimeExceptionจะมี

ดังนั้นหากคุณอยู่ในการactivityโทรToast.makeText()จากด้ายคนงานทำสิ่งนี้:

runOnUiThread(new Runnable() 
{
   public void run() 
   {
      Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();    
   }
}); 

รหัสด้านบนช่วยให้มั่นใจได้ว่าคุณกำลังแสดงข้อความ Toast ในUI threadเนื่องจากคุณกำลังเรียกมันภายในrunOnUiThreadวิธี java.lang.RuntimeExceptionดังนั้นไม่มีอะไรมาก


23

นั่นคือสิ่งที่ฉันทำ

new Handler(Looper.getMainLooper()).post(new Runnable() {
    @Override
    public void run() {
        Toast(...);
    }
});

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


ฉันใช้วิธีเดียวกันนี้ อย่างไรก็ตามการปล่อยให้สิ่งนี้เปิดโอกาสให้เกิดการรั่วไหลได้เพราะคลาสภายในที่ไม่ระบุชื่อของ Runnable จะมีการอ้างอิงถึงกิจกรรมโดยนัยหรือไม่?
Peter G. Williams

1
นั่นเป็นจุดที่ดี :) เพียงแค่ใช้ getApplicationContext () หรืออะไรทำนองนั้นเพื่อความปลอดภัย ฉันไม่เคยมีปัญหาใด ๆ กับรหัสที่ฉันรู้
eiran

22

ฉันได้รับข้อผิดพลาดนี้จนกว่าฉันจะทำสิ่งต่อไปนี้

public void somethingHappened(final Context context)
{
    Handler handler = new Handler(Looper.getMainLooper());
    handler.post(
        new Runnable()
        {
            @Override
            public void run()
            {
                Toast.makeText(context, "Something happened.", Toast.LENGTH_SHORT).show();
            }
        }
    );
}

และทำให้สิ่งนี้เป็นคลาสเดี่ยว:

public enum Toaster {
    INSTANCE;

    private final Handler handler = new Handler(Looper.getMainLooper());

    public void postMessage(final String message) {
        handler.post(
            new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(ApplicationHolder.INSTANCE.getCustomApplication(), message, Toast.LENGTH_SHORT)
                        .show();
                }
            }
        );
    }

}

คุณใช้เครื่องปิ้งขนมปังอยู่ที่ไหน ในข้อมูลโค้ดแรกของคุณจะไม่ใช้ ...
IgorGanapolsky

1
มันเป็นระดับความสะดวกสบายที่ฉันใช้เหมือนกันToaster.INSTANCE.postMessage(ResourceUtils.getString(R.string.blah));(ฉันรู้มานาน! เราลดจำนวนนี้ในภายหลัง) แม้ว่าฉันจะไม่ได้ใช้ขนมปังปิ้งนาน ๆ
EpicPandaForce

แล้วจะApplicationHolder.INSTANCEประเมินเป็นอย่างไร?
IgorGanapolsky

ตัวแปรคงที่ของการCustomApplicationตั้งค่าในการCustomApplication.onCreate()พิจารณาการใช้งานอยู่เสมอในขณะที่กระบวนการที่มีอยู่บริบทนี้สามารถใช้ทั่วโลก
EpicPandaForce

12
 runOnUiThread(new Runnable() {
            public void run() {
                Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
            }
        });

2
สิ่งนี้ใช้ได้สำหรับฉันและฉันใช้แลมบ์ดาrunOnUiThread(() -> { Toast toast = Toast.makeText(getApplicationContext(), "Message", Toast.LENGTH_SHORT); toast.show(); });
Black_Zerg

ขอบคุณ มันใช้งานได้สำหรับฉัน
อามิน

11

วิธีแก้ปัญหา Kotlin ที่ยอดเยี่ยม:

runOnUiThread {
    // Add your ui thread code here
}

4
runOnUiThreadเป็นส่วนหนึ่งของกิจกรรมคือactivity?.runOnUiThread { ... }
AtomicStrongForce

9

นี่เป็นเพราะ Toast.makeText () กำลังเรียกใช้จากเธรดผู้ปฏิบัติงาน ควรโทรจากเธรด UI หลักเช่นนี้

runOnUiThread(new Runnable() {
      public void run() {
        Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
      }
 });

8

คำตอบโดย ChicoBird ทำงานให้ฉัน การเปลี่ยนแปลงเดียวที่ฉันทำคือการสร้าง UIHandler ที่ฉันต้องทำ

HandlerThread uiThread = new HandlerThread("UIHandler");

Eclipse ปฏิเสธที่จะยอมรับสิ่งอื่น ทำให้รู้สึกฉันคิดว่า

ยังuiHandlerเป็นที่ชัดเจนระดับโลกที่กำหนดไว้ที่ไหนสักแห่ง ฉันยังคงไม่เรียกร้องให้เข้าใจว่า Android กำลังทำสิ่งนี้อย่างไรและเกิดอะไรขึ้น แต่ฉันดีใจที่มันได้ผล ตอนนี้ฉันจะศึกษาต่อไปและดูว่าฉันสามารถเข้าใจสิ่งที่ Android กำลังทำอยู่หรือไม่และทำไมต้องผ่านห่วงและลูปเหล่านี้ทั้งหมด ขอบคุณสำหรับความช่วยเหลือ ChicoBird


6

โทรครั้งแรกLooper.prepare()และจากนั้นโทรสายToast.makeText().show()สุดท้ายLooper.loop()เช่น:

Looper.prepare() // to be able to make toast
Toast.makeText(context, "not connected", Toast.LENGTH_LONG).show()
Looper.loop()

ทำไมคำตอบนี้ถูกประเมินต่ำเกินไป
DkPathak

5

สำหรับผู้ใช้ Rxjava และ RxAndroid:

public static void shortToast(String msg) {
    Observable.just(msg)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(message -> {
                Toast.makeText(App.getInstance(), message, Toast.LENGTH_SHORT).show();
            });
}

วงเล็บเหล่านั้นไม่จำเป็น
Borja

4

ฉันพบปัญหาเดียวกันเมื่อการโทรกลับของฉันพยายามแสดงข้อความโต้ตอบ

ฉันแก้ไขด้วยวิธีเฉพาะในกิจกรรม - ที่ระดับสมาชิกอินสแตนซ์กิจกรรม- การใช้งานนั้นrunOnUiThread(..)

public void showAuthProgressDialog() {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            mAuthProgressDialog = DialogUtil.getVisibleProgressDialog(SignInActivity.this, "Loading ...");
        }
    });
}

public void dismissAuthProgressDialog() {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (mAuthProgressDialog == null || ! mAuthProgressDialog.isShowing()) {
                return;
            }
            mAuthProgressDialog.dismiss();
        }
    });
}

2
Handler handler2;  
HandlerThread handlerThread=new HandlerThread("second_thread");
handlerThread.start();
handler2=new Handler(handlerThread.getLooper());

ตอนนี้ handler2 จะใช้เธรดอื่นเพื่อจัดการกับข้อความที่ไม่ใช่เธรดหลัก


1

ในการแสดงไดอะล็อกหรือเครื่องปิ้งขนมปังในชุดข้อความวิธีที่รัดกุมที่สุดคือการใช้วัตถุกิจกรรม

ตัวอย่างเช่น:

new Thread(new Runnable() {
    @Override
    public void run() {
        myActivity.runOnUiThread(new Runnable() {
            public void run() {
                myActivity.this.processingWaitDialog = new ProgressDialog(myActivity.this.getContext());
                myActivity.this.processingWaitDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
                myActivity.this.processingWaitDialog.setMessage("abc");
                myActivity.this.processingWaitDialog.setIndeterminate(true);
                myActivity.this.processingWaitDialog.show();
            }
        });
        expenseClassify.serverPost(
                new AsyncOperationCallback() {
                    public void operationCompleted(Object sender) {
                        myActivity.runOnUiThread(new Runnable() {
                            public void run() {
                                if (myActivity.this.processingWaitDialog != null 
                                        && myActivity.this.processingWaitDialog.isShowing()) {
                                    myActivity.this.processingWaitDialog.dismiss();
                                    myActivity.this.processingWaitDialog = null;
                                }
                            }
                        }); // .runOnUiThread(new Runnable()
...

0

Toast, AlertDialogจำเป็นต้องเรียกใช้บนเธรด UI คุณสามารถใช้Asynctaskเพื่อใช้งานได้อย่างถูกต้องในการพัฒนา android แต่บางกรณีเราจำเป็นต้องปรับแต่งเวลาให้ช้าลงดังนั้นเราจึงใช้เธรดแต่ในเธรดที่เราไม่สามารถใช้ Toast, Alertdialogs เหมือนเราใช้ ใน AsyncTask.So เราต้องมีตัวจัดการแยกต่างหาก สำหรับป๊อปอัปเหล่านั้น

public void onSigned() {
    Thread thread = new Thread(){
        @Override
        public void run() {
            try{
                sleep(3000);
                Message message = new Message();
                message.what = 2;
                handler.sendMessage(message);
            } catch (Exception e){
                e.printStackTrace();
            }
        }
    };
    thread.start();
}

ในตัวอย่างข้างต้นฉันต้องการที่จะนอนด้ายของฉันใน 3 วินาทีและหลังจากที่ฉันต้องการที่จะแสดงข้อความ Toast สำหรับการที่ในmainthreadของคุณใช้ตัวจัดการ

handler = new Handler() {
       public void handleMessage(Message msg) {
           switch(msg.what){
              case 1:
              Toast.makeText(getActivity(),"cool",Toast.LENGTH_SHORT).show();
              break;
           }
           super.handleMessage(msg);
       }
};

ฉันใช้ตัวเรือนสวิตช์ที่นี่เพราะถ้าคุณต้องการแสดงข้อความที่แตกต่างในลักษณะเดียวกันคุณสามารถใช้ตัวเรือนสวิตช์ภายในคลาสตัวจัดการ ... หวังว่านี่จะช่วยคุณได้


0

มักจะเกิดขึ้นเมื่อมีบางสิ่งในเธรดหลักถูกเรียกจากเธรดพื้นหลังใด ๆ ให้ดูตัวอย่างเช่น

private class MyTask extends AsyncTask<Void, Void, Void> {


@Override
protected Void doInBackground(Void... voids) {
        textView.setText("Any Text");
        return null;
    }
}

ในตัวอย่างข้างต้นเรากำลังตั้งค่าข้อความบน textview ซึ่งอยู่ในเธรด UI หลักจากเมธอด doInBackground () ซึ่งทำงานบนเธรดผู้ปฏิบัติงานเท่านั้น


0

ฉันมีปัญหาเดียวกันและฉันแก้ไขได้ง่ายๆโดยการใส่ Toast ใน onPostExecute () ฟังก์ชั่นการแทนที่ของ Asynctask <> และมันใช้งานได้


-2

ฉันใช้รหัสต่อไปนี้เพื่อแสดงข้อความจาก "บริบท" ที่ไม่ใช่หัวข้อหลัก

@FunctionalInterface
public interface IShowMessage {
    Context getContext();

    default void showMessage(String message) {
        final Thread mThread = new Thread() {
            @Override
            public void run() {
                try {
                    Looper.prepare();
                    Toast.makeText(getContext(), message, Toast.LENGTH_LONG).show();
                    Looper.loop();
                } catch (Exception error) {
                    error.printStackTrace();
                    Log.e("IShowMessage", error.getMessage());
                }
            }
        };
        mThread.start();
    }
}

จากนั้นใช้ดังต่อไปนี้:

class myClass implements IShowMessage{

  showMessage("your message!");
 @Override
    public Context getContext() {
        return getApplicationContext();
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.