에 대해 읽고 있었고 AsyncTask
아래 간단한 프로그램을 시도했습니다. 그러나 작동하지 않는 것 같습니다. 어떻게 작동시킬 수 있습니까?
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>
답변
좋아, 다른 스레드를 통해 GUI에 액세스하려고합니다. 이것은 기본적으로 좋은 습관이 아닙니다.
AsyncTask doInBackground()
는 다른 스레드 내부의 모든 것을 실행 하며 뷰가있는 GUI에 액세스 할 수 없습니다.
preExecute()
그리고 postExecute()
당신은 이전과 무거운이 새로운 스레드에서 발생한 후 GUI에 대한 액세스를 제공하며, 당신도 할 수 긴 작업의 결과를 전달할 수있는 postExecute()
후 처리의 결과를 표시합니다.
나중에 TextView를 업데이트하는 다음 행을 참조하십시오.
TextView txt = findViewById(R.id.output);
txt.setText("Executed");
에 넣으십시오 onPostExecute()
.
그러면 doInBackground
완료 후 TextView 텍스트가 업데이트 된 것을 볼 수 있습니다 .
onClick 리스너가 선택된보기를 확인하지 않는 것으로 나타났습니다. 가장 쉬운 방법은 switch 문을 사용하는 것입니다. 혼란을 피하기 위해 모든 제안 사항을 아래에서 편집 한 완전한 수업이 있습니다.
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;
AsyncTask<?, ?, ?> runningTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btn = findViewById(R.id.button1);
// Because we implement OnClickListener, we only
// have to pass "this" (much easier)
btn.setOnClickListener(this);
}
@Override
public void onClick(View view) {
// Detect the view that was "clicked"
switch (view.getId()) {
case R.id.button1:
if (runningTask != null)
runningTask.cancel(true);
runningTask = new LongOperation();
runningTask.execute();
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// Cancel running task(s) to avoid memory leaks
if (runningTask != null)
runningTask.cancel(true);
}
private final class LongOperation extends AsyncTask<Void, Void, String> {
@Override
protected String doInBackground(Void... params) {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// We were cancelled; stop sleeping!
}
}
return "Executed";
}
@Override
protected void onPostExecute(String result) {
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed"); // txt.setText(result);
// You might want to change "executed" for the returned string
// passed into onPostExecute(), but that is up to you
}
}
}
답변
답변
제대로 실행되고 있다고 확신하지만 백그라운드 스레드에서 UI 요소를 변경하려고 시도하지만 그렇지 않습니다.
다음과 같이 호출 및 AsyncTask를 수정하십시오.
호출 클래스
참고 : 개인적 onPostExecute()
으로 AsyncTask 자체를 확장하는 클래스가 아닌 AsyncTask 스레드를 실행할 때마다 사용하는 것이 좋습니다 . 결과가 약간 다른 여러 위치에서 AsyncTask가 필요한 경우 특히 코드를 쉽게 읽을 수 있다고 생각합니다.
new LongThread() {
@Override public void onPostExecute(String result) {
TextView txt = (TextView) findViewById(R.id.output);
txt.setText(result);
}
}.execute("");
LongThread 클래스 (AsyncTask 확장) :
@Override
protected String doInBackground(String... params) {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return "Executed";
}
답변
Android의 AsyncTask를 사용하는 간단한 예를 만들었습니다. onPreExecute(), doInBackground(), publishProgress()
마지막으로 시작합니다 onProgressUpdate()
.
여기서 doInBackground ()는 백그라운드 스레드로 작동하고 다른 스레드는 UI 스레드에서 작동합니다. doInBackground ()에서 UI 요소에 액세스 할 수 없습니다. 순서는 내가 언급 한 것과 같습니다.
당신이에서 어떤 위젯을 업데이트해야 할 경우에는 doInBackground
, 당신은 할 수 publishProgress
에서 doInBackground
어떤 호출 onProgressUpdate
하여 UI 위젯을 업데이트 할 수 있습니다.
class TestAsync extends AsyncTask<Void, Integer, String> {
String TAG = getClass().getSimpleName();
protected void onPreExecute() {
super.onPreExecute();
Log.d(TAG + " PreExceute","On pre Exceute......");
}
protected String doInBackground(Void...arg0) {
Log.d(TAG + " DoINBackGround", "On doInBackground...");
for (int i=0; i<10; i++){
Integer in = new Integer(i);
publishProgress(i);
}
return "You are at PostExecute";
}
protected void onProgressUpdate(Integer...a) {
super.onProgressUpdate(a);
Log.d(TAG + " onProgressUpdate", "You are in progress update ... " + a[0]);
}
protected void onPostExecute(String result) {
super.onPostExecute(result);
Log.d(TAG + " onPostExecute", "" + result);
}
}
당신의 활동에서 이것을 다음과 같이 부르십시오 :
new TestAsync().execute();
답변
이 두 줄을 이동하십시오.
TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");
AsyncTask의 doInBackground
메소드에서 벗어나 메소드에 넣으십시오 onPostExecute
. 당신 AsyncTask
은 다음과 같이 보일 것입니다 :
private class LongOperation extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
try {
Thread.sleep(5000); // no need for a loop
} catch (InterruptedException e) {
Log.e("LongOperation", "Interrupted", e);
return "Interrupted";
}
return "Executed";
}
@Override
protected void onPostExecute(String result) {
TextView txt = (TextView) findViewById(R.id.output);
txt.setText(result);
}
}
답변
배경 / 이론
AsyncTask를 사용하면 결과를 UI 스레드에 게시하는 동안 백그라운드 스레드에서 작업을 실행할 수 있습니다.
사용자는 항상 앱과 상호 작용할 수 있어야하므로 웹에서 콘텐츠를 다운로드하는 등의 작업으로 기본 (UI) 스레드 를 차단하지 않는 것이 중요
합니다 .이것이 우리가를 사용하는 이유
AsyncTask
입니다.UI 스레드 메시지 큐와 처리기를 래핑하여 다른 스레드에서 실행 가능한 개체와 메시지를 보내고 처리 할 수 있는 간단한 인터페이스를 제공 합니다 .
이행
AsyncTask 는 일반 클래스입니다. ( 생성자에 매개 변수화 된 유형 을 사용합니다.)
다음 세 가지 일반 유형을 사용합니다.
Params
-실행시 태스크로 전송되는 매개 변수 유형
Progress
-백그라운드 계산 중에 게시 된 진행률 단위의 유형
Result
-백그라운드 계산 결과의 유형.
모든 유형이 항상 비동기 작업에서 사용되는 것은 아닙니다. 유형을 사용하지 않는 것으로 표시하려면 Void 유형을 사용하십시오.
private class MyTask extends AsyncTask<Void, Void, Void> { ... }
이 세 매개 변수 는 다음 에서 대체 할 수있는 세 가지 기본 기능에 해당합니다AsyncTask
.
doInBackground(Params...)
onProgressUpdate(Progress...)
onPostExecute(Result)
AsyncTask를 실행하려면
execute()
백그라운드 작업으로 전송 될 파라미터를 사용하여 호출 합니다.
무슨 일이야
-
에 주 /의 UI 스레드 ,
onPreExecute()
라고합니다.- 이 스레드에서 무언가를 초기화합니다. (예 : 사용자 인터페이스에 진행률 표시 줄이 표시됩니다.)
-
A의 백그라운드 스레드 ,
doInBackground(Params...)
라고합니다.- (
Params
을 통해 전달되었습니다execute
.) - 장기 실행 작업이 발생하는 위치
-
doInBackground()
AsyncTask를 사용하려면 최소한 재정의해야합니다 . -
publishProgress(Progress...)
백그라운드 계산이 여전히 실행되는 동안 진행률 표시 (예 : UI 애니메이션 또는 로그 텍스트 인쇄)로 사용자 인터페이스를 업데이트하려면 호출하십시오 .- 원인은
onProgressUpdate()
호출 할 수 있습니다.
- 원인은
- (
-
온 배경 스레드 결과는에서 반환됩니다
doInBackground()
.- (다음 단계가 시작됩니다.)
-
에 주 /의 UI 스레드 ,
onPostExecute()
반환 된 결과라고합니다.
예
두 예에서 “차단 작업”은 웹에서 다운로드 한 것입니다.
- 예제 A 는 이미지를 다운로드 하여 ImageView에 표시합니다.
- 예제 B는 일부 파일을 다운로드 합니다 .
예 A
이 doInBackground()
메소드는 이미지를 다운로드하여 BitMap 유형의 오브젝트에 저장합니다. 이 onPostExecute()
메소드는 비트 맵을 가져와 ImageView에 배치합니다.
class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
ImageView bitImage;
public DownloadImageTask(ImageView bitImage) {
this.bitImage = bitImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mBmp = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mBmp = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mBmp;
}
protected void onPostExecute(Bitmap result) {
bitImage.setImageBitmap(result);
}
}
실시 예 B
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
예제 B 실행
new DownloadFilesTask().execute(url1, url2, url3);
답변
비동기 작업이 실행될 때 작업은 다음 4 단계를 거칩니다.
- onPreExecute ()
- doInBackground (파람 …)
- onProgressUpdate (진행 …)
- onPostExecute (결과)
아래는 데모 예입니다.
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled())
break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
그리고 일단 생성하면 작업이 매우 간단하게 실행됩니다.
new DownloadFilesTask().execute(url1, url2, url3);