안드로이드 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 답변

  • 좋아요

    0

    싫어요
    채택 취소하기

    지금 별도의 스레드를 통해서 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) {}
        }
    }
    

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)