java 예제 - 안드로이드:AsyncTask에 함수 참조 전달




포인터 콜백 (3)

나는 안드로이드에 익숙하며 웹 개발에 익숙합니다. 자바 스크립트에서 비동기 작업을 수행하려는 경우 함수를 인수로 전달합니다 (콜백).

http.get('www.example.com' , function(response){
   //some code to handle response
});

안드로이드의 AsyncTask 하여 동일한 작업을 수행 할 수 있는지, onPostExecute() 메소드에 대한 함수 참조를 전달하는지, 그리고 실행할지 궁금합니다.

어떤 제안?


Answers

그렇습니다. 콜백 개념은 자바에도 매우 많이 존재합니다. Java에서는 다음과 같이 콜백을 정의합니다.

public interface TaskListener {
    public void onFinished(String result);
}

다음과 같이 AsyncTask 내부에 이러한 종류의 리스너 정의를 중첩하는 경우가 많습니다.

public class ExampleTask extends AsyncTask<Void, Void, String> {

    public interface TaskListener {
        public void onFinished(String result);
    }

    ...
}

그리고 AsyncTask 에서 콜백의 완전한 구현은 다음과 같습니다.

public class ExampleTask extends AsyncTask<Void, Void, String> {

    public interface TaskListener {
        public void onFinished(String result);
    }

    // This is the reference to the associated listener
    private final TaskListener taskListener;

    public ExampleTask(TaskListener listener) {
        // The listener reference is passed in through the constructor
        this.taskListener = listener;
    }

    @Override
    protected String doInBackground(Void... params) {
        return doSomething();
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);

        // In onPostExecute we check if the listener is valid
        if(this.taskListener != null) {

            // And if it is we call the callback function on it.
            this.taskListener.onFinished(result);
        }
    }
}

백그라운드 작업이 끝나자 마자 onPostExecute() 가 호출됩니다. 이런 모든 것을 사용할 수 있습니다 :

ExampleTask task = new ExampleTask(new ExampleTask.TaskListener() {
    @Override
    public void onFinished(String result) {
        // Do Something after the task has finished
    }
});

task.execute();

또는 다음과 같이 TaskListener 완전히 따로 정의 할 수 있습니다.

ExampleTask.TaskListener listener = new ExampleTask.TaskListener() {
    @Override
    public void onFinished(String result) {
        // Do Something after the task has finished
    }
};

ExampleTask task = new ExampleTask(listener);    
task.execute();

또는 다음과 같이 TaskListener 를 하위 클래스 TaskListener 수 있습니다.

public class ExampleTaskListener implements TaskListener {

    @Override
    public void onFinished(String result) {

    }
}

그리고 다음과 같이 사용하십시오 :

ExampleTask task = new ExampleTask(new ExampleTaskListener());    
task.execute();

물론 AsyncTaskonPostExecute() 메소드를 오버라이드 할 수는 있지만, 이는 권장되지 않으며 대부분의 경우 실제로는 꽤 나쁜 습관입니다. 예를 들어 다음과 같이 할 수 있습니다.

ExampleTask task = new ExampleTask() {
    @Override
    public void onPostExecute(String result) {
        super.onPostExecute(result);

        // Your code goes here
    }
};

위와 같은 구현은 별도의 리스너 인터페이스로 작동하지만 몇 가지 문제가 있습니다.

무엇보다 먼저 실제로 ExampleTask 모두 깨뜨릴 수 있습니다. 위의 super.onPostExecute() 호출은 모두 super.onPostExecute() . 개발자 인 경우 위와 같이 onPostExecute() 재정의하고 Super 호출을 포함하거나 ExampleTask 의 원래 onPostExecute() 메서드가 더 이상 호출되지 않는 이유를 막론하고 단순히 삭제해야합니다. 예를 들어, TaskListener 에 대한 호출이 onPostExecute() 에서 구현 되었기 때문에 TaskListener 사용한 전체 리스너 구현이 갑자기 작동하지 않게됩니다. 또한 무의식적으로 또는 무의식적으로 ExampleTask 의 상태에 영향을 주어 더 이상 작동하지 않게함으로써 다른 많은 방법으로 TaskListener 를 중단 할 수 있습니다.

이와 같은 방법을 재정의 할 때 실제 일어나고있는 일을 살펴보면 진행 상황이 훨씬 명확 해집니다. onPostExecute() 를 재정 의하여 ExampleTask 의 새 하위 클래스를 ExampleTask . 이렇게하는 것은 똑같은 일이 될 것입니다 :

public class AnotherExampleTask extends ExampleTask {

    @Override
    public void onPostExecute(String result) {
        super.onPostExecute(result);

        // Your code goes here
    }
}

이 모든 것은 익명 클래스라는 언어 기능 뒤에 숨어 있습니다. 갑자기이 방법을 재정의하는 것은 더 이상 깨끗하지 않고 빠른 것으로 보이지 않습니다.

요약하려면 다음을 수행하십시오.

  • 이와 같은 메서드를 재정의하면 실제로 새 하위 클래스가 만들어집니다. 당신은 단지 콜백을 추가하는 것이 아니라,이 클래스가 어떻게 작동 하는지를 수정하고 있으며, 무의식적으로 많은 것을 깨뜨릴 수 있습니다.
  • 이와 같은 디버깅 오류는 a2의 단순한 고통 이상의 것일 수 있습니다. 갑자기 ExampleTaskExceptions throw하거나 실제로 코드를 수정하지 않았기 때문에 명백한 이유없이 더 이상 작동하지 않을 수 있기 때문입니다.
  • 각 클래스는 적절하고 의도 된 곳에서 리스너 구현을 제공해야합니다. 물론 나중에 onPostExecute() 를 재정 의하여 추가 할 수는 있지만 항상 위험합니다. 그의 13k 평판을 가진 @flup조차도 그의 대답에 super.onPostExecute() 호출을 포함하는 것을 잊어 버렸습니다. 숙련 된 개발자가 아닌 다른 개발자가 상상해보십시오!
  • 약간의 추상화는 결코 아무도 다치게하지 않습니다. 특정 수신기를 작성하는 것은 약간 더 많은 코드 일 수 있지만 훨씬 좋은 해결책입니다. 코드는보다 깨끗하고 읽기 쉽고 유지 보수가 용이합니다. onPostExecute() 재정의하는 것과 같은 단축키를 사용하면 약간의 편리함을 위해 코드 품질이 희생됩니다. 장기적으로는 문제를 일으키는 좋은 아이디어는 결코 아닙니다.

자바에서는 함수가 JavaScript보다 일등 시민권에 덜 부합합니다. AsyncTask는 클래스의 메서드로 콜백을 제공하며이를 재정의해야합니다.

웹 요청을하는 doInBackground 구현을 사용하여 AsyncTask의 하위 클래스 인 android로 HTTP 요청 만들기를 참조하십시오.

서로 다른 콜백을 사용하여 여러 HTTP 요청을 수행하려는 경우 RequestTask를 재정 의하여 다른 콜백 구현을 사용하여 onPostExecute를 구현할 수 있습니다. 익명 클래스를 사용하여 자바 스크립트 콜백이 일반적으로 사용하는 클로저를 시뮬레이트 할 수 있습니다.

new RequestTask(){
    @Override
    public void onPostExecute(String result) {
        // Implementation has read only access to 
        // final variables in calling scope. 
    }
}.execute("http://.com");

Xaver이 보여 주듯이 리스너를위한 완전한 인터페이스를 만들 수도 있습니다. 이것은 몇 가지 기본 onPostExecute 함수를 구현하고 특정 호출에 대해 이러한 기본 구현 중 하나를 선택하려는 경우 유용합니다.


아래 소스 코드를 참조하십시오.

/**
 * Used to determine whether the user making this call is subject to
 * teleportations.
 *
 * <p>As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this method can
 * now automatically identify goats using advanced goat recognition technology.</p>
 *
 * @return Returns true if the user making this call is a goat.
 */
public boolean isUserAGoat() {
    return mContext.getPackageManager()
            .isPackageAvailable("com.coffeestainstudios.goatsimulator");
}




java android android-asynctask