Android, uzun süren işlemlerin yapılabilinmesi için AsyncTask isimli bir mekanizma sağlar. Bu mekanizma normalde sizin yapmanız gereken (ve pek güzel görünmeyen) thread açma ve benzeri işlemleri yöneten ve kolaylaştıran bir mekanizma.

Bu yazımda daha önce anlattığım SOAP web-servis iletişiminde kullandığım kodu AsyncTask’a nasıl uyarlanabileceğini anlatacağım. Burada çağırılan örnek servisi daha önceki örnekte çağırdığımızla aynı.

Geliştireceğimiz arkaplan işlemi için AsyncTask sınıfını extend eden bir sınıf geliştirmeliyiz.

protected class ServiceAsyncTask extends AsyncTask<String, Void, String>

Bu sınıf tanımlamasında alınan 3 tip görüyorsunuz. Burada atadığımız tipler aşağıdaki metodlarda parametre veya dönüş tipi olarak kullanacak.

Bu oluşturduğumuz sınıfın override edilebilinecek birkaç metodu olacak. Bunlardan en önemlilerini açıklayacağım

protected void onPreExecute()

İşlem öncesi çalıştırılacak method. Burada GUI işlemleri yapılabilir.

protected String doInBackground(String... strings)

Bu method arkaplan işleminin gerçekleştiği metod. Sınıfa verdiğimiz 1. tipi parametre olarak alır ve 3. tipi dönüş tipi olarak kullanır. Burada ilerleyişi raporlamak için publishProgress(); methodunu çağırabiliriz.

protected void onProgressUpdate(Void... values)

İşlemin durumunu takip etmemizi sağlayan metod. Burada sınıfa verdiğimiz 2. parametre tipinde bir parametre alabiliriz. GUI işlemleri gerçekleştirilebilir.

protected void onPostExecute(String response)

Arkaplan işlemi sonrası yapılacaklar bu method içinde gerçekleştirilmelidir. GUI işlemleri gerçekleştirilebilir.

protected void onCancelled()

Son olarak arkaplan işleminin iptal edildiğinde bu metod çalıştırılır. GUI işlemleri gerçekleştirilebilir.

Konuyu daha iyi açıklayabilmek için bir örnek hazırladım. Bu örnekte daha önce yaptığımız bir örnek üzerinden gideceğiz ve daha önce yazdığımız kodu AsyncTask kullanarak yeniden geliştireceğiz.

package com.canyapan.android.soap.web_service.connection.test;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnDismissListener;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }

  public void onButtonSendClicked(View view) {
    final EditText inputView = (EditText) findViewById(R.id.editTextMessage);

    // Servisi çağıracağımız methodu ihtiyacımız olacak parametrelerle
    // çağırıyoruz.
    ServiceAsyncTask asyncTask = new ServiceAsyncTask(false, false);
    asyncTask.execute(inputView.getText().toString());
  }

  private String callService(final String input) throws Exception {
    // SOAP zarf (envelope) objesini oluşturuyoruz.
    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);

    // Çağıracağımız servis operasyonunun adı ve namespace'i ile bir
    // request objesi oluşturuyoruz.
    SoapObject request = new SoapObject("http://services.test.com", "echo");
    // Operasyonun aldığı parametreleri ekliyoruz.
    request.addProperty("value", input);

    // Bu request objemizi göndereceğimiz zarf'a dahil ediyoruz.
    envelope.setOutputSoapObject(request);

    // Servisimizin bağlantı bilgilerini giriyoruz. Burada 10.0.2.2
    // ip adresine gönderdiğimiz istekler
    // geliştirme yaptığımız bilgisayara yönlendirilir. Port olarak
    // Apache web-server'ın dinlediği port 8080 belirliyoruz.
    // Ve servisin EndPoint detaylarını yazıyoruz. Bu bilgiyi
    // WSDL'den edinebilirsiniz.
    // Timeout olarak 60sn verdim.
    HttpTransportSE transport = new HttpTransportSE("http://10.0.2.2:8080/Axis2TestProject/services/TestService.TestServiceHttpSoap11Endpoint/", 60000);

    Object response = null;
    try {
      // Servisimizi onun action bilgisi ile zarfımızı dahil
      // ederek çağırıyoruz.
      transport.debug = true;

      transport.call("urn:echo", envelope);

      // Dönen cevabı içeren objeyi alıyoruz.
      response = envelope.getResponse();

      // Cevabı dönüyoruz
      return response.toString();
    } catch (Exception e) {
      Log.e("KSOAP-CALL", "Call unsuccesful", e);

      Log.d("request", transport.requestDump);

      if (null != transport.responseDump)
        Log.d("response", transport.responseDump);

      throw e;
    }
  }

  private void printServiceOutput(final String output) {
    final TextView outputView = (TextView) findViewById(R.id.textViewResponse);

    // Bir TextView içinde bu dönen cevabı gösteriyoruz.
    outputView.setText(output);
  }

  /**
   * Bu sınıf AsyncTask sınıfını extend eden ve ihtiyacımız olan arkaplan işleminin gerçekleşeceği sınıf.
   * Burada giden ve gelen veri tiplerini belirlememiz gerekiyor.
   */
  protected class ServiceAsyncTask extends AsyncTask<String, Integer, String> { // Gönderilecek veri, İşlem durumu, Gelen veri
    private ProgressDialog progressDialog = null;
    private final boolean cancelable;
    private final boolean exitOnError;
    private String message = null;

    /**
     * Yapıcı metod.
     * @param cancelable Eğer bu değişken true ise işlemi iptal etmek için gerekli bileşenler eklenir.
     * @param exitOnError Eğer bu değişken true ise hata durumunda aktivite sonlandırılır.
     */
    public ServiceAsyncTask(final boolean cancelable, final boolean exitOnError) {
      this.cancelable = cancelable;
      this.exitOnError = exitOnError;
    }

    /**
     * İşlem öncesi yapılacaklar bu metod içinde gerçekleşir. UI thread içinde çalışır.
     */
    @Override
    protected void onPreExecute() {
      // İşlem göstergeçini devam eden işlemlerde kullanıcıyı bilgilendirmek için kullanacağız.
      progressDialog = new ProgressDialog(MainActivity.this);
      progressDialog.setTitle("Please wait...");
      progressDialog.setCancelable(cancelable);
      progressDialog.setIndeterminate(true);

      if (cancelable) {
        progressDialog.setButton(ProgressDialog.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int which) {
            progressDialog.cancel();
          }
        });
      }

      progressDialog.setOnCancelListener(new OnCancelListener() {
        @Override
        public void onCancel(DialogInterface dialog) {
          ServiceAsyncTask.this.cancel(true);

          if (exitOnError) {
            MainActivity.this.finish();
          }
        }
      });

      progressDialog.show();
    }

    /**
     * Arkaplan işlemimiz burada gerçekleşir. Android bu işlem için bir thread açar bu sebeple burada direk UI içinde bir işlem yapmamalıyız.
     */
    @Override
    protected String doInBackground(String... strings) {
      try {
        return callService(strings[0]);
      } catch (Exception e) {
        message = e.getMessage();

        Log.e(this.getClass().getName(), "List cannot be loaded.", e);
        return null;
      }
    }

    /**
     * Arkaplan işlemimiz bittiğinde bu metod çalışır.
     */
    @Override
    protected void onPostExecute(String response) {
      progressDialog.setCancelable(true);

      if (null == message) {
        progressDialog.setTitle("Successful");

        printServiceOutput(response);
      } else {
        progressDialog.setTitle("Error :(");
        progressDialog.setMessage(message);

        if (exitOnError) {
          progressDialog.setOnDismissListener(new OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
              MainActivity.this.finish();
            }
          });
        }
      }

      new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
          if (progressDialog.isShowing()) {
            progressDialog.dismiss();
          }
        }
      }, null == message ? 700 : 3000);
    }

    /**
     * Arkaplan işlemi iptal edildiğinde bu metod çalışır.
     */
    @Override
    protected void onCancelled() {
      if (progressDialog.isShowing()) {
        progressDialog.dismiss();
      }

      if (exitOnError &amp;&amp; !MainActivity.this.isFinishing()) {
        MainActivity.this.finish();
      }
    }

    public String getMessage() {
      return message;
    }
  }
}

Bu yazımında sonuna geldik. Başka bir yazımda görüşmek üzere..