안드로이드 AsyncTask 에 관한 질문입니다.
조회수 2528회
AsyncTask 에 대한 문서를 읽은적이 있어서 아래와 같이 간단하게 프로그램을 짜봤습니다. 그런데 제대로 작동이 안되네요... 어떻게 수정하면 될까요?
package com.test;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings.System;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.view.View.OnClickListener;
public class AsyncTaskActivity extends Activity {
Button btn;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn = (Button) findViewById(R.id.button1);
btn.setOnClickListener((OnClickListener) this);
}
public void onClick(View view){
new LongOperation().execute("");
}
private class LongOperation extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
for(int i=0;i<5;i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");
return null;
}
@Override
protected void onPostExecute(String result) {
}
@Override
protected void onPreExecute() {
}
@Override
protected void onProgressUpdate(Void... values) {
}
}
}
백그라운드 프로세스에서 5초후에 라벨의 내용을 변경하고 싶어요.
아래 제가 작성한 main.xml파일입니다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="false"
android:max="10"
android:padding="10dip">
</ProgressBar>
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Progress" >
</Button>
<TextView android:id="@+id/output"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Replace"/>
</LinearLayout>
1 답변
-
지금 별도의 스레드를 통해서 GUI에 접근하고 싶은 것 같은데요. 메인 메소드에서의 그러한 접근 시도는 좋지 않아요.
AsyncTask는 GUI에 대한 접근 권한이 없는 다른 스레드내에서 작동하며 모든 작업을 doInBackground()메소드에서 처리합니다.
preExecute(), postExecute()메소드는 새로운 스레드에서의 큰 작업 전후에 GUI에 접근할 수 있도록 권한을 부여합니다. 또한 긴 시간을 필요로하는 작업을 끝낸 후에는 postExecute() 메소드로 작업의 결과를 보내 작업의 결과를 확인할 수 있습니다.
아래 코드가 TextView를 최신화하는 부분일 것으로 예상됩니다.
TextView txt = (TextView) findViewById(R.id.output); txt.setText("Executed");
이 코드를 postExecute()메소드에 삽입하세요. 그러면 doInBackground 메소드가 실행된 후에 TextView가 정상적으로 최신화되는 것을 확인할 수 있을겁니다.
수정: 작성하신 코드에는 onClick listener에서 어떤 View가 선택됐는지 확인하는 과정이 없습니다. 이런 문제를 해결하기위해 switch문을 활용하는 간단한 방법을 알려드리겠습니다. 혼란을 주고 있는 부분을 해결해 줄 수정된 class를 아래와 같이 만들어봤습니다. 확인해보세요.
import android.app.Activity; import android.os.AsyncTask; import android.os.Bundle; import android.provider.Settings.System; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.view.View.OnClickListener; public class AsyncTaskActivity extends Activity implements OnClickListener { Button btn; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); btn = (Button) findViewById(R.id.button1); // because we implement OnClickListener we only have to pass "this" // (much easier) btn.setOnClickListener(this); } public void onClick(View view) { // detect the view that was "clicked" switch (view.getId()) { case R.id.button1: new LongOperation().execute(""); break; } } private class LongOperation extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... params) { for (int i = 0; i < 5; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.interrupted(); } } return "Executed"; } @Override protected void onPostExecute(String result) { TextView txt = (TextView) findViewById(R.id.output); txt.setText("Executed"); // txt.setText(result); // might want to change "executed" for the returned string passed // into onPostExecute() but that is upto you } @Override protected void onPreExecute() {} @Override protected void onProgressUpdate(Void... values) {} } }
댓글 입력