본문 바로가기
App/Android Studio

Android Studio - 어싱크 태스크와 타이머

by 코젼 2022. 8. 11.
728x90
반응형

2022-08-11(39일차)



💡비동기(Asynchronous) 실행"의 정형화된 패턴

  • 실행(execute) : 비동기(Asynchronous) 작업 준비 및 시작.
  • 백그라운드 작업(doInBackground) : 백그라운드 스레드에서 비동기(Asynchronous) 작업 실행.
  • 진행 상황 업데이트(onProgressUpdate) : 백그라운드 스레드 진행 상황을 메인스레드로 전달.
  • 비동기 실행 완료 후 처리(onPostExecute) : 백그라운드 스레드 완료 후 메인스레드에 완료 상태 전달.
    execute -> doInBackground -> onProgressUpdate -> onPostExecute

📃어싱크태스크 예제


📝activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical"
    android:gravity="center">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/text"
        android:text="0"
        android:gravity="center"
        android:textSize="40sp"/>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/update"
        android:layout_gravity="center"
        android:onClick="mOnClick"
        android:text="Updata"/>


</LinearLayout>

📝MainActivity.java

◾ AccumulateTask 클래스 생성
◾ AccumulateTask 객체 생성
execute로 실행한다.

onPreExecute에서 value 값 지정
doInBackground에서 value가 50보다 작을 때까지 publishProgress메소드를 통해 onProgressUpdate 호출
onProgressUpdate에서 텍스트뷰에 값 세팅
◾ 작업을 모두 마치면 onPostExecute가 실행되고, 해당 텍스트가 세팅된다.
package com.project.test02;
import androidx.appcompat.app.AppCompatActivity;

import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    long value;
    TextView mText;

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

        mText = (TextView)findViewById(R.id.text);
    }

    public void mOnClick(View v) {
        AccumulateTask myTask = new AccumulateTask();
        myTask.execute(50);
//        new AccumulateTask().execute(100);
    }

    class AccumulateTask extends AsyncTask<Integer, String, Long> {
        protected void onPreExecute() {
            value = 0;
        }
        protected Long doInBackground(Integer... params) {
            while (isCancelled() == false) {
                value++;
                if (value < params[0]) {   // execute의 인자값이 params[0] 로 전달
                    publishProgress(value + ""); // onProgressUpdate가 호출됨
                } else {
                    break;
                }
                try { Thread.sleep(50); } catch (InterruptedException e) {;}
            }
            return value;
        }
        protected void onProgressUpdate(String... progress) {

            mText.setText(progress[0]);
        }

        @Override
        protected void onPostExecute(Long result) {
            super.onPostExecute(result);
            mText.setText("success!!! " + result);
            Log.i("jenn", "작업을 마친 후 반환 값은 " + result + "입니다");
        }
    }

}

 


📃어싱크태스크를 이용한 프로그레스바 진행 표시


📝activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">


    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="100dp"
        android:layout_centerInParent="true"
        android:max="100"
        android:progress="0" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="start"
        android:layout_below="@id/progressBar"
        android:onClick="mOnClick"
        android:layout_centerHorizontal="true"/>
</RelativeLayout>

📝MainActivity.java

package com.project.test03;

import androidx.appcompat.app.AppCompatActivity;

import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    ProgressBar pb;

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

        pb = findViewById(R.id.progressBar);
    }

    public void mOnClick(View v) {
        int max = pb.getMax();
        new AccumulateTask().execute(max);
    }

    class AccumulateTask  extends AsyncTask<Integer, Integer, String> {
        static final String RESULT_SUCCESS = "SUCCESS";
        int progress = 0;

        @Override
        protected void onPreExecute() {
            progress = 0;
        }

        @Override
        protected String doInBackground(Integer... params) {
            while(progress < params[0]) {
                progress++;
                publishProgress(progress);
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            return RESULT_SUCCESS;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            pb.setProgress(values[0]);
        }

        @Override
        protected void onPostExecute(String result) {
            Toast.makeText(MainActivity.this, result, Toast.LENGTH_SHORT).show();
        }
    }
}

📃초 단위 타이머 만들기


📝activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="3"
            android:id="@+id/et_time"
            android:hint="초 단위로 입력하세요"
            android:inputType="time"/>

        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:id="@+id/btn_start"
            android:onClick="onClickStart"
            android:layout_weight="1"
            android:text="시작"/>

        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:id="@+id/btn_stop"
            android:onClick="onClickStop"
            android:layout_weight="1"
            android:text="중지"/>

    </LinearLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:id="@+id/tv_count"
        android:text="0"
        android:layout_centerInParent="true" />

</RelativeLayout>

📝MainActivity.java

package com.project.test04;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {
    TimerTask tickTask; // 1초마다 카운트
    TimerTask finishTask; // 에디트에 입력한 시간이 되면 실행

    Timer timer = new Timer();

    TextView tv_count; // 카운트 초를 출력하는 텍스트뷰


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        tv_count = findViewById(R.id.tv_count);
    }
    
    // 시작 버튼을 클릭했을 때 호출되는 onClickStart()에서 타이머태스크 두 개를 생성한다.
    // 하나는 1초마다 증가되는 시간을 카운트 할 tickTask
    // 다른 하나는 에티드에 입력한 시간이 되면 tickTask를 중지한다.
    public void onClickStart(View v) {
        tickTask = new TimerTask() {
            int count = 0;
            
            @Override
            public void run() {
                count++;
                tv_count.post(new Runnable() {
                    @Override
                    public void run() {
                        tv_count.setText(count + "초");
                    }
                });
            }
        };
        
        finishTask = new TimerTask() {
            @Override
            public void run() {
                tickTask.cancel();
                tickTask = null;
            }
        };

        EditText et = findViewById(R.id.et_time);
        int sec = Integer.valueOf(et.getText().toString());
        int delay = sec * 1000; // 에디트에 입력된 값을 밀리세컨드로 변환
        timer.schedule(finishTask, delay); // 입력된 시간에 finishTask 실행
        timer.schedule(tickTask, 0, 1000); // 1초마다 tickTask가 실행
    }
    
    // 정지 버튼이 눌리면 모든 타이머태스크를 중지한다.
    public void onClickStop(View v) {
        if(tickTask != null) {
            tickTask.cancel();
            tickTask = null;
        }
        
        if(finishTask != null) {
            finishTask.cancel();
            finishTask = null;
        }
    }
}

 

728x90
반응형

댓글