runOnUiThread
UI쓰레드 = 메인 쓰레드 (onCreate를 실행하는 쓰레드)
다운로드 받을 때에는 무조건 새로운 쓰레드(I/O)
새로운쓰레드로 다운로드 -> 쓰레드 마지막에 콜백
다운로드 다받은 데이터를 메인쓰레드의 변수에서 쓰기 어렵다(다운로드 받는 걸 메인에서 기다리지 않기 때문)
그래서 runOnUiThread 나 핸들러를 사용해야한다.
사용하지 않을려면
메인쓰레드에 함수에 넘겨야하는데 자바는 함수를 넘길 수 없으므로 클래스(인터페이스)를 넘겨야한다
asyncTask를 이용하여 메인에서 다운로드 데이터를 받는 타이밍을 잡아야한다
원리를 이해하고 나서 라이브러리를 사용하자
--------------
asyncTask
두잇 안드 490페이지 메서드(doInBackground)
-----------------------
메인쓰레드
이벤트핸들러 쓰레드
-----------------------
다른 쓰레드에서 이벤트핸들러쓰레드를 통해서 메인쓰레드의 이미지를 변경한다
어떻게 하면 다른 쓰레드가 이벤트핸들러에 접근할 수 있을까
1. 쓰레드 안에 runOnUiThread()를 하나더 만들어서 이용 - 핸들러에게 던짐
2. 핸들러를 이용하는 방법 handler.post() (Do it 안드 478페이지)
3.
-----------------------
프로그레스 진행 만들기
-----------------------
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"
android:orientation="vertical"
tools:context=".MainActivity">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button
android:id="@+id/btn_execute"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="실행" />
<Button
android:id="@+id/btn_stop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="중지" />
</LinearLayout>
MainActivity
package com.jaybon.asynctask;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
public class MainActivity extends AppCompatActivity {
private Button btnExecute, btnStop; //실행 중지버튼
private ProgressBar progressBar; // 진행바
private int value = 0; // 진행바의 퍼센테이지
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mInit(); // 함수 사용할 때 내가 만든 것은 m을 붙이고 오버라이딩은 그대로
progressBar.setProgress(value);
mListenser();
}
private void mListenser() {
btnExecute.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() { // 여기다가 데이터변환을 쓰면 안된다(runOnUiThread나 핸들러)
@Override
public void run() {
// runOnUiThread는 잘 안쓰니까 핸들러를 사용하자
handler.post(new Runnable() { // 핸들러한테 던지는 타겟을 넣기
@Override
public void run() {
while (true) {
value = value + 5;
progressBar.setProgress(value);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.getStackTrace();
}
if(value >= 100){
break;
}
}
}
});
}
}).start();
}
});
}
private void mInit() {
btnExecute = findViewById(R.id.btn_execute);
btnStop = findViewById(R.id.btn_stop);
progressBar = findViewById(R.id.progressBar);
}
}
결과
진행이 안되고 한번에 쫙 100퍼가 채워진다
쓰레드가 종료되야 핸들러가 실행되기 때문
데이터는 변경된다! 다만 UI에 그리는건 핸들러 쓰레드가 끝나야 되는 것!
------------------------
asyncTask로 변경하여 만들기
블록지정 부분 삭제
제네릭 값이 전달된다
package com.jaybon.asynctask;
import androidx.appcompat.app.AppCompatActivity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "Main_Activity";
private Button btnExecute, btnStop; //실행 중지버튼
private ProgressBar progressBar; // 진행바
private int value = 0; // 진행바의 퍼센테이지
private Handler handler = new Handler();
class BackgroundTask extends AsyncTask<Integer, Integer, Integer> { // 이것이 쓰레드가 됨
@Override // 타겟 호출 직전
protected void onPreExecute() {
super.onPreExecute();
progressBar.setProgress(value);
Log.d(TAG, "onPreExecute: ");
}
@Override // 타겟 (run()과 같음)
protected Integer doInBackground(Integer... integers) { // 스레드 실행시 인수 받기
Log.d(TAG, "doInBackground: ");
while (value < 100){
value = value + 5;
// 이 값은 onProgressUpdate로 넘어간다
// 넘어가서 바로 그려짐
publishProgress(value);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 이 값이 onPostExecute의 매개변수로 넘어간다
return 1; // 정상적으로 수행됐으면 1, 안됐으면 -1
}
@Override // UI쓰레드에 그림을 그려주는 메서드
protected void onProgressUpdate(Integer... values) { // publishProgress 리턴 값 받기
super.onProgressUpdate(values);
Log.d(TAG, "onProgressUpdate: ");
progressBar.setProgress(values[0]); // Integer...는 배열이라서 0번 주소 = Integer[]
}
@Override // 타겟 호출 이후
protected void onPostExecute(Integer integer) { // doInBackground 리턴 값 받기
// 리턴값 받아서 값에 따라 분기
super.onPostExecute(integer);
Log.d(TAG, "onPostExecute: ");
Toast.makeText(MainActivity.this, "다운로드 완료", Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mInit(); // 함수 사용할 때 내가 만든 것은 m을 붙이고 오버라이딩은 그대로
mListenser();
}
private void mListenser() {
btnExecute.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new BackgroundTask().execute(); // execute(여기의 값이 doInBackground 의 매개변수로 감)
}
});
btnStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
private void mInit() {
btnExecute = findViewById(R.id.btn_execute);
btnStop = findViewById(R.id.btn_stop);
progressBar = findViewById(R.id.progressBar);
}
}
이렇게 짜면 중지 할 수 없다
중지하려면 전역변수로 잡아줘야한다
멈추기
멈추기는 가능하나 다시 실행이 안된다
중지 재시작
package com.jaybon.asynctask;
import androidx.appcompat.app.AppCompatActivity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "Main_Activity";
private Button btnExecute, btnStop; //실행 중지버튼
private ProgressBar progressBar; // 진행바
private int value = 0; // 진행바의 퍼센테이지
private BackgroundTask task;
class BackgroundTask extends AsyncTask<Integer, Integer, Integer> { // 이것이 쓰레드가 됨
@Override // 타겟 호출 직전
protected void onPreExecute() {
super.onPreExecute();
progressBar.setProgress(value);
Log.d(TAG, "onPreExecute: ");
}
@Override // 타겟 (run()과 같음)
protected Integer doInBackground(Integer... integers) { // 스레드 실행시 인수 받기
Log.d(TAG, "doInBackground: ");
while (isCancelled() == false){
value = value + 5;
if(value >= 100){
break;
}
// 이 값은 onProgressUpdate로 넘어간다
// 넘어가서 바로 그려짐
publishProgress(value);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 이 값이 onPostExecute의 매개변수로 넘어간다
return 1; // 정상적으로 수행됐으면 1, 안됐으면 -1
}
@Override // UI쓰레드에 그림을 그려주는 메서드
protected void onProgressUpdate(Integer... values) { // publishProgress 리턴 값 받기
super.onProgressUpdate(values);
Log.d(TAG, "onProgressUpdate: ");
progressBar.setProgress(values[0]); // Integer...는 배열이라서 0번 주소 = Integer[]
}
@Override // 타겟 호출 이후
protected void onPostExecute(Integer integer) { // doInBackground 리턴 값 받기
// 리턴값 받아서 값에 따라 분기
super.onPostExecute(integer);
Log.d(TAG, "onPostExecute: ");
Toast.makeText(MainActivity.this, "다운로드 완료", Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mInit(); // 함수 사용할 때 내가 만든 것은 m을 붙이고 오버라이딩은 그대로
task = new BackgroundTask();
mListenser();
}
private void mListenser() {
btnExecute.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(task == null || task.isCancelled() == true){
task = new BackgroundTask();
task.execute(); // execute(여기의 값이 doInBackground 의 매개변수로 감)
}
}
});
btnStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
task.cancel(true);
}
});
}
private void mInit() {
btnExecute = findViewById(R.id.btn_execute);
btnStop = findViewById(R.id.btn_stop);
progressBar = findViewById(R.id.progressBar);
}
}
--------------
쓰레드종료 interrupt()를 걸면된다. (무조건 sleep 주자)
task.cancel = 잠깐 멈춰서 interrupt()
--------------
'낙서장' 카테고리의 다른 글
git 깃 // 공동작업 시 merge 머징 CONFLICT 문제 해결법 (0) | 2020.07.30 |
---|---|
최종 프로젝트 화면 (0) | 2020.07.29 |
안드로이드 // 플래그와 부가데이터 (0) | 2020.07.27 |
200724 실기 오답노트 (0) | 2020.07.24 |
실기 오답노트 200722 (0) | 2020.07.22 |