Program/Android Java

Android AsyncTaskLoader

너구리V 2013. 1. 10. 19:18

출처 : http://itzone.tistory.com/464

최근 비동기 처리를하기 위해서는 Loader 클래스가 사용되는 것 같습니다. Android3.0 (API Level 11)에서 도입된 비동기 처리를 실시하는 클래스입니다. 서브 클래스로 AsyncTaskLoader이나 CursorLoader가 정의되어 있습니다

Loader 클래스는 SupportPackage에도 들어 있기 때문에 어떤 Version에서든 이용이 가능합니다. 지금까지 AsyncTask로 실행했던 것을 AsyncTaskLoader에서 구현하여 차이를보고 있습니다

리뉴얼 된 레퍼런스 페이지에는 Loader 관련 정보는 여기 에 집약되어 있습니다. 그 설명을 대충 보면

Introduced in Android 3.0 loaders make it easy to asynchronously load data in an activity or fragment. Loaders have these characteristics : 
· They are available to every Activity and Fragment. 
· They provide asynchronous loading of data. 
· They monitor the source of their data and deliver new results when the content changes. 
· They automatically reconnect to the last loader 's cursor when being recreated after a configuration change. Thus, they don't need to re-query their data.

비동기 처리하기위한 도구 같습니다. Fragment에도 비동기 처리를 사용할 수 있도록 새롭게 재 설계 한 클래스일까요?

이전에는 AsyncTask를 이용하여 비동기 처리를 실현하고 있었다고 생각합니다. AsyncTask의 설명은 다음과 같이 기술되어 있습니다

AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and / or handlers

AsyncTask는 Handler와 Thread를 이용하지 않고 UI Thread를 이용하여 Background 작업을하고 있던 것 같습니다. Loader 클래스의 설명을 보면, UI Thread와 같은 단어는 보여지지 않기 때문에 (실행해봤더니 UI 처리를하면 예외를 뱉고 강종됩니다), 실행할 수있는 것은 동일하지만, 근본적으로 설계가 다른 클래스 인 것 같습니다

AsyncTask의 동작 이미지

같은 화면의 UI를 제어하는​​ 코드가 여러 클래스에 포함되어 있습니다.

AsyncTaskLoader 동작 이미지

같은 화면에서 표시하는 Progress와 비동기 처리 완료 후 View 갱신 처리 등 UI 제어에 대한 코드는 한자리에 있습니다. AsyncTaskLoader에서 결과만 LoaderCallback을 통해 통지됩니다.

다음으로 AsyncTaskLoader를 상속하여 구현 한 경우, 구체적으로 어떤 차이가 있는지를 살펴 보겠습니다.

구현 예제 (기본 바탕)

URL을 지정하여 Web 상에있는 이미지를 가져오고 그것을 ImageView에 표시하는 작업을 살펴​​ 보겠습니다

AsyncTask를 사용하는 경우

01public class DownloadImageAsyncTaskHelper extends AsyncTask<string, string, bitmap> {
02  
03    @ Override
04    protected Bitmap doInBackground(String... urls) {
05         String url = urls[0];
06           
07         // Progress Dialog보기
08         publishProgress("Loading from" + url);
09         return HttpUtil.getBitmapHttpService(context, url);
10     }
11  
12     @ Override
13     protected void onProgressUpdate(String... progress) {
14         // ProgressDialog에 문자열을 설정
15         setProgressMessage(progress[0]);
16     }
17  
18     @ Override
19     protected void OnPostExecute(Bitmap result) {
20         // 비동기 적으로로드가 완료 이미지를 View에 표시
21         showImage(result);
22     }
23}

비동기 처리에 필요한 초기 매개 변수, 경과를 나타내는 Progress 매개 변수, 결과의 형태 등 지정하는 것이 많네요.

또한 doInBackground()에서 실행되는 비동기 이미지 읽기와 showImage() setProgerssMessage() 등의 UI 업데이트 작업도 포함되어 있습니다. AsyncTask는 UI Thread에서 실행되기 때문에 UI의 변경도 가능하기 때문입니다.

AsyncTaskLoader를 이용하는 경우

마찬가지로 URL을 지정하고 Web에서 이미지를 가져 와서 ImageView에 표시하는 작업을 구현 봅니다

01public class DownloadImageAsyncTaskLoaderHelper extendsAsyncTaskLoader<bitmap> {
02  
03    private String imageUrl = "";
04    private Context Context = null;
05      
06    public DownloadImageAsyncTaskLoaderHelper(Context context, String url) {
07        super (context);
08          
09        this.imageUrl = url;
10        this.context = context;
11    }
12  
13    @Override
14    public Bitmap loadInBackground() {
15         return HttpUtil.getBitmapHttpService(context, url);
16    }
17      
18    @Override
19    protected void onStartLoading() {
20        forceLoad();
21    }
22}

Progress 표시 비동기 처리 종료시 View 업데이트 등의 UI 제어 코드가 없어 정돈된 느낌입니다. UI Thread가 얽혀 있지 않기 때문에 UI 변경은 여기서 할 수 없습니다. 만약 AsyncTask처럼 UI 변경하면 UI Thread 이외 View 변경 때 Throw되는 항상 예외가 발생합니다

Caused by : android.view.ViewRoot $ CalledFromWrongThreadException : Only the original thread that created a view hierarchy can touch its views.

또한 AsyncTask에 비해 다른 것은 결과의 형식만 지정되어 있습니다. 그럼, 어디서 종료시 View 업데이트 등의 UI 업데이트를 실시하면 좋을까요?

AsyncTaskLoader 결과를 받으려면

LoaderCallbacks 이라는 Interface를 구현 해주는 것으로, 비동기 처리 결과를받을 수 있습니다

이때 주의해야 할 점이 있습니다. SupportPakcage를 이용할 경우, Loader를 이용하는 방법(getSupportLoaderManager)이 "FragmentActivity"에 포함되어 있기 때문에 Activity에서 실행하려면 "FragmentActivity"을 상속 해 줄 필요가 있습니다

01public class MainActivity extends FragmentActivity Implements LoaderCallbacks<bitmap> {
02    // Loader의 초기화에서 시작까지
03    public void startAsyncLoadImage(String url) {
04        Bundle args = New Bundle();
05        args.putString("url", url);
06        getSupportLoaderManager().initLoader(0, args, this);     // onCreateLoader가 호출
07          
08        // 여러 Loader를 동시에 움직일 경우에는 첫 번째 인수를 고유 ID를 해 줄 필요가 있습니다.
09        // GridView 등에 표시하는 이미지를 비동기로 단번에 취득하는 경우 나
10    }
11      
12    @Override
13    public Loader<bitmap> onCreateLoader(int ID, Bundle args) {        
14        // 비동기 처리를 수행하는 Loader를 생성합니다.
15        // 여기를 전환주는 것만으로 다양한 비동기 처리에 대응할 수 있습니다.
16        if (args! = null) {
17            String url = args.getString("url");
18            return New DownloadImageAsyncTaskLoaderHelper(this, url);
19        }
20    }
21      
22    @Override
23    public void onLoadFinished(Loader<bitmap> arg0, Bitmap arg1) {    
24        // 비동기 처리가 끝나면 불립니다.
25        // 이번은 Download가 완료 이미지를 ImageView에 표시합니다.
26        ImageView imageView = (ImageView)findViewById(R.id.imageview);
27        Drawable iconImage = New BitmapDrawable(getResources(), bmp);
28        imageView.setImageDrawable(iconImage);
29        imageView.invalidate();
30    }
31      
32    @Override
33    public void onLoaderReset(Loader<bitmap> arg0) {
34          
35    }
36}

비동기 처리 부분과 UI 업데이트 부분을 명확하게 나눌 수 있습니다. UI의 제어에 관련되는 부분이한데 모아져 코드가 분산되지 않기 때문에 기존보다 역할 분담이 명확하게되었습니다.

정리

  • AsyncTaskLoader를 사용하면 UI 제어 및 비동기 처리의 역할 분담을 명확하게 나눌 수있다.
  • SupportPackage에 들어 있기 때문에, 지금이라도 사용 가능.
  • 무엇보다 최근의 비동기 처리 구현이므로 멋지다. (아마도)

반응형