티스토리 뷰
Stack Overflow에 자주 검색, 등록되는 문제들과 제가 개발 중 찾아 본 문제들 중에서 나중에도 찾아 볼 것 같은 문제들을 정리하고 있습니다.
Stack Overflow에서 가장 먼저 확인하게 되는 가장 높은 점수를 받은 Solution과 현 시점에 도움이 될 수 있는 가장 최근에 업데이트(최소 점수 확보)된 Solution을 각각 정리하였습니다.
아래 word cloud를 통해 이번 포스팅의 주요 키워드를 미리 확인하세요.
How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?
AsyncTask는 별도의 클래스인데, OnPostExecute()의 결과를 어떻게 메인 액티비티로 가져오나요?
문제 내용
I have this two classes. My main Activity and the one that extends the AsyncTask
, Now in my main Activity I need to get the result from the OnPostExecute()
in the AsyncTask
. How can I pass or get the result to my main Activity?
제가 가지고 있는 두 개의 클래스는 메인 액티비티와 AsyncTask를 확장한 클래스입니다. 이제 메인 액티비티에서 AsyncTask의 OnPostExecute() 결과를 가져와야 합니다. 어떻게 하면 메인 액티비티에서 결과를 전달하거나 가져올 수 있을까요?
Here is the sample codes.
다음은 샘플 코드입니다.
My main Activity.
제 메인 액티비티 코드입니다.
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);
}
}
This is the AsyncTask class
이것은 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);
}
}
높은 점수를 받은 Solution
Easy:
이건 쉬워요.
- Create
interface
class, whereString output
is optional, or can be whatever variables you want to return. public interface AsyncResponse { void processFinish(String output); }
- Go to your
AsyncTask
class, and declare interfaceAsyncResponse
as a field : public class MyAsyncTask extends AsyncTask<Void, Void, String> { public AsyncResponse delegate = null; @Override protected void onPostExecute(String result) { delegate.processFinish(result); } }
- In your main Activity you need to
implements
interfaceAsyncResponse
. 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. } }
1. 인터페이스 클래스를 만들어, 반환할 변수를 String으로 지정하거나, 원하는 변수로 지정합니다.
2. public interface AsyncResponse { void processFinish(String output); }
3. AsyncTask 클래스에서 인터페이스 AsyncResponse를 필드로 선언합니다.
4. public class MyAsyncTask extends AsyncTask<void, string="" void,=""> { public AsyncResponse delegate = null; ``` typescriptCopy code `@Override protected void onPostExecute(String result) { delegate.processFinish(result); }` ``` }
5. 메인 액티비티에서 AsyncResponse 인터페이스를 구현해야 합니다.
6. public class MainActivity implements AsyncResponse{ MyAsyncTask asyncTask =new MyAsyncTask(); @Override public void onCreate(Bundle savedInstanceState) { ``` vbnetCopy code `//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. } } </void,>
UPDATE
업데이트
I didn't know this is such a favourite to many of you. So here's the simple and convenience way to use interface
.
이게 많은 분들에게 즐겨찾기에 해당되는 줄 몰랐네요. 그래서 인터페이스를 사용하는 간단하고 편리한 방법을 소개합니다.
still using same interface
. FYI, you may combine this into AsyncTask
class.
여전히 같은 인터페이스를 사용합니다. 참고로 이를 AsyncTask 클래스로 결합할 수 있습니다.
in AsyncTask
class :
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);
}
}
do this in your Activity
class
다음과 같이 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();
}
Or, implementing the interface on the Activity again
또는, 인터페이스를 다시 액티비티에 구현하는 방법도 있습니다.
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.
}
}
As you can see 2 solutions above, the first and third one, it needs to create method processFinish
, the other one, the method is inside the caller parameter. The third is more neat because there is no nested anonymous class.
위에서 볼 수 있는 두 가지 해결책 중, 첫 번째와 세 번째 방법은 processFinish 메소드를 생성해야 합니다. 그리고 두 번째 방법은 caller 매개변수 안에 메소드가 있습니다. 세 번째 방법이 좀 더 깔끔합니다. 왜냐하면 중첩된 익명 클래스가 없기 때문입니다.
Tip: Change String output
, String response
, and String result
to different matching types in order to get different objects.
팁: "String output", "String response", "String result"를 서로 다른 맞춤형 유형으로 변경하여 다른 객체를 가져올 수 있습니다.
가장 최근 달린 Solution
This answer might be late but I would like to mention few things when your Activity
dependent on AsyncTask
. That would help you in prevent crashes and memory management. As already mentioned in above answers go with interface
, we also say them callbacks. They will work as an informer, but never ever send strong reference of Activity
or interface
always use weak reference in those cases.
이 답변은 늦을 수 있지만, AsyncTask에 종속된 Activity에서 몇 가지 사항을 언급하고 싶습니다. 이는 충돌과 메모리 관리를 방지하는 데 도움이 됩니다. 이미 위의 답변에서 언급한 대로 인터페이스, 콜백으로 진행하면 되고, 이들은 알리미 역할을 하지만, 절대로 Activity나 인터페이스의 강력한 참조를 보내지 마시고, 이러한 경우에는 언제나 약한 참조를 사용하십시오.
Please refer to below screenshot to findout how that can cause issues.
아래 스크린샷을 참조하여 어떻게 문제를 일으킬 수 있는지 확인해주세요.
As you can see if we started AsyncTask
with a strong reference then there is no guarantee that our Activity
/Fragment
will be alive till we get data, so it would be better to use WeakReference
in those cases and that will also help in memory management as we will never hold the strong reference of our Activity
then it will be eligible for garbage collection after its distortion.
보시다시피, 우리가 강한 참조로 AsyncTask를 시작하면, 데이터를 받을 때까지 Activity/Fragment가 살아있을 것이 보장되지 않으므로, 그 경우에는 WeakReference를 사용하는 것이 좋습니다. 이렇게 하면 우리는 Activity의 강한 참조를 유지하지 않으므로, 파괴 후 가비지 수집 가능성이 있습니다. 이는 메모리 관리에도 도움이 됩니다.
Check below code snippet to find out how to use awesome WeakReference -
아래 코드 스니펫을 살펴보세요. 어떻게 멋진 WeakReference를 사용하는지 알 수 있습니다.
MyTaskInformer.java
Interface which will work as an informer.
MyTaskInformer.java는 인포머 역할을 하는 인터페이스입니다.
public interface MyTaskInformer {
void onTaskDone(String output);
}
MySmallAsyncTask.java
AsyncTask to do long running task, which will use WeakReference
.
MySmallAsyncTask.java: Activity에 종속된 장기 실행 작업을 수행하는 AsyncTask로, 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
This class is used to start my AsyncTask
implement interface
on this class and override
this mandatory method.
MainActivity.java는 AsyncTask를 시작하기 위해 사용되며, 이 클래스에서 인터페이스를 구현하고 이 필수 메서드를 재정의합니다.
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);
}
}
출처 : https://stackoverflow.com/questions/12575068/how-to-get-the-result-of-onpostexecute-to-main-activity-because-asynctask-is-a
'개발 > 안드로이드' 카테고리의 다른 글
지원 중단된 Html.fromHtml 구현하기 (0) | 2023.01.07 |
---|---|
액티비티 재시작하기 (0) | 2023.01.06 |
뒤로 가기 두번 클릭으로 액티비티 종료하기 (0) | 2023.01.05 |
액티비티 스택에서 액티비티 제거하기 (0) | 2023.01.05 |
안드로이드 모바일 웹사이트(어플리케이션이 아닌)에서 WhatsApp으로 링크 공유하기 (0) | 2023.01.05 |