AsyncTask deprecated에 따른 대응방안

happytory·2023년 1월 11일
0

This class was deprecated in API level 30.

Use the standard java.util.concurrent or Kotlin concurrency utilities instead.

AsyncTask 란?

  • 안드로이드에서 스레드나 메시지 루프 등의 원리를 이해하지 않아도 하나의 클래스에서 UI 작업을 쉽게 할 수 있게 해주는 제공하는 클래스 (스레드 - 핸들러의 추상화
    개념)

기존 AsyncTask 사용방법

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
     protected Long doInBackground(URL... urls) {
         int count = urls.length;
         long totalSize = 0;
         for (int i = 0; i < count; i++) {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
             // Escape early if cancel() is called
             if (isCancelled()) break;
         }
         return totalSize;
     }

     protected void onProgressUpdate(Integer... progress) {
         setProgressPercent(progress[0]);
     }

     protected void onPostExecute(Long result) {
         showDialog("Downloaded " + result + " bytes");
     }
 }

//실행
new DownloadFilesTask().execute(url1, url2, url3);

deprecated 된 이유는?

  • 일반적인 사용 사례는 UI에 통합하기 위한 것이었고, 이는 컨텍스트 누출을 유발합니다.
  • 콜백 또는 구성 변경 시 충돌합니다. 또한 서로 다른 환경에서 일관되지 않은 동작을 합니다.

1. java.util.concurrent 패키지에서 제공하는 다양한 API

ExecutorService executorService = Executors.newFixedThreadPool(4);
Handler mainThreadHandler = HandlerCompat.createAsync(Looper.getMainLooper());

//
public class LoginRepository {
    ...
    private final Handler resultHandler;

    public LoginRepository(LoginResponseParser responseParser, Executor executor,
            Handler resultHandler) {
        this.responseParser = responseParser;
        this.executor = executor;
        this.resultHandler = resultHandler;
    }

    public void makeLoginRequest(
        final String jsonBody,
        final RepositoryCallback<LoginResponse> callback
    ) {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Result<LoginResponse> result = makeSynchronousLoginRequest(jsonBody);
                    notifyResult(result, callback);
                } catch (Exception e) {
                    Result<LoginResponse> errorResult = new Result.Error<>(e);
                    notifyResult(errorResult, callback);
                }
            }
        });
    }

    private void notifyResult(
        final Result<LoginResponse> result,
        final RepositoryCallback<LoginResponse> callback,
    ) {
        resultHandler.post(new Runnable() {
            @Override
            public void run() {
                callback.onComplete(result);
            }
        });
    }
    ...
}

2. RxJava 활용

  • RxJava는 Java로 Reactive Programming을 할 수 있는 라이브러리이며, 비동기 프로그래밍과 함수형 프로그래밍 기법을 함께 활용한다.
  • ReactiveX는 관찰 가능한(Observable) 스트림을 사용하는 비동기 프로그래밍을 위한 API이다.
interface StackOverflowService {
	@GET("/users")
	fun getTopUsers(): Single<List<User>>
    
	@GET("/users/{userId}/badges")
	fun getBadges(
    		@Path("userId") userId: Int
	): Single<List<Badge>>
    
	@GET("/users/{userId}/top-tags")
	fun getTags(
   		@Path("userId") userId: Int
	): Single<List<Tag>>
}


class MyViewModel(
	private val service: StackOverflowService
) : ViewModel() {

	private val disposable = CompositeDisposable()

	fun load() {
		disposable +=
			service.getTopUsers()
				.subscribeOn(io())
				.observeOn(mainThread())
				.subscribe(
					{ users -> updateUi(users) },
					{ e -> updateUi(e) }
				)
	}
    
	private fun updateUi(s: Any) {
		//...
	}
    
	override fun onCleared() {
		disposable.clear()
	}
}

3. koltin 코루틴 활용

interface StackOverflowService {
	@GET("/users")
	suspend fun getTopUsers(): List<User>
    
	@GET("/users/{userId}/badges")
	suspend fun getBadges(
    		@Path("userId") userId: Int
	): List<Badge>
    
	@GET("/users/{userId}/top-tags")
	suspend fun getTags(
   		@Path("userId") userId: Int
	): List<Tag>
}

class MyViewModel(
	private val service: StackOverflowService
) : ViewModel() {

	fun load() {
		viewModelScope.launch {
			try {
				val users = service.getTopUsers()
				updateUi(users)
			} catch (e: Exception) {
				updateUi(e)
			}
		}
	}
    
	private fun updateUi(s: Any) {
		//...
	}
}

4. 대응방안

  • 구글은 깔끔한 처리를 위해 코루틴을 사용하길 권장하나 코루틴을 사용하려면 코틀린에서만 가능하며 코틀린으로 마이그레이션을 하기전까지는 java.util.concurrent 활용
  • 추후 구글의 정책, 더 나은 안정성과 생산성을 위해 Kotlin과 Coroutines 라이브러리를 함께 사용
profile
mobile developer

0개의 댓글