AsyncTask Android örneği

AsyncTask` hakkında bir şeyler okuyordum ve aşağıdaki basit programı denedim. Ancak çalışmıyor gibi görünüyor. Nasıl çalışmasını sağlayabilirim?

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) {
        }
    }
}

Sadece arka plan işleminde 5 saniye sonra etiketi değiştirmeye çalışıyorum.

Bu benim main.xml dosyam:

<?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>
Çözüm

Tamam, GUI'ye başka bir iş parçacığı üzerinden erişmeye çalışıyorsunuz. Bu, esas olarak, iyi bir uygulama değildir.

AsyncTask, doInBackground() içindeki her şeyi, görünümlerinizin bulunduğu GUI'ye erişimi olmayan başka bir iş parçacığının içinde yürütür.

preExecute()vepostExecute()bu yeni iş parçacığında ağır işler yapılmadan önce ve yapıldıktan sonra GUI'ye erişmenizi sağlar, hatta uzun işlemin sonucunupostExecute()` işlevine aktararak işlem sonuçlarını gösterebilirsiniz.

TextView'inizi daha sonra güncelleyeceğiniz bu satırlara bakın:

TextView txt = findViewById(R.id.output);
txt.setText("Executed");

bunları onPostExecute() içine koyun

Daha sonra doInBackground tamamlandıktan sonra TextView metninizin güncellendiğini göreceksiniz.

EDIT: onClick dinleyicinizin hangi Görünümün seçildiğini kontrol etmediğini fark ettim. Bunu yapmanın en kolay yolunun switch deyimleri olduğunu düşünüyorum. Karışıklığı önlemek için tüm önerilerle birlikte aşağıda düzenlenmiş eksiksiz bir sınıfım var.

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 {

        @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);
            // might want to change "executed" for the returned string passed
            // into onPostExecute() but that is upto you
        }
    }
}
Yorumlar (11)

Düzgün çalıştığından eminim, ancak arka plan iş parçacığında kullanıcı arayüzü öğelerini değiştirmeye çalışıyorsunuz ve bu işe yaramayacak.

Çağrınızı ve AsyncTask'ı aşağıdaki gibi revize edin:

Çağrı Sınıfı

Not: Ben şahsen onPostExecute() fonksiyonunu AsyncTask iş parçacığını çalıştırdığınız her yerde kullanmanızı öneririm, AsyncTask'ın kendisini genişleten sınıfta değil. Özellikle AsyncTask'a birden fazla yerde ihtiyacınız varsa ve sonuçları biraz farklı işliyorsanız, kodun okunmasını kolaylaştırdığını düşünüyorum.

new LongThread() {
    @Override public void onPostExecute(String result) {
        TextView txt = (TextView) findViewById(R.id.output);
        txt.setText(result);
    }
}.execute("");

LongThread sınıfı (AsyncTask'ı genişletir):

@Override
protected String doInBackground(String... params) {
    for (int i = 0; i < 5; i++) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    return "Executed";
}      
Yorumlar (2)

Bu iki çizgiyi taşıyın:

TextView txt = (TextView) findViewById(R.id.output);
txt.setText("Executed");

AsyncTask'ınızın doInBackground yönteminden çıkarın ve onPostExecute yöntemine koyun. AsyncTask`ınız aşağıdaki gibi görünmelidir:

private class LongOperation extends AsyncTask {

    @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);
    }
}
Yorumlar (2)