다른 스레드의 메인 스레드에서 코드 실행


326

안드로이드 서비스에서 백그라운드 작업을 수행하기위한 스레드를 만들었습니다.

스레드가 기본 스레드의 메시지 대기열에 특정 작업을 게시 해야하는 상황이 있습니다 (예 : a) Runnable.

Handler메인 스레드 를 가져 와서 다른 스레드에서 게시 Message/ 게시 하는 방법이 Runnable있습니까?

감사,


2
당신은 또한 사용자 정의 방송 수신기를 사용할 수 있습니다 .... 내 대답을 여기에 [내부 방송 수신기] [1] [1] : stackoverflow.com/a/22541324/1881527
— Melbourne Lopes

많은 방법이 있습니다. David의 답변 및 dzeikei의 답변에 대한 답변 외에도 (3) 브로드 캐스트 수신기를 사용하거나 (4) 서비스를 시작하는 데 사용되는 Intent 이외의 핸들러를 전달한 다음 getIntent ( ) .getExtras ().
— Ashok Bijoy Debnath

2
@ sazzad-hissain-khan, 왜 kotlin 태그를 사용하여 Java에서 주로 답변하는 2012 년의이 질문에 태그를 추가해야합니까?
— Tenfour04

답변:


617

참고 :이 답변은 많은 주목을 받았으므로 업데이트해야합니다. 원래 답변이 게시 된 이후 @dzeikei의 의견은 원래 답변만큼이나 많은 주목을 받았습니다. 가능한 해결책은 다음과 같습니다.

1. 백그라운드 스레드에 Context객체에 대한 참조가있는 경우 :

백그라운드 워커 스레드가 컨텍스트 오브젝트에 액세스 할 수 있는지 확인하십시오 (응용 프로그램 컨텍스트 또는 서비스 컨텍스트 일 ​​수 있음). 그런 다음 백그라운드 작업자 스레드 에서이 작업을 수행하십시오.

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(context.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);

2. 백그라운드 스레드에 Context객체가 없거나 필요한 경우

(@dzeikei에서 제안 함) :

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(Looper.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);

1
고맙습니다 David Handler를 확장하고 handleMessage ()를 확장하면 주 스레드가 메시지를 처리하지 못하게 할 수 있습니다. 그것은 curosity에 대한 질문 일뿐입니다.
— Ahmed

2
아니요. 서브 클래스를 Handler사용하거나 Handler.Callback인터페이스를 사용 handleMessage()하는 경우 핸들러를 사용하여 게시 된 메시지에 대해서만 메소드가 호출됩니다. 기본 스레드는 다른 핸들러를 사용하여 메시지를 게시 / 처리하므로 충돌이 없습니다.
— David Wasser 2016 년

205
나는 당신이 사용한다면 상황이 필요 없을 것이라고 믿습니다Handler mainHandler = new Handler(Looper.getMainLooper());
— dzeikei

6
사소한 점; 귀하의 코드는 현재 위치로 이동하지 않습니다 ... 그것은해야한다new Runnable(){@Override public void run() {....}};
— 리처드 설렘

1
@SagarDevanga 이것은 다른 질문을하기에 적합한 장소가 아닙니다. 관련이없는 답변에 대한 의견이 아닌 새로운 질문을 게시하십시오. 그런 식으로 더 좋고 빠른 응답을 얻을 수 있습니다.
— David Wasser

138

아래의 주석가가 올바르게 지적했듯이 이것은 서비스의 일반적인 솔루션이 아니며 활동에서 시작된 스레드 (서비스는 그러한 스레드 일 수는 있지만 모든 스레드는 아닙니다)입니다. 서비스 활동 커뮤니케이션의 복잡한 주제에 대해서는 공식 문서의 전체 서비스 섹션을 읽으십시오-복잡하기 때문에 기본 사항을 이해하는 것이 좋습니다 : http://developer.android.com/guide/components/services.html # 알림

아래 방법은 가장 간단한 경우에 작동 할 수 있습니다.

올바르게 이해하면 응용 프로그램의 GUI 스레드에서 일부 코드를 실행해야합니다 ( "메인"스레드라는 다른 것을 생각할 수 없음). 이를 위해 다음과 같은 방법이 있습니다 Activity.

someActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
           //Your code to run in GUI thread here
        }//public void run() {
});

문서 : http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29

이것이 당신이 찾고있는 것이기를 바랍니다.


20
OP는 그가 스레드를 실행 중이라고 말합니다 Service. runOnUiThread()에서 사용할 수 없습니다 Service. 이 답변은 오해의 소지가 있으며 질문과 대답을 다루지 않습니다.
— David Wasser

31

컨텍스트에 액세스 할 수없는 경우 다른 간단한 방법이 있습니다.

1). 메인 루퍼에서 핸들러를 만듭니다.

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

2). Runnable 인터페이스를 구현하십시오.

Runnable runnable = new Runnable() { // your code here }

삼). Runnable을 uiHandler에 게시하십시오.

uiHandler.post(runnable);

그게 전부입니다 ;-) 스레드와 함께 즐거운 시간을 보내십시오.


29

스레드에서 코드를 실행하는 경우 (예 : 일부 작업 지연) runOnUiThread컨텍스트에서 호출해야합니다 . 예를 들어 코드가 MainActivity클래스 내부에 있으면 다음을 사용하십시오.

MainActivity.this.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        myAction();
    }
});

기본 (UI 스레드) 또는 다른 스레드에서 메소드를 호출 할 수 있다면 다음과 같은 검사가 필요합니다.

public void myMethod() {
   if( Looper.myLooper() == Looper.getMainLooper() ) {
       myAction();
   }
   else {

}

7
OP는 그가 스레드를 실행 중이라고 말합니다 Service. runOnUiThread()에서 사용할 수 없습니다 Service.
— David Wasser

@DavidWasser 어디에나 문서화되어 있습니까? 방법 문서는 그것에 대해 언급하지 않습니다. developer.android.com/reference/android/app/…
— Greg Brown

1
@GregBrown Activity문서 링크를 통해 알 수 있듯이 runOnUiThread()의 방법입니다 Activity. 의 방법이 Service아니므로 사용할 수 없습니다. 그보다 더 명확한 것은 무엇입니까?
— David Wasser

@DavidWasser Fair로 충분합니다. 왜 내가 지금 그 질문을했는지 (아직 1 년 전 게시 된) 기억이 나지 않습니다.
— Greg Brown

24

압축 코드 블록은 다음과 같습니다.

   new Handler(Looper.getMainLooper()).post(new Runnable() {
       @Override
       public void run() {
           // things to do on the main thread
       }
   });

여기에는 활동 참조 또는 응용 프로그램 참조를 전달하지 않아도됩니다.

코 틀린 동등 물 :

    Handler(Looper.getMainLooper()).post(Runnable {
        // things to do on the main thread
    })

20

코 틀린 버전

때 당신이 활동에있는 다음 사용

runOnUiThread {
    //code that runs in main
}

때 당신이 활동 컨텍스트가 , mContext는 사용

mContext.runOnUiThread {
    //code that runs in main
}

사용 가능한 컨텍스트 가 없는 곳에있는 경우

Handler(Looper.getMainLooper()).post {  
    //code that runs in main
}

이것이 어떤 Kotlin 버전인지 확실하지 않지만 중괄호를 추가해야했습니다.runOnUiThread(){...}
— Wex

5

컨텍스트가없는 경우 가장 간단한 방법, RxAndroid를 사용하는 경우 다음을 수행 할 수 있습니다.

AndroidSchedulers.mainThread().scheduleDirect {
    runCodeHere()
}

5

핸들러를 사용하는보다 정확한 Kotlin 코드 :

Handler(Looper.getMainLooper()).post {  
 // your codes here run on main Thread
 }

4

내가 생각할 수있는 한 가지 방법은 다음과 같습니다.

1) UI가 서비스에 바인딩되도록하십시오.
2) 다음 Binder을 등록 하는 방법으로 다음과 같은 방법을 노출 하십시오 Handler.

public void registerHandler(Handler handler) {
    mHandler = handler;
}

3) UI 스레드에서 서비스에 바인딩 한 후 위의 메소드를 호출하십시오.

mBinder.registerHandler(new Handler());

4) 서비스 스레드에서 처리기를 사용하여 작업을 게시하십시오.

mHandler.post(runnable);

3

HandlerThread 안드로이드에서 일반 자바 스레드에 대한 더 나은 옵션입니다.

  1. HandlerThread를 작성 하고 시작하십시오.
  2. 크리에이트 핸들러 와 루퍼 HandlerThread에서를 :requestHandler
  3. postRunnable작업에requestHandler

UI 스레드와의 통신 HandlerThread

  1. 기본 스레드에 대한 Handlerwith Looper를 작성하고 메소드를 responseHandler대체하십시오.handleMessage
  2. 내부 Runnable(다른 스레드의 작업 HandlerThread이 경우), 전화 sendMessage에responseHandler
  3. 이 sendMessage결과 호출 handleMessage에서 responseHandler.
  4. 속성을 가져 Message와서 처리하고 UI를 업데이트하십시오.

예 : TextView웹 서비스에서받은 데이터로 업데이트 합니다. 웹 서비스는 UI가 아닌 스레드에서 호출되어야하므로 HandlerThread네트워크 작업을 위해 생성 됩니다. 웹 서비스에서 컨텐츠를 가져 오면 기본 스레드 (UI 스레드) 핸들러로 메시지를 보내면 메시지를 Handler처리하고 UI를 업데이트합니다.

샘플 코드 :

HandlerThread handlerThread = new HandlerThread("NetworkOperation");
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);
    }
};

Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Log.d("Runnable", "Before IO call");
            URL page = new URL("http://www.your_web_site.com/fetchData.jsp");
            StringBuffer text = new StringBuffer();
            HttpURLConnection conn = (HttpURLConnection) page.openConnection();
            conn.connect();
            InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
            BufferedReader buff = new BufferedReader(in);
            String line;
            while ((line = buff.readLine()) != null) {
                text.append(line + "\n");
            }
            Log.d("Runnable", "After IO call:"+ text.toString());
            Message msg = new Message();
            msg.obj = text.toString();
            responseHandler.sendMessage(msg);


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

유용한 기사 :

핸들러 스레드-왜 당신은 안드로이드 앱에서 그들을 사용해야합니까?

안드로이드 루퍼 처리기 처리기


2

나는 이것이 오래된 질문이라는 것을 알고 있지만 Kotlin과 Java 모두에서 사용하는 메인 스레드 원 라이너를 발견했습니다. 이것은 서비스에 가장 적합한 솔루션은 아니지만 프래그먼트 내부의 UI를 변경하는 무언가를 호출하는 경우 매우 간단하고 명백합니다.

자바 (8) :

 getActivity().runOnUiThread(()->{
      //your main thread code
 });

코 틀린 :

this.runOnUiThread {
     //your main thread code
}

1

이 방법을 따르십시오. 이 방법을 사용하면 백그라운드 스레드에서 UI를 간단히 업데이트 할 수 있습니다. runOnUiThread 메인 (UI) 스레드에서 작동합니다. 이 코드 스 니펫은 특히 초보자에게 덜 복잡하고 쉽다고 생각합니다.

AsyncTask.execute(new Runnable() {
            @Override
            public void run() {

            //code you want to run on the background
            someCode();

           //the code you want to run on main thread
 MainActivity.this.runOnUiThread(new Runnable() {

                    public void run() {

/*the code you want to run after the background operation otherwise they will executed earlier and give you an error*/
                        executeAfterOperation();

                   }
                });
            }
        });

서비스의 경우

oncreate에서 핸들러를 작성하십시오.

 handler = new Handler();

다음과 같이 사용하십시오

 private void runOnUiThread(Runnable runnable) {
        handler.post(runnable);
    }

이 코드 스 니펫은 제한적이고 즉각적인 도움이 될 수 있습니다. 적절한 설명은 크게 장기 가치를 향상 할 보여줌으로써 왜 이 문제에 대한 좋은 해결책이고, 다른 유사한 질문을 미래의 독자들에게 더 유용 할 것입니다. 제발 편집 당신이 만든 가정 등 일부 설명을 추가 할 답변을.
— iBug

1

Kotlin의 경우 Anko corountines를 사용할 수 있습니다 .

최신 정보

doAsync {
   ...
}

더 이상 사용되지 않음

async(UI) {
    // Code run on UI thread
    // Use ref() instead of this@MyActivity
}

1

가장 편리한 방법은 다음과 같습니다.

import android.os.AsyncTask
import android.os.Handler
import android.os.Looper

object Dispatch {
    fun asyncOnBackground(call: ()->Unit) {
        AsyncTask.execute {
            call()
        }
    }

    fun asyncOnMain(call: ()->Unit) {
        Handler(Looper.getMainLooper()).post {
            call()
        }
    }
}

그리고 후에 :

Dispatch.asyncOnBackground {
    val value = ...// super processing
    Dispatch.asyncOnMain { completion(value)}
}

0
public void mainWork() {
    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            //Add Your Code Here
        }
    });
}

이것은 문제가없는 서비스 클래스에서도 작동 할 수 있습니다.


이 코드는 질문에 대한 답변을 제공하지만 다른 사용자에 대한 답변의 가치를 높이기 위해 몇 가지 설명 문장을 추가하는 것이 좋습니다.
— MBT

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.