【Android】遅延処理・非同期処理を使って時間差でViewに反映させる

#Handler（遅延処理）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/566570/ff283bfb-45cf-0193-fdab-ec4ba4525490.png)


3つのTextViewに1秒ずつテキストをセットしてみます。

```java:MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private Handler handler = new Handler();

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

    public void btnOnClick(View view) {
        
        final TextView txt1 = findViewById(R.id.txt1);
        final TextView txt2 = findViewById(R.id.txt2);
        final TextView txt3 = findViewById(R.id.txt3);

        txt1.setText("開始");

        //Runnableインターフェースのrunメソッドをオーバーライドしている。
        //そしてpostDelayedメソッドの引数としてrunメソッドを利用している。
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                txt2.setText("1秒後");
            }
        }, 1000);

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                txt3.setText("2秒後");
            }
        }, 2000);
    }


```

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

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="開始"
        android:onClick="btnOnClick"/>

    <TextView
        android:id="@+id/txt1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/txt2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/txt3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>
```

#AsyncTask（非同期処理）
**※AsyncTaskはAndroid11から非推奨になるようです。**

こちらも3つのTextViewに時間差で文字セット。
activity_main.xmlは遅延処理のソースと同じ。

```java:AsyncText.java
import android.content.Context;
import android.os.AsyncTask;
import android.widget.TextView;
import java.lang.ref.WeakReference;

public class AsyncText extends AsyncTask<String,String,String> {
    //WeakReferenceにするとリークを防げる
    private WeakReference<TextView> txt1;
    private WeakReference<TextView> txt2;
    private WeakReference<TextView> txt3;

    AsyncText(Context context) {
        //Viewの取得
        super();
        MainActivity activity = (MainActivity)context;
        txt1 = new WeakReference<>((TextView)activity.findViewById(R.id.txt1));
        txt2 = new WeakReference<>((TextView)activity.findViewById(R.id.txt2));
        txt3 = new WeakReference<>((TextView)activity.findViewById(R.id.txt3));
    }

    // 非同期処理を開始する前
    @Override
    protected void onPreExecute() {
        txt1.get().setText("開始前");
    }

    // 非同期処理の途中経過
    @Override
    protected void onProgressUpdate(String... values) {
        txt2.get().setText(values[0]);
    }

    // 非同期処理を終了した後
    @Override
    protected void onPostExecute(String result) {
        txt3.get().setText(result);

    }

    // 非同期処理をキャンセル
    @Override
    protected void onCancelled() {
    }


    //メインスレッドとは別のスレッドで実行される
    //ここに非同期で行いたい処理を書く
    @Override
    protected String doInBackground(String... strings) {
        publishProgress("途中");// onProgressUpdateを呼び出す

        //1秒待つ
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //戻り値はonPostExecuteに引数として渡される
        return strings[0];
    }
}
```

```java:MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;

public class MainActivity extends AppCompatActivity {
    private Handler handler = new Handler();

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

    public void btnOnClick(View view) {
        AsyncText asyncText = new AsyncText(this);
        asyncText.execute("非同期処理完了");//doInBackgroundメソッドが呼び出される
    }
}
```

#Thread.sleep(失敗例）
これだと2秒後に全TextViewが一気に表示されてしまう。

```java:MainActivity.java
package to.msn.wings.copy;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    private Handler handler = new Handler();

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

    public void btnOnClick(View view) throws InterruptedException {
        
        final TextView txt1 = findViewById(R.id.txt1);
        final TextView txt2 = findViewById(R.id.txt2);
        final TextView txt3 = findViewById(R.id.txt3);

        txt1.setText("開始");
        Thread.sleep(1000);
        txt2.setText("1秒後");
        Thread.sleep(1000);
        txt3.setText("2秒後");
    }
}
```