국비교육(22-23)

76일차(4)/Android App(36) : AsyncTask(1)

서리/Seori 2023. 1. 27. 00:26

76일차(4)/Android App(36) : AsyncTask

 

- 새 모듈 생성- step16asynctask 

 

- AsyncTask : 비동기작업

 

activity_main.xml

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

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="무언가 입력해 보세요..."/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/sendBtn"
        android:text="전송"/>

</LinearLayout>

 

Messenger 클래스생성

package com.example.step16asynctask;

import android.util.Log;

public class Messenger {

    //가상으로 메세지를 보내는 static 메소드
    public static void sendMessage(String msg){
        Log.e("Messenger sendMessage()", "메세지 전송중...");
        //메세지를 전송하는 데 20초가 걸린다고 가정
        try{
            Thread.sleep(20000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }Log.e("Messenger sendMessage()", "메세지 전송 완료");

    }
}

 

- 메신저의 static 메소드를 수행하면서 어떤 작업을 하려고 한다.

- 어떤 메시지를 전송하는 데 20초가 걸린다고 가정하기!

 

- 여기에 실행순서가 들어올 때,  20초 동안 메인스레드에 실행 순서가 잡혀 있는 것이 문제이다.

 


 

MainActivity

package com.example.step16asynctask;

import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.Button;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

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

        //전송버튼
        Button sendBtn=findViewById(R.id.sendBtn);
        sendBtn.setOnClickListener(v -> {
            /*
                시간이 오래 걸리거나 혹은 실행 시간이 불확실한 작업은
                Main thread(UI thread) 에서 하면 안 된다.
             */
            //비동기 task 객체를 생성해서
            SendTask task=new SendTask();
            //execute() 메소드를 호출해서 작업을 시작한다.
            task.execute("hello", "...", "bye!");
        });
    }
    /*
        비동기 작업을 도와줄 클래스 설계하기
        1. AsyncTask 추상 클래스를 상속받는다.
        2. AsyncTask<파라미터 type, 진행중 type, 결과 type> 에 맞게끔
           Generic 클래스를 잘 정의한다.
        3. doInBackground() 메소드를 오버라이드한다.
        4. 추가로 필요한 메소드가 있으면 추가로 오버라이드한다.
     */
    public class SendTask extends AsyncTask<String, Void, Void>{

        //백그라운드에서 작업할 내용을 여기서 해준다(새로운 스레드에서 할 작업)
        @Override
        protected Void doInBackground(String... strings) {
            //여기는 UI 스레드가 아니다!! 즉 UI를 업데이트할 수 없다.

            //String... 은 String[] 로 간주해서 사용하면 된다.
            Messenger.sendMessage(strings[0]);
            //작업에 결과가 있다면 return 해주면 되고
            return null;
        }
        // doInBackground() 메소드가 리턴하면 자동으로 호출되는 메소드
        @Override
        protected void onPostExecute(Void unused) {
            super.onPostExecute(unused);
            //여기는 UI 스레드이기 때문에 UI에 관련된 작업을 마음대로 할 수 있다.
            new AlertDialog.Builder(MainActivity.this)
                    .setMessage("작업성공")
                    .create()
                    .show();
        }
    }
}

 

- 전송 버튼을 누르면 20초간 앱이 멈춘다. 더이상 입력도 할 수 없다. 응답하지 않는다.

- 사용자의 요청에 응답하지 않으면 운영체제가 알아차리고 강제종료시킬 수가 있다.

 

- 이렇게 시간이 오래 걸리거나 혹은 실행 시간이 불확실한 작업은
  Main thread(UI thread) 에서 하면 안 된다.

 

- 아래에 새 클래스 생성. AsyncTask 상속

- 3개의 제너릭 타입을 지정

 

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

}

- 이렇게 작성해준 후 메소드 오버라이드

 

- 3개의 제너릭<> 은 각각 파라미터 타입, 진행중 타입, 결과 타입인데

 따로 작업의 결과가 없으면 그냥 Void 라고 한다.

 

Messenger.sendMessage("")

- 위쪽 스레드가 아니라 백그라운드 메소드에서 이 작업을 한다.

 

- 이 SendTask 클래스를 사용하는 방법은? onCreate() 메소드 안에서 객체를 생성해서 execute() 에 넣어준다

- 받는 파라미터가 동적이다.(여러개의 인자가 들어갈 수 있다)

 

- execute() 에 들어간 인자가 여기에 담긴다.

- String... String[ ] 배열이라고 생각하고 사용하면 된다!

 

- 받아서 인덱스의 방 번호로 호출한다.

 

- run 해보면 이제 메시지가 전송되고 있어도 정지되지 않는다.

- 전송을 보내고 20초 기다리면 작업 성공이라는 알림이 뜬다!

 


 

- AsyncTask는 현재 deprecated 되어있다.

- 즉 장기적으로 사용을 하지 않을 예정이다. 하지만 아직 동작은 한다.

 

- 비동기작업. 백그라운드에서 사용되는 doInBackground 메소드는 기존과는 다른 별개의, 새로운 스레드이다.

 

- 작업에 필요한 파라미터들은 여기에 담긴다.

- 파라미터 타입이 String인 이유, 진행,결과 타입이 void인 이유는 인자를 그 타입으로 받기 때문이다.

 

- 여기는 UI 스레드가 아니다!! 즉 UI를 업데이트할 수 없다.

- list에 결과를 출력하는 등의 동작은 이 스레드에서는 할 수 없다.

 

- onPostExecute() 메소드에서 따로 UI 업데이트를 할 수 있다.

 

- 시간이 많이걸리는 동작은 별도의 스레드에서!

 

- 작업이 끝나면 자동으로 onPostExecute 로 리턴된 것이 전달된다.(여기서는 void)

- 작업의 결과물을 가지고 UI를 업데이트할 수 있다.

 

- 파라미터, 과정, 결과 타입 알아두기!

- 작업이 끝났을때 알림을 띄우도록 onPostExecute에 이어질 작업 코딩