Looper.prepare()를 호출하지 않은 스레드 내에 핸들러를 만들 수 없습니다.
다음 예외는 무엇을 의미합니까? 어떻게 해결할 수 있습니까?
코드는 다음과 같습니다.
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)
은 야합다니화에 .Toast.makeText(...)
UI 스레드에서:
activity.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show();
}
});
이것은 다른 (중복) SO 답변에서 복사하여 붙여넣은 것입니다.
당신은 그것을 노동자 스레드에서 부르고 있습니다.은 야합다니화에 .Toast.makeText()
(및 UI를 다루는 대부분의 다른 함수) 메인 스레드 내에서.예를 들어 핸들러를 사용할 수 있습니다.
설명서에서 UI 스레드와의 통신을 검색합니다.간단히 말해서,
// 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();
}
기타 옵션:
사용할 수 있습니다. 만약 당신이 가지고 있다면 직설적으로.Activity
:
@WorkerThread
void workerThread() {
myActivity.runOnUiThread(() -> {
// This is where your UI code goes.
}
}
메인 루퍼에 글을 올릴 수도 있습니다.이것은 당신이 가진 것이 전부라면 잘 작동합니다.Context
.
@WorkerThread
void workerThread() {
ContextCompat.getMainExecutor(context).execute(() -> {
// This is where your UI code goes.
}
}
사용되지 않음:
백그라운드에서 실행되는 대부분의 작업에 잘 작동하는 비동기 작업을 사용할 수 있습니다.이 도구에는 진행 상황과 완료 시기를 나타내는 후크가 있습니다.
편리하지만 올바르게 사용하지 않으면 컨텍스트가 유출될 수 있습니다.그것은 공식적으로 더 이상 사용되지 않으며, 더 이상 사용해서는 안 됩니다.
업데이트 - 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 스레드와 백그라운드 스레드의 두 가지 스레드 유형에서 작동합니다.안드로이드 문서에 따르면 -
이 문제를 해결하기 위해 UI 스레드 외부에서 Android UI 툴킷에 액세스하지 마십시오. Android는 다른 스레드에서 UI 스레드에 액세스할 수 있는 여러 가지 방법을 제공합니다.다음은 도움이 될 수 있는 방법의 목록입니다.
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
이제 이 문제를 해결하기 위한 다양한 방법이 있습니다.
코드 샘플로 설명하겠습니다.
Ui 스레드에서 실행
new Thread()
{
public void run()
{
myactivity.this.runOnUiThread(new Runnable()
{
public void run()
{
//Do your UI operations like dialog opening or Toast here
}
});
}
}.start();
루퍼
스레드에 대한 메시지 루프를 실행하는 데 사용되는 클래스입니다.스레드에는 기본적으로 연결된 메시지 루프가 없습니다. 메시지 루프를 만들려면 루프를 실행할 스레드에서 prepare()를 호출한 다음 루프가 중지될 때까지 메시지를 처리하도록 루프()를 지정합니다.
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();
}
}
비동기 작업
비동기 작업을 사용하면 사용자 인터페이스에서 비동기 작업을 수행할 수 있습니다.작업자 스레드에서 차단 작업을 수행한 다음 사용자가 직접 스레드 및/또는 처리기를 처리할 필요 없이 결과를 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
}
}
핸들러
처리기를 사용하면 스레드의 메시지 큐와 관련된 메시지 및 실행 가능 개체를 보내고 처리할 수 있습니다.
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;
}
});
Toast.makeText()
기본/UI 스레드에서만 호출할 수 있습니다.Looper.getMainLooper()는 다음과 같은 이점을 제공합니다.
JAVA
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// write your code here
}
});
KOTLIN
Handler(Looper.getMainLooper()).post {
// write your code here
}
이 방법의 장점은 활동이나 컨텍스트 없이 UI 코드를 실행할 수 있다는 것입니다.
런타임이 표시되면 시도해 보십시오.Looper로 인한 예외가 처리기 앞에 준비되지 않았습니다.
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
// Run your task here
}
}, 1000 );
저도 같은 문제에 부딪혔는데, 이 문제를 해결한 방법은 다음과 같습니다.
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);
}
UI 핸들러를 만들려면 다음을 수행해야 합니다.
HandlerThread uiThread = new HandlerThread("UIHandler");
uiThread.start();
uiHandler = new UIHandler((HandlerThread) uiThread.getLooper());
이게 도움이 되길 바랍니다.
오류 이유:
worker 스레드는 백그라운드 작업을 수행하기 위한 것으로, runOnUiThread와 같은 메서드를 호출하지 않으면 worker 스레드 내의 UI에 아무것도 표시할 수 없습니다.runOnUiThread를 호출하지 않고 UI 스레드에 표시하려는 경우java.lang.RuntimeException
.
이 래서그에 있으면 당신이약만.activity
하지만 부르는 것Toast.makeText()
작업자 스레드에서 다음 작업을 수행합니다.
runOnUiThread(new Runnable()
{
public void run()
{
Toast toast = Toast.makeText(getApplicationContext(), "Something", Toast.LENGTH_SHORT).show();
}
});
위의 코드를 사용하면 토스트 메시지가 다음과 같이 표시됩니다.UI thread
당신이 그것을 속으로 부르고 있기 때문에.runOnUiThread
방법.그래서 더 이상은java.lang.RuntimeException
.
그게 제가 한 일입니다.
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast(...);
}
});
시각적 구성요소는 외부 스레드의 변경사항에 대해 "잠금"됩니다.따라서 토스트에는 메인 스레드에 의해 관리되는 메인 화면의 내용이 표시되므로 해당 스레드에서 이 코드를 실행해야 합니다.도움이 되길 바랍니다:)
다음을 수행하기 전까지 이 오류가 발생했습니다.
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();
}
}
);
}
}
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
}
});
멋진 코틀린 솔루션:
runOnUiThread {
// Add your ui thread code here
}
번째 전화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()
이는 작업자 스레드에서 Toast.makeText()가 호출되고 있기 때문입니다.메인 UI 스레드에서 이렇게 호출해야 합니다.
runOnUiThread(new Runnable() {
public void run() {
Toast toast = Toast.makeText(mContext, "Something", Toast.LENGTH_SHORT);
}
});
ChicoBird의 대답은 저에게 효과가 있었습니다.변경한 것은 UI 처리기를 만드는 것뿐입니다.
HandlerThread uiThread = new HandlerThread("UIHandler");
이클립스는 다른 어떤 것도 받아들이지 않았습니다.말이 되는군요.
한또.uiHandler
분명하게 정의된 전역 클래스입니다.나는 여전히 안드로이드가 어떻게 이것을 하고 있고 무슨 일이 일어나고 있는지 이해할 수 없다고 주장하지만, 그것이 작동해서 기쁩니다.이제 저는 그것을 연구하고 안드로이드가 무엇을 하는지 이해할 수 있는지, 그리고 왜 사람들이 이 모든 어려움을 겪어야 하는지 알아보겠습니다.Chico Bird를 도와주셔서 감사합니다.
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();
});
}
코루틴이 완벽하게 해낼 겁니다
CoroutineScope(Job() + Dispatchers.Main).launch {
Toast.makeText(context, "yourmessage",Toast.LENGTH_LONG).show()}
자바 8
new Handler(Looper.getMainLooper()).post(() -> {
// Work in the UI thread
});
코틀린
Handler(Looper.getMainLooper()).post{
// Work in the UI thread
}
GL
제 콜백이 대화상자를 표시하려고 할 때도 같은 문제가 발생했습니다.
활동 - 활동 인스턴스 구성원 수준 - 을 사용하는 전용 방법으로 해결했습니다.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();
}
});
}
Handler handler2;
HandlerThread handlerThread=new HandlerThread("second_thread");
handlerThread.start();
handler2=new Handler(handlerThread.getLooper());
이제 핸들러 2는 메인 스레드와 다른 스레드를 사용하여 메시지를 처리합니다.
저도 같은 문제가 발생했고 이 코드는 현재 저에게 잘 작동하고 있습니다.
예를 들어 이것은 백그라운드 및 UI 스레드에서 작업을 수행하기 위한 내 코드입니다.
루퍼의 사용 방법을 관찰합니다.
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
// your Background Task here
runOnUiThread(new Runnable() {
@Override
public void run() {
// update your UI here
Looper.loop();
}
});
}
}).start();
스레드에 대화상자 또는 토스터를 표시하려면 활동 개체를 사용하는 것이 가장 간단한 방법입니다.
예:
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()
...
람다 사용:
activity.runOnUiThread(() -> Toast.makeText(activity, "Hello", Toast.LENGTH_SHORT).show());
토스트, AlertDialogs는 UI 스레드에서 실행되어야 하며, 비동기 작업을 사용하여 안드로이드 개발에서 올바르게 사용할 수 있습니다.그러나 시간 초과를 사용자 지정해야 하는 경우가 있으므로 스레드를 사용하지만 스레드에서는 비동기 작업에서 사용하는 것처럼 토스트, 알림 대화 상자를 사용할 수 없습니다.팝업을 위해 별도의 처리기가 필요합니다.
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초 안에 스레드를 절전 모드로 전환하고 메인 스레드 구현 핸들러에 대한 토스트 메시지를 표시하고 싶습니다.
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);
}
};
여기서 스위치 케이스를 사용했습니다. 같은 방식으로 다른 메시지를 표시해야 할 경우 핸들러 클래스 내에서 스위치 케이스를 사용할 수 있기 때문입니다.이것이 당신에게 도움이 되기를 바랍니다.
이것은 일반적으로 주 스레드의 어떤 것이 백그라운드 스레드에서 호출될 때 발생합니다.예를 들어, 예를 들어 보겠습니다.
private class MyTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
textView.setText("Any Text");
return null;
}
}
위의 예에서는 작업자 스레드에서만 작동하는 doInBackground() 메서드의 메인 UI 스레드에 있는 텍스트 뷰에 텍스트를 설정하고 있습니다.
저도 같은 문제가 있었고 토스트를 포스트에 넣는 것만으로 간단히 해결했습니다.비동기 작업 <>의 실행() 재정의 기능이 작동했습니다.
당신은 UI 스레드에 토스트를 만들어야 합니다.아래 예제를 찾습니다.
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(activity, "YOUR_MESSAGE", Toast.LENGTH_SHORT).show();
}
});
토스트 메시지를 표시하려면 이 문서를 참조하십시오.
코루틴을 사용하는 코틀린을 위한 솔루션은 다음과 같습니다.
CoroutineScope by MainScope()로 클래스를 확장합니다.
class BootstrapActivity : CoroutineScope by MainScope() {}
그런 다음 간단하게 다음을 수행합니다.
launch {
// whatever you want to do in the main thread
}
코루틴에 대한 종속성을 추가하는 것을 잊지 마십시오.
org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.kotlinCoroutines}
org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.kotlinCoroutines}
스레드 외부에 처리기 만들기
final Handler handler = new Handler();
new Thread(new Runnable() {
@Override
public void run() {
try{
handler.post(new Runnable() {
@Override
public void run() {
showAlertDialog(p.getProviderName(), Token, p.getProviderId(), Amount);
}
});
}
}
catch (Exception e){
Log.d("ProvidersNullExp", e.getMessage());
}
}
}).start();
최근에 이런 문제가 발생했습니다. 생성자의 UI 작업을 수행하는 함수를 호출하려고 했기 때문입니다.생성자에서 초기화를 제거하여 문제를 해결했습니다.
다음 코드를 사용하여 비 메인 스레드 "session"의 메시지를 표시합니다.
@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();
}
}
언급URL : https://stackoverflow.com/questions/3875184/cant-create-handler-inside-thread-that-has-not-called-looper-prepare
'source' 카테고리의 다른 글
Excel 패키지로 작성된 Excel 셀의 통화 형식 설정 (0) | 2023.06.08 |
---|---|
모듈을 찾을 수 없음: 오류:'ts-loader'를 확인할 수 없습니다. (0) | 2023.06.08 |
어떤 경우에 Oracle은 자동으로 인덱스를 생성합니까? (0) | 2023.06.08 |
Windows zure에서 Ocp-Apim-Subscription-Key를 찾을 수 있는 위치 (0) | 2023.06.03 |
테이크(1) 대 퍼스트 클래스 (0) | 2023.06.03 |