안드로이드 서비스에서 백그라운드 작업을 수행하기위한 스레드를 만들었습니다.
스레드가 기본 스레드의 메시지 대기열에 특정 작업을 게시 해야하는 상황이 있습니다 (예 : a) Runnable
.
Handler
메인 스레드 를 가져 와서 다른 스레드에서 게시 Message
/ 게시 하는 방법이 Runnable
있습니까?
감사,
안드로이드 서비스에서 백그라운드 작업을 수행하기위한 스레드를 만들었습니다.
스레드가 기본 스레드의 메시지 대기열에 특정 작업을 게시 해야하는 상황이 있습니다 (예 : a) Runnable
.
Handler
메인 스레드 를 가져 와서 다른 스레드에서 게시 Message
/ 게시 하는 방법이 Runnable
있습니까?
감사,
답변:
참고 :이 답변은 많은 주목을 받았으므로 업데이트해야합니다. 원래 답변이 게시 된 이후 @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);
Handler
사용하거나 Handler.Callback
인터페이스를 사용 handleMessage()
하는 경우 핸들러를 사용하여 게시 된 메시지에 대해서만 메소드가 호출됩니다. 기본 스레드는 다른 핸들러를 사용하여 메시지를 게시 / 처리하므로 충돌이 없습니다.
Handler mainHandler = new Handler(Looper.getMainLooper());
new Runnable(){@Override public void run() {....}};
아래의 주석가가 올바르게 지적했듯이 이것은 서비스의 일반적인 솔루션이 아니며 활동에서 시작된 스레드 (서비스는 그러한 스레드 일 수는 있지만 모든 스레드는 아닙니다)입니다. 서비스 활동 커뮤니케이션의 복잡한 주제에 대해서는 공식 문서의 전체 서비스 섹션을 읽으십시오-복잡하기 때문에 기본 사항을 이해하는 것이 좋습니다 : 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() {
});
이것이 당신이 찾고있는 것이기를 바랍니다.
Service
. runOnUiThread()
에서 사용할 수 없습니다 Service
. 이 답변은 오해의 소지가 있으며 질문과 대답을 다루지 않습니다.
컨텍스트에 액세스 할 수없는 경우 다른 간단한 방법이 있습니다.
1). 메인 루퍼에서 핸들러를 만듭니다.
Handler uiHandler = new Handler(Looper.getMainLooper());
2). Runnable 인터페이스를 구현하십시오.
Runnable runnable = new Runnable() { // your code here }
삼). Runnable을 uiHandler에 게시하십시오.
uiHandler.post(runnable);
그게 전부입니다 ;-) 스레드와 함께 즐거운 시간을 보내십시오.
스레드에서 코드를 실행하는 경우 (예 : 일부 작업 지연) runOnUiThread
컨텍스트에서 호출해야합니다 . 예를 들어 코드가 MainActivity
클래스 내부에 있으면 다음을 사용하십시오.
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
myAction();
}
});
기본 (UI 스레드) 또는 다른 스레드에서 메소드를 호출 할 수 있다면 다음과 같은 검사가 필요합니다.
public void myMethod() {
if( Looper.myLooper() == Looper.getMainLooper() ) {
myAction();
}
else {
}
Service
. runOnUiThread()
에서 사용할 수 없습니다 Service
.
Activity
문서 링크를 통해 알 수 있듯이 runOnUiThread()
의 방법입니다 Activity
. 의 방법이 Service
아니므로 사용할 수 없습니다. 그보다 더 명확한 것은 무엇입니까?
때 당신이 활동에있는 다음 사용
runOnUiThread {
//code that runs in main
}
때 당신이 활동 컨텍스트가 , mContext는 사용
mContext.runOnUiThread {
//code that runs in main
}
사용 가능한 컨텍스트 가 없는 곳에있는 경우
Handler(Looper.getMainLooper()).post {
//code that runs in main
}
runOnUiThread(){...}
내가 생각할 수있는 한 가지 방법은 다음과 같습니다.
1) UI가 서비스에 바인딩되도록하십시오.
2) 다음 Binder
을 등록 하는 방법으로 다음과 같은 방법을 노출 하십시오 Handler
.
public void registerHandler(Handler handler) {
mHandler = handler;
}
3) UI 스레드에서 서비스에 바인딩 한 후 위의 메소드를 호출하십시오.
mBinder.registerHandler(new Handler());
4) 서비스 스레드에서 처리기를 사용하여 작업을 게시하십시오.
mHandler.post(runnable);
HandlerThread
안드로이드에서 일반 자바 스레드에 대한 더 나은 옵션입니다.
requestHandler
post
Runnable
작업에requestHandler
UI 스레드와의 통신 HandlerThread
Handler
with Looper
를 작성하고 메소드를 responseHandler
대체하십시오.handleMessage
Runnable
(다른 스레드의 작업 HandlerThread
이 경우), 전화 sendMessage
에responseHandler
sendMessage
결과 호출 handleMessage
에서 responseHandler
.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);
유용한 기사 :
이 방법을 따르십시오. 이 방법을 사용하면 백그라운드 스레드에서 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);
}
Kotlin의 경우 Anko corountines를 사용할 수 있습니다 .
최신 정보
doAsync {
...
}
더 이상 사용되지 않음
async(UI) {
// Code run on UI thread
// Use ref() instead of this@MyActivity
}
가장 편리한 방법은 다음과 같습니다.
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)}
}