[android] 여러 기본 매개 변수를 AsyncTask에 어떻게 전달할 수 있습니까?

AsyncTask 클래스에 2 개의 매개 변수를 어떻게 전달할 수 있습니까? 와 같은 관련 질문이 있습니다 . ,하지만 AsyncTask에 매개 변수로 여러 개의 프리미티브를 전달하는 데 헛된 시도를하는 어려움에 부딪 혔으므로 발견 한 내용을 공유하고 싶습니다. 이 미묘함은 기존의 질문과 답변에 담겨 있지 않기 때문에 저와 같은 문제에 부딪히는 사람을 돕고 고통을 덜어주고 싶습니다.

질문은 이것이다 : 백그라운드에서 실행될 AsyncTask에 전달하려는 여러 개의 기본 매개 변수 (예 : 두 개의 long)가 있습니다. 어떻게 수행 할 수 있습니까? (내 대답 … 한동안 고생 한 후 … 아래에서 찾을 수 있습니다.)



답변

간단한 컨테이너에 기본 요소를 래핑하고 다음과 같이 매개 변수로 전달 AsyncTask하십시오.

private static class MyTaskParams {
    int foo;
    long bar;
    double arple;

    MyTaskParams(int foo, long bar, double arple) {
        this.foo = foo;
        this.bar = bar;
        this.arple = arple;
    }
}

private class MyTask extends AsyncTask<MyTaskParams, Void, Void> {
    @Override
    protected void doInBackground(MyTaskParams... params) {
        int foo = params[0].foo;
        long bar = params[0].bar;
        double arple = params[0].arple;
        ...
    }
}

다음과 같이 호출하십시오.

MyTaskParams params = new MyTaskParams(foo, bar, arple);
MyTask myTask = new MyTask();
myTask.execute(params);


답변

또 다른 방법 : MyTask 클래스에 MyTask 생성자를 추가하기 만하면됩니다.

private class MyTask extends AsyncTask<String, Void, Void> {
    int foo;
    long bar;
    double arple;

    MyTask(int foo, long bar, double arple) {
         // list all the parameters like in normal class define
        this.foo = foo;
        this.bar = bar;
        this.arple = arple;
    }
    ......   // Here is doInBackground etc. as you did before
}

그런 다음 전화

new MyTask(int foo, long bar, double arple).execute();

David Wasser의 답변과 같은 두 번째 방법.


답변

AsyncTask에 여러 프리미티브를 전달하는 것은 (엄격하게 말하면) 불가능합니다. 예를 들어 해당 방법 을 수행 myTask.execute(long1, long2)하고 설정 하려는 경우 private class myTask extends AsyncTask<long, Void, Void>:

@Override
protected LocationItemizedOverlay doInBackground(long... params) {...}

IDE는 상위 유형 메서드를 재정의해야한다고 불평 할 것입니다. 에 대한 소위 Varargs 메서드 서명을 사용 doInBackground하고 있습니다. (long... params)“나는 params라는 배열로 저장된 가변 수의 long을 허용합니다. 컴파일러 / IDE 불만이 제기되는 원인을 완전히 이해하지 못합니다. ,하지만 제네릭 클래스 Params가 정의 되는 방식과 관련이 있다고 생각합니다 .

어떤 경우 든, 프리미티브를 각각의 프리미티브가 아닌 래퍼 (예 : int => Integer, long => Long 등)로 올바르게 캐스트한다면 문제없이 원하는 것을 얻을 수 있습니다. 사실, 당신은 당신의 프리미티브를 프리미티브가 아닌 것으로 명시 적으로 캐스팅 할 필요가 없습니다. Java가 당신을 위해 그것을 처리하는 것 같습니다. 다음과 같이 ASyncTask를 설정하기 만하면됩니다 (예 : longs).

private class MyTask extends AsyncTask<Long, Void, Void> {

    @Override
    protected void doInBackground(Long... params) {
        // Do stuff with params, for example:
        long myFirstParam = params[0]
    }
    ...
}

그런 다음 원래 의도 한대로이 클래스를 사용할 수 있습니다. 예 :

MyTask myTask = new MyTask();
myTask.execute(long1, long2);

또는 원하는 수의 프리미티브에 대해 동일한 유형으로 제공됩니다. 여러 유형의 프리미티브를 전달해야하는 경우이 작업도 수행 할 수 있지만 위의 내용을 다음과 같이 수정해야합니다.

private class MyTask extends AsyncTask<Object, Void, Void> {

    @Override
    protected void doInBackground(Object... params) {
        // Do stuff with params, for example:
        long myLongParam = (Long) params[0];
        int myIntParam = (Integer) params[1];

    }
    ...
}

이것은 더 유연하지만 매개 변수를 각각의 유형으로 명시 적으로 캐스팅해야합니다. 이러한 유연성이 필요하지 않은 경우 (즉, 단일 데이터 유형), 약간 더 읽기 쉬운 첫 번째 옵션을 고수하는 것이 좋습니다.


답변

내장 된 execute 메소드는 Params 배열을 받아들이지 만 모두 정의 된 유형이어야합니다. 따라서 PARAM 유형을 OBJECT로 설정하면 객체의 자식 인 한 원하는대로 전달할 수 있습니다. …

private class MyTask extends AsyncTask<Object, Void, Void> {

그런 다음 doInBackGround에서 각 매개 변수를 필요한 것으로 되돌리기 위해 간단히 캐스팅합니다.

 @Override
 protected void doInBackground(Object... params) {
     Context t = (Context)params[0];
     String a = (String) params[1];
     List<LatLng> list = (List<LatLng>)params[2];
     .
     .
     .

그리고 실행은 간단합니다.

 new MyTask().execute(context,somestring,list_of_points);

자신의 래퍼 클래스, 번들 또는 해시 등으로 포장하는 것만 큼 좋은 형식은 아닙니다. 주문은 양쪽에 종속되어 있기 때문에 작동합니다. 물론 배열을 HashMap (,)의 매개 변수로 만들 수 있으며 기본적으로 그 시점에서 번들을 사용자 정의 구현하지만 작동합니다.


답변

나는 malajisi의 방법을 좋아하지만 그렇지 않다면 Bundle 클래스를 사용할 수 없습니까?

 Bundle myBundle = new Bundle();
 myBundle.putInt("foo", foo);
 myBundle.putLong("bar", bar);
 myBundle.putDouble("arple", arple);

그런 다음 번들을 전달하고 MyTask에서 압축을 풉니 다. 이것은 끔찍한 생각입니까? 사용자 지정 클래스를 만들지 않고 나중에 추가 매개 변수를 전달해야하는 경우 유연합니다.

업데이트 :이 답변을 작성한 지 꽤 몇 년이 지났고 지금은 정말 싫어합니다. 번들을 사용하지 않는 것이 좋습니다. 여러 매개 변수를 비동기 작업 (또는 실제로)에 전달해야하는 경우 모든 매개 변수를 한 번에 보유하는 사용자 정의 클래스를 사용하십시오. 번들을 사용하면 안되는 문제에 대한 훌륭한 해결책이됩니다. 필요한 것을 정확히 담기 위해 커스텀 클래스를 만드는 법은 없습니다.

또한 코 루틴을 사용하지 않는 이유는 무엇입니까? Asynctasks은 그래서 2014.


답변

이것은 서브 클래 싱을 통해 해결됩니다. Google은 공식 Android AsyncTask 문서에이 문제 (서브 클래 싱)를 해결하는 예가 있습니다.

http://developer.android.com/reference/android/os/AsyncTask.html

예:

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");
    }
}


답변