development

AsyncTask가 별도의 클래스이기 때문에 OnPostExecute () 결과를 주요 활동으로 가져 오는 방법은 무엇입니까?

big-blog 2020. 3. 4. 07:53
반응형

AsyncTask가 별도의 클래스이기 때문에 OnPostExecute () 결과를 주요 활동으로 가져 오는 방법은 무엇입니까?


이 두 수업이 있습니다. 내 주요 활동과를 확장하는 AsyncTask활동, 이제 내 주요 활동에서의 결과를 가져와야 OnPostExecute()합니다 AsyncTask. 주요 활동에 결과를 전달하거나 얻는 방법은 무엇입니까?

샘플 코드는 다음과 같습니다.

나의 주요 활동.

public class MainActivity extends Activity{

    AasyncTask asyncTask = new AasyncTask();

    @Override
    public void onCreate(Bundle aBundle) {
        super.onCreate(aBundle);            

        //Calling the AsyncTask class to start to execute.  
        asyncTask.execute(a.targetServer); 

        //Creating a TextView.
        TextView displayUI = asyncTask.dataDisplay;
        displayUI = new TextView(this);
        this.setContentView(tTextView); 
    }

}

이것은 AsyncTask 클래스입니다

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

TextView dataDisplay; //store the data  
String soapAction = "http://sample.com"; //SOAPAction header line. 
String targetServer = "https://sampletargeturl.com"; //Target Server.

//SOAP Request.
String soapRequest = "<sample XML request>";    



@Override
protected String doInBackground(String... string) {

String responseStorage = null; //storage of the response

try {


    //Uses URL and HttpURLConnection for server connection. 
    URL targetURL = new URL(targetServer);
    HttpURLConnection httpCon = (HttpURLConnection) targetURL.openConnection();
    httpCon.setDoOutput(true);
    httpCon.setDoInput(true);
    httpCon.setUseCaches(false); 
    httpCon.setChunkedStreamingMode(0);

    //properties of SOAPAction header
    httpCon.addRequestProperty("SOAPAction", soapAction);
    httpCon.addRequestProperty("Content-Type", "text/xml; charset=utf-8"); 
    httpCon.addRequestProperty("Content-Length", "" + soapRequest.length());
    httpCon.setRequestMethod(HttpPost.METHOD_NAME);


    //sending request to the server.
    OutputStream outputStream = httpCon.getOutputStream(); 
    Writer writer = new OutputStreamWriter(outputStream);
    writer.write(soapRequest);
    writer.flush();
    writer.close();


    //getting the response from the server
    InputStream inputStream = httpCon.getInputStream(); 
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
    ByteArrayBuffer byteArrayBuffer = new ByteArrayBuffer(50);

    int intResponse = httpCon.getResponseCode();

    while ((intResponse = bufferedReader.read()) != -1) {
        byteArrayBuffer.append(intResponse);
    }

    responseStorage = new String(byteArrayBuffer.toByteArray()); 

    } catch (Exception aException) {
    responseStorage = aException.getMessage(); 
    }
    return responseStorage;
}

protected void onPostExecute(String result) {

    aTextView.setText(result);

}       

}   

쉬운:

  1. 선택 사항 인 interface클래스를 작성 String output하거나 리턴하려는 변수가 될 수 있습니다.

    public interface AsyncResponse {
        void processFinish(String output);
    }
    
  2. AsyncTask클래스로 이동하여 인터페이스 AsyncResponse를 필드로 선언 하십시오 .

    public class MyAsyncTask extends AsyncTask<Void, Void, String> {
      public AsyncResponse delegate = null;
    
        @Override
        protected void onPostExecute(String result) {
          delegate.processFinish(result);
        }
     }
    
  3. 주요 활동에서 당신은 implements인터페이스 해야합니다 AsyncResponse.

    public class MainActivity implements AsyncResponse{
      MyAsyncTask asyncTask =new MyAsyncTask();
    
      @Override
      public void onCreate(Bundle savedInstanceState) {
    
         //this to set delegate/listener back to this class
         asyncTask.delegate = this;
    
         //execute the async task 
         asyncTask.execute();
      }
    
      //this override the implemented method from asyncTask
      @Override
      void processFinish(String output){
         //Here you will receive the result fired from async class 
         //of onPostExecute(result) method.
       }
     }
    

최신 정보

나는 이것이 당신에게 많은 것을 좋아한다는 것을 몰랐습니다. 간단하고 편리한 사용 방법은 다음과 같습니다 interface.

여전히 같은 것을 사용 interface합니다. 참고로, 이것을 AsyncTask클래스 로 결합 할 수 있습니다 .

에서 AsyncTask클래스 :

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

  // you may separate this or combined to caller class.
  public interface AsyncResponse {
        void processFinish(String output);
  }

  public AsyncResponse delegate = null;

    public MyAsyncTask(AsyncResponse delegate){
        this.delegate = delegate;
    }

    @Override
    protected void onPostExecute(String result) {
      delegate.processFinish(result);
    }
}

당신이 작업을 수행 Activity클래스

public class MainActivity extends Activity {

   MyAsyncTask asyncTask = new MyAsyncTask(new AsyncResponse(){

     @Override
     void processFinish(String output){
     //Here you will receive the result fired from async class 
     //of onPostExecute(result) method.
     }
  }).execute();

 }

또는 Activity에서 인터페이스를 다시 구현하십시오.

public class MainActivity extends Activity 
    implements AsyncResponse{

    @Override
    public void onCreate(Bundle savedInstanceState) {

        //execute the async task 
        new MyAsyncTask(this).execute();
    }

    //this override the implemented method from AsyncResponse
    @Override
    void processFinish(String output){
        //Here you will receive the result fired from async class 
        //of onPostExecute(result) method.
    }
}

위의 첫 번째 솔루션과 세 번째 솔루션의 두 가지 솔루션을 볼 수 있듯이 method를 작성해야 processFinish하며 다른 하나는 caller 매개 변수 내에 있습니다. 세 번째는 중첩 된 익명 클래스가 없기 때문에 더 깔끔합니다. 도움이 되었기를 바랍니다

: 변경 String output, String responseString result다른 일치 유형에 다른 개체를 얻기 위해.


몇 가지 옵션이 있습니다.

  • AsyncTask수업 내 에서 수업을 중첩시킵니다 Activity. 여러 작업에서 동일한 작업을 사용하지 않는 경우 가장 쉬운 방법입니다. 모든 코드가 동일하게 유지되므로 기존 작업 클래스를 활동 클래스 내부의 중첩 클래스로 이동하기 만하면됩니다.

    public class MyActivity extends Activity {
        // existing Activity code
        ...
    
        private class MyAsyncTask extends AsyncTask<String, Void, String> {
            // existing AsyncTask code
            ...
        }
    }
    
  • AsyncTask대한 참조를 사용 하는 사용자 정의 생성자를 만듭니다 Activity. 과 같은 작업을 인스턴스화합니다 new MyAsyncTask(this).execute(param1, param2).

    public class MyAsyncTask extends AsyncTask<String, Void, String> {
        private Activity activity;
    
        public MyAsyncTask(Activity activity) {
            this.activity = activity;
        }
    
        // existing AsyncTask code
        ...
    }
    

이 클래스는 Main 클래스에서 시도 할 수 있습니다. 그것은 나를 위해 일했지만 다른 방법으로 메소드를 구현했습니다.

try {
    String receivedData = new AsyncTask().execute("http://yourdomain.com/yourscript.php").get();
} 
catch (ExecutionException | InterruptedException ei) {
    ei.printStackTrace();
}

아래 접근 방식이 매우 쉽다고 생각했습니다.

콜백에 대한 인터페이스를 선언했습니다

public interface AsyncResponse {
    void processFinish(Object output);
}

그런 다음 모든 유형의 병렬 요청에 응답하는 비동기 작업을 만들었습니다.

 public class MyAsyncTask extends AsyncTask<Object, Object, Object> {

    public AsyncResponse delegate = null;//Call back interface

    public MyAsyncTask(AsyncResponse asyncResponse) {
        delegate = asyncResponse;//Assigning call back interfacethrough constructor
    }

    @Override
    protected Object doInBackground(Object... params) {

      //My Background tasks are written here

      return {resutl Object}

    }

    @Override
    protected void onPostExecute(Object result) {
        delegate.processFinish(result);
    }

}

그런 다음 활동 클래스에서 단추를 클릭 할 때 비동기 태스크를 호출했습니다.

public class MainActivity extends Activity{

    @Override
    public void onCreate(Bundle savedInstanceState) {

    Button mbtnPress = (Button) findViewById(R.id.btnPress);

    mbtnPress.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                MyAsyncTask asyncTask =new MyAsyncTask(new AsyncResponse() {

                    @Override
                    public void processFinish(Object output) {
                        Log.d("Response From Asynchronous task:", (String) output);

                        mbtnPress.setText((String) output);
                   }
                });

                asyncTask.execute(new Object[] { "Your request to aynchronous task class is giving here.." });


            }
        });

    }



}

감사


이 답변은 늦을 수도 있지만에 Activity의지 할 때 몇 가지 언급하고 싶습니다 AsyncTask. 충돌 및 메모리 관리를 방지하는 데 도움이됩니다. 위의 답변에서 이미 언급했듯이 interface콜백이라고도합니다. 그들은 정보원으로 일할 것이지만, 그런 경우에는 결코 강력한 참조를 보내 Activity거나 interface항상 약한 참조를 사용 하지 않습니다 .

이것이 어떻게 문제를 일으킬 수 있는지 알아 보려면 아래 스크린 샷을 참조하십시오.

여기에 이미지 설명을 입력하십시오

우리 AsyncTask강력한 참조로 시작했는지 알 수 있듯이 데이터를 얻을 때까지 Activity/ 우리 Fragment가 살아있을 것이라는 보장이 없으므로 WeakReference그러한 경우 에 사용하는 것이 더 좋으며 우리가 결코 잡지 않을 메모리 관리에 도움이 될 것입니다 우리의 강력한 참조 Activity는 왜곡 후 가비지 수집 대상이 될 것입니다.

멋진 WeakReference를 사용하는 방법을 알아 보려면 아래 코드 스 니펫을 확인하십시오.

MyTaskInformer.java 정보원으로 작동하는 인터페이스입니다.

public interface MyTaskInformer {

    void onTaskDone(String output);

}

MySmallAsyncTask.javaAsyncTask는 장기 실행 작업을 수행합니다 WeakReference.

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

    // ***** Hold weak reference *****
    private WeakReference<MyTaskInformer> mCallBack;

    public MySmallAsyncTask(MyTaskInformer callback) {
        this.mCallBack = new WeakReference<>(callback);
    }

    @Override
    protected String doInBackground(String... params) {

        // Here do whatever your task is like reading/writing file
        // or read data from your server or any other heavy task

        // Let us suppose here you get response, just return it
        final String output = "Any out, mine is just demo output";

        // Return it from here to post execute
        return output;
    }

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

        // Here you can't guarantee that Activity/Fragment is alive who started this AsyncTask

        // Make sure your caller is active

        final MyTaskInformer callBack = mCallBack.get();

        if(callBack != null) {
            callBack.onTaskDone(s);
        }
    }
}

MainActivity.java이 클래스는 이 클래스 와이 필수 메소드 에서 AsyncTask구현 을 시작하는 데 사용됩니다 .interfaceoverride

public class MainActivity extends Activity implements MyTaskInformer {

    private TextView mMyTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mMyTextView = (TextView) findViewById(R.id.tv_text_view);

        // Start your AsyncTask and pass reference of MyTaskInformer in constructor
        new MySmallAsyncTask(this).execute();
    }

    @Override
    public void onTaskDone(String output) {

        // Here you will receive output only if your Activity is alive.
        // no need to add checks like if(!isFinishing())

        mMyTextView.setText(output);
    }
}

AsyncTask를 호출 할 때 onPostExecute를 재정의하면 몇 줄로 할 수 있습니다. 다음은 예입니다.

new AasyncTask()
{
    @Override public void onPostExecute(String result)
    {
       // do whatever you want with result 
    }
}.execute(a.targetServer);

나는 그것이 당신에게 도움이되기를 바랍니다, 행복한 코딩 :)


Oncreate ()에서 :

`

myTask.execute("url");
String result = "";
try {
      result = myTask.get().toString();
} catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
}catch (ExecutionException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();

}`


사람들이 왜 그렇게 어렵게 만드는가?

이것으로 충분합니다.

비동기 작업에서 onPostExecute를 구현하지 말고 Activity에서 구현하십시오.

public class MainActivity extends Activity 
{

@Override
public void onCreate(Bundle savedInstanceState) {

    //execute the async task 
    MyAsyncTask task = new MyAsyncTask(){
            protected void onPostExecute(String result) {
                //Do your thing
            }       

    }

    task.execute("Param");

}


}

get()메소드 AsyncTask(또는 오버로드 된 get(long, TimeUnit))를 호출 할 수 있습니다 . 이 메소드는 AsyncTask작업이 완료 될 때까지 차단되며이 시점에서을 (를) 리턴합니다 Result.

비동기 작업 생성 / 시작과 get메서드 호출간에 다른 작업을 수행하는 것이 현명 할 것입니다 . 그렇지 않으면 비동기 작업을 매우 효율적으로 활용하지 못합니다.


안녕 당신은 이런 식으로 만들 수 있습니다 :

  1. AsyncTask를 구현하는 클래스 만들기

    // TASK 
    public class SomeClass extends AsyncTask<Void, Void, String>>
    {
    
        private OnTaskExecutionFinished _task_finished_event;
    
        public interface OnTaskExecutionFinished
        {
            public void OnTaskFihishedEvent(String Reslut);
        }
    
        public void setOnTaskFinishedEvent(OnTaskExecutionFinished _event)
        {
            if(_event != null)
            {
                this._task_finished_event = _event;
            }
        }
    
        @Override
        protected void onPreExecute()
        {
            super.onPreExecute();
    
        }
    
        @Override
        protected String doInBackground(Void... params)
        {
            // do your background task here ...
    
            return "Done!";
        }
    
        @Override
        protected void onPostExecute(String result)
        {
            super.onPostExecute(result);
            if(this._task_finished_event != null)
            {
                this._task_finished_event.OnTaskFihishedEvent(result);
            }
            else
            {
                Log.d("SomeClass", "task_finished even is null");
            }
        }
    }
    
  2. 주요 활동에 추가

    // MAIN ACTIVITY
    public class MyActivity extends ListActivity
    {
       ...
        SomeClass _some_class = new SomeClass();
        _someclass.setOnTaskFinishedEvent(new _some_class.OnTaskExecutionFinished()
        {
        @Override
        public void OnTaskFihishedEvent(String result)
        {
            Toast.makeText(getApplicationContext(),
                    "Phony thread finished: " + result,
                    Toast.LENGTH_SHORT).show();
        }
    
       });
       _some_class.execute();
       ...
     }
    

자신의 청취자를 작성할 수 있습니다. HelmiB 의 답변 과 동일 하지만 더 자연스럽게 보입니다.

리스너 인터페이스를 만듭니다.

public interface myAsyncTaskCompletedListener {
    void onMyAsynTaskCompleted(int responseCode, String result);
}

그런 다음 비동기 작업을 작성하십시오.

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

    private myAsyncTaskCompletedListener listener;
    private int responseCode = 0;

    public myAsyncTask() {
    }

    public myAsyncTask(myAsyncTaskCompletedListener listener, int responseCode) {
        this.listener = listener;
        this.responseCode = responseCode;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }


    @Override
    protected String doInBackground(String... params) {
        String result;
        String param = (params.length == 0) ? null : params[0];
        if (param != null) {
            // Do some background jobs, like httprequest...
            return result;
        }
        return null;
    }

    @Override
    protected void onPostExecute(String finalResult) {
        super.onPostExecute(finalResult);
        if (!isCancelled()) {
            if (listener != null) {
                listener.onMyAsynTaskCompleted(responseCode, finalResult);
            }
        }
    }
}

마지막으로 활동에 리스너를 구현하십시오.

public class MainActivity extends AppCompatActivity implements myAsyncTaskCompletedListener {

    @Override
    public void onMyAsynTaskCompleted(int responseCode, String result) {

        switch (responseCode) {
            case TASK_CODE_ONE: 
                // Do something for CODE_ONE
                break;
            case TASK_CODE_TWO:
                // Do something for CODE_TWO
                break;
            default: 
                // Show some error code
        }        
    }

그리고 이것은 asyncTask를 호출하는 방법입니다.

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Some other codes...
        new myAsyncTask(this,TASK_CODE_ONE).execute("Data for background job");
        // And some another codes...
}

Activity 클래스에서 정적 멤버를 작성하십시오. 그런 다음onPostExecute

예를 들어, AsyncTask의 결과가 문자열 인 경우 활동에서 공개 정적 문자열을 작성하십시오.

public static String dataFromAsyncTask;

그런 다음 onPostExecuteAsyncTask에서 기본 클래스를 정적 ​​호출하고 값을 설정하십시오.

MainActivity.dataFromAsyncTask = "result blah";


스레딩 및 핸들러 / 메시지를 사용하여 작동시킵니다. 다음과 같은 단계 : 진행률 선언 대화 상자

ProgressDialog loadingdialog;

작업이 끝나면 대화 상자를 닫는 기능을 만듭니다.

   private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        loadingdialog.dismiss();

    }
    };

실행 세부 사항을 코딩하십시오.

 public void startUpload(String filepath) {
    loadingdialog = ProgressDialog.show(MainActivity.this, "Uploading", "Uploading Please Wait", true);
    final String _path = filepath;
    new Thread() {
        public void run() {
            try {
                UploadFile(_path, getHostName(), getPortNo());
                handler.sendEmptyMessage(0);

            } catch (Exception e) {
                Log.e("threadmessage", e.getMessage());
            }
        }
    }.start();
}

데이터를 위임하거나 제공 하려면 "프로토콜" 을 사용해야 합니다 AsynTask.

대리인 및 데이터 소스

델리게이트는 프로그램에서 이벤트가 발생했을 때 다른 오브젝트를 대신하거나 그와 함께 동작하는 오브젝트입니다. ( 애플 정의 )

프로토콜은 일부 동작을 위임하는 몇 가지 방법을 정의하는 인터페이스입니다.

여기 완전한 예가 있습니다 !!!


이 시도:

public class SomAsyncTask extends AsyncTask<String, Integer, JSONObject> {

    private CallBack callBack;

    public interface CallBack {
        void async( JSONObject jsonResult );
        void sync( JSONObject jsonResult );
        void progress( Integer... status );
        void cancel();
    }

    public SomAsyncTask(CallBack callBack) {
        this.callBack = callBack;
    }

    @Override
    protected JSONObject doInBackground(String... strings) {

        JSONObject dataJson = null;

        //TODO query, get some dataJson

        if(this.callBack != null)
            this.callBack.async( dataJson );// asynchronize with MAIN LOOP THREAD

        return dataJson;

    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);

        if(this.callBack != null)
            this.callBack.progress(values);// synchronize with MAIN LOOP THREAD

    }

    @Override
    protected void onPostExecute(JSONObject jsonObject) {
        super.onPostExecute(jsonObject);

        if(this.callBack != null)
            this.callBack.sync(jsonObject);// synchronize with MAIN LOOP THREAD
    }

    @Override
    protected void onCancelled() {
        super.onCancelled();

        if(this.callBack != null)
            this.callBack.cancel();

    }
}

그리고 사용 예 :

public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);

         final Context _localContext = getContext();
         SomeAsyncTask.CallBack someCallBack = new SomeAsyncTask.CallBack() {

                @Override
                public void async(JSONObject jsonResult) {//async thread
                    //some async process, e.g. send data to server...
                }

                @Override
                public void sync(JSONObject jsonResult) {//sync thread
                    //get result...

                    //get some resource of Activity variable...
                    Resources resources = _localContext.getResources();
                }

                @Override
                public void progress(Integer... status) {//sync thread
                    //e.g. change status progress bar...
                }

                @Override
                public void cancel() {

                }

            };

            new SomeAsyncTask( someCallBack )
                                .execute("someParams0", "someParams1", "someParams2");

    }

아마도 약간 오버 보드가되지만 실행 코드와 결과 모두에 대한 콜백을 제공했습니다. 분명히 스레드 안전을 위해 실행 콜백에서 액세스하는 내용에주의를 기울이고 싶습니다.

AsyncTask 구현 :

public class AsyncDbCall<ExecuteType,ResultType> extends AsyncTask<ExecuteType, Void,  
ResultType>
{
    public interface ExecuteCallback<E, R>
    {
        public R execute(E executeInput);
    }
    public interface PostExecuteCallback<R>
    {
        public void finish(R result);
    }

    private PostExecuteCallback<ResultType> _resultCallback = null;
    private ExecuteCallback<ExecuteType,ResultType> _executeCallback = null;


    AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback, PostExecuteCallback<ResultType> postExecuteCallback)
    {
        _resultCallback = postExecuteCallback;
        _executeCallback = executeCallback;
    }

    AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback)
    {
        _executeCallback = executeCallback;
    }

    @Override
    protected ResultType doInBackground(final ExecuteType... params)
    {
        return  _executeCallback.execute(params[0]);
    }

    @Override
    protected void onPostExecute(ResultType result)
    {
        if(_resultCallback != null)
            _resultCallback.finish(result);
    }
}

콜백 :

 AsyncDbCall.ExecuteCallback<Device, Device> updateDeviceCallback = new 
 AsyncDbCall.ExecuteCallback<Device, Device>()
    {
        @Override
        public Device execute(Device device)
        {
            deviceDao.updateDevice(device);
            return device;
        }
    };

그리고 마지막으로 비동기 작업을 실행합니다.

 new AsyncDbCall<>(addDeviceCallback, resultCallback).execute(device);

참고 : https://stackoverflow.com/questions/12575068/how-to-get-the-result-of-onpostexecute-to-main-activity-because-asynctask-is-a



반응형