티스토리 뷰

Android/Android Multi Threading

12. 인텐트 서비스

안드로이드용용 2016. 8. 29. 16:21

11장에서는 런타임에 의한 백그라운드 스레드의 종료를 피하면서, 서비스 생명주기가 비동기 실행을 처리하는 방법에 대해 논의했다. 그러나 서비스는 UI스레드에서 실행되기 때문에 완전한 비동기 기술이 아니다. 이러한 단점은 Service 클래스를 확장한 IntentService를 통해 해결할 수 있다.


12.1 기본사항

인텐트 서비스는 싱글 백그라운드 스레드에서 태스크를 실행한다.인텐트 서비스가 실행중이라면 큐에서 대기하고, 더이상 처리할 인텐트가 없을 때 생명주기가 끝난다. 인텐트 서비스는 활성화된 구성요소를 항상 포함하므로, 너무 일찍 태스크가 종료되는 문제를 막을 수 있다.


사용방법은 인텐트 서비스를 오버라이드 하고, 서비스 구성요소를 AndroidManifest.xml에 정의한다.

<service android:namd= ".SimpleIntentService />


구현은 onHandleIntent 메서드만 구현하면 된다.

public class SimpleIntentService extends IntentService {
    public SimpleIntentService() {
        super(SimpleIntentService.clas.getName());
        setIntentRedelivery(true);
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        // 백그라운드 스레드에서 호출됨
    }
}



12.2 인텐트 서비스를 사용하는 좋은 방법


12.2.1 순차적으로 정렬된 태스크

인텐트 서비스는 구성요소를 시작한 곳과 독립적이며, 순차적으로 실행되어야 하는 태스크에 사용할 수 있다.


예제 :  웹 서비스 통신

public class MainActivity extends AppCompatActivity {
    private final static String getUrl = "...";
    private final static String postUrl = "...";
    private ResultReceiver mRecevier;
    public MainActivity() {
        mRecevier = new ResultReceiver(new Handler()) {
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
                int httpStatus = resultCode;
                String jsonResult = null;
                if (httpStatus == 200) { // OK
                    if(resultData != null) {
                        jsonResult = resultData.getString(WebService.BUNDLE_KEY_REQUEST_RESULT);
                        // 생략됨 : 응답 처리
                    }
                } else {
                    // Error Handling
                }
            }
        };
    }

    private void doPost() {
        Intent intent = new Intent(this, WebService.class);
        intent.setData(Uri.parse(postUrl));
        intent.putExtra(WebService.INTENT_KEY_REQUEST_TYPE, WebService.POST);
        intent.putExtra(WebService.INTENT_KEY_JSON, "{\foo\":\"bar\"}");
        intent.putExtra(WebService.INTENT_KEY_RECEIVER, mRecevier);
        startService(intent);
    }

    private void doGet() {
        Intent intent = new Intent(this, WebService.class);
        intent.setData(Uri.parse(getUrl));
        intent.putExtra(WebService.INTENT_KEY_REQUEST_TYPE, WebService.GET);
        intent.putExtra(WebService.INTENT_KEY_RECEIVER, mRecevier);
        startService(intent);
    }
}

public class WebService extends IntentService {
    private static final String TAG = WebService.class.getName();
    public static final int GET = 1;
    public static final int POST = 2;

    public static final String INTENT_KEY_REQUEST_TYPE = "com.eat.INTENT_KEY_REQUEST_TYPE";
    public static final String INTENT_KEY_JSON = "com.eat.INTENT_KEY_JSON";
    public static final String INTENT_KEY_RECEIVER = "com.eat.INTENT_KEY_RECEIVER";
    public static final String BUNDLE_KEY_REQUEST_RESULT = "com.eat.BUNDLE_KEY_REQUEST_RESULT";

    public WebService() {
        super(TAG);
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        Uri uri = intent.getData();
        int requestType = intent.getIntExtra(INTENT_KEY_REQUEST_TYPE, 0 );
        String json = (String) intent.getSerializableExtra(INTENT_KEY_JSON);
        ResultReceiver receiver = intent.getParcelableExtra(INTENT_KEY_RECEIVER);

        try {
            HttpRequestBase request = null;
            switch (requestType) {
                case GET:
                    request = new HttpGet();
                    //요청 설정 생략
                    break;
                case POST :
                    request = new HttpPost();
                    if(json != null) {
                        ((HttpPost)request).setEntity(new StringEntity(json));
                    }
                    break;
            }

            if(request != null) {
                request.setURI(new URI(uri.toString()));
                HttpResponse response = doRequest(request);
                HttpEntity httpEntity = response.getEntity();
                StatusLine responseStatus = resoponse.getStatusLine();
                int statusCode = responseStatus != null ? responseStatus.getStatusCode() : 0;

                if(httpEntity != null) {
                    Bundle resultBundle = new Bundle();
                    resultBundle.putString(BUNDLE_KEY_REQUEST_RESULT, EntityUtils.toString(httpEntity));
                    receiver.send(statusCode, resultBundle);
                } else {
                    receiver.send(statusCode, null);
                }

            } else {
                receiver.send(0, null);
            }
        } catch (IOException e) {
            receiver.send(0, null);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    private HttpRequest doRequest(HttpRequestBase requst) throws IOException {
        HttpClient client = new DefaultHttpClient();

        // Http 설정 생략
        return client.execute(request);
    }
}

12.2.2 브로드캐스트 리시버에서 비동기 실행

브로드 캐스트 리시버는 UI스레드에서 호출되는 onReceive 콜백으로 인텐트를 보낸다. 따라서 오래 걸리는 작업이 실행되어야 하는 경우 비동기 실행이 필요하다.


onReceive가 종료되더라도 태스크가 실행을 보장받기 위해서는 인텐트 서비스를 사용해야 한다. 


12.3 인텐트 서비스와 서비스

인텐스 서비스는 서비스로부터 동일한 선언, 프로세스 순위에 대한 동일한 영향, 클라이언트를 위한 동일한 시작 요청 절차 등의 특성을 상속 받는다.


인텐트 서비스는 올바른 사용 사례에 대해서 매력적으로 사용이 간편하고 완벽한 해결책을 제공한다.


  • 클라이언트에 의한 제어
    다른 구성요소에 의해 제어되길 원한다면 사용자 제어 서비스를 선택하라
  • 동시적인 태스크 실행
    동시에 태스크를 실행하려면 서비스에서 여러 스레드를 시작하라
  • 순차적이고 재배열 가능한 태스크
    태스크 쿠를 우회하기 위해 태스크가 우선시 될 수 있다.
12.4 마치며
인텐트 서비스는 UI 스레드에서 뿐만 아니라 인텐트 서비스를 시작한 다른 구성요소에서의 작업을 떠넘기는 데 사용하기 유용한 태스크 처리기 이다. 인텐트 서비스는 다른 구성요소가 없는 독립적인 구성요소로 실행된다는 장점이 있다.


댓글
댓글쓰기 폼
공지사항
최근에 달린 댓글
Total
65,392
Today
3
Yesterday
1
TAG
more
«   2022/10   »
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
글 보관함