20 Ekim 2011 Perşembe

How to pass a complex object from one activity to another in Android

implement your class with Serializable. Let's suppose that this is your entity class:
import java.io.Serializable;
@SuppressWarnings("serial") //with this annotation we are going to hide compiler warning
public class Deneme implements Serializable {
public Deneme(double id, String name){
    this.id = id;
    this.name = name;
}
public double getId() {
    return id;
}
public void setId(double id) {
    this.id = id;
}
public String getName() {
    return this.name;
}
public void setName(String name) {
    this.name = name;
}
private double id;
private String name;
}
we are sending the object called dene from X activity to Y activity. Somewhere in X activity;
Deneme dene = new Deneme(4,"Mustafa");
Intent i = new Intent(this, Y.class);
i.putExtra("sampleObject", dene);
startActivity(i);
In Y activity we are getting the object.
Intent i = getIntent();
Deneme dene = (Deneme)i.getSerializableExtra("sampleObject");
that's it.

7 Ekim 2011 Cuma

AsyncTask class'tan dönen parametreyi handle etmek.

Merhaba

Android projelerinde genelde AsyncTask class, bir sub class olarak kullanıldığından o activity'e ait bir nesneyi set etmek çok fazla problem olmuyor. Bunun için OnPostExecute methodunda gerekli set işlemini yapmanız yeterli (konuyla ilgili bilgisi olmayanlar için güzel bir makale). Ancak bazı durumlarda network gibi UI thread üzerinde çalışmaya izin verilmeyen ancak bir çok activity tarafından kullanılacağı için inner class olarak tanımlanmasının da mantıklı olmadığı AsyncTask classlara ihtiyacımız olabilir. Bu durumda Context'i parametre olarak geçip AsyncTask class'ında o context'e ait gerekli field'ı ya da methodu set etmek mümkün gibi gözükse de bu çok kullanışlı olmayacaktır çünkü yine o methodu (veya field ya da context'i) cast edip içerisindeki set edeceğiniz field'ı manuel bir şekilde belirtmeniz gerekecektir.

Örneğimizde herhangi bir activity içerisinde soap request göndermek istenilen bir butona basıldığını varsayıyoruz.


public void onClick(View v) {
switch (v.getId()) {
case R.id.btnGonder:
String uri = "http://www.mustafaguven.com.tr/androidDenemeWebservice/Service1.asmx";
String soapAction = "http://tempuri.org/HelloWorld";
KeyValuePair[] parameters = new KeyValuePair[1];
parameters[0] = new KeyValuePair("a", "a parametresine atanan deger burada");
CallSoap soap = new CallSoap(uri, soapAction, parameters);
soap.setDataDownloadListener(new CallSoap.DataDownloadListener() {
public void dataDownloadedSuccessfully(String data) {
Log.e("GELEN DATA",data);
}
public void dataDownloadFailed() {

}
});
soap.execute("");
break;

default:
break;
}
}


Sıra geldi tüm bu istekleri hem dispatch edecek hem de işleyip geriye değer dönecek classımızı yazmaya. Hatırlayacağınız üzere yukarıda bir çok handikaptan bahsetmiştim, bu handikaplardan kurtulmak için kendi tanımlayacağımız bir Listener içeren AsyncTask class yazmak yeterli. Aşağıdaki class farklı activitylerden gelen soap isteklerini arkaplanda çalışan bir thread ile yönetip daha sonra bulduğu sonuç kümesini (result value) onPostExecute ile UI thread'e geçiyor. Buraya kadar yapılanlar, diğer asenkron classların kullanım metodolojisiyle zaten aynı. İşte tam bu noktada DataDownloadListener adlı listenerımız devreye giriyor. onPostExecute'da set edilen dataDownloadedSuccessfully methodu sayesinde bu class'ı call eden activity'de geri dönüş değeri kolaylıkla handle edilebiliyor.



package com.quadro.main.Util;

import org.apache.http.HttpEntity;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;

import BusinessObjects.KeyValuePair;
import android.os.AsyncTask;
import android.util.Log;

public class CallSoap extends AsyncTask {

private String methodName="";
private String uri="";
private String soapAction="";
private KeyValuePair[] parameters = null;
private String envelope = "";

DataDownloadListener dataDownloadListener;
   public void setDataDownloadListener(DataDownloadListener dataDownloadListener) {
       this.dataDownloadListener = dataDownloadListener;
   }

public CallSoap(String uri, String soapAction, KeyValuePair[] parameters){
this.uri=uri;
this.soapAction=soapAction;
this.parameters = parameters;
int iLastIndexOf = soapAction.lastIndexOf("/");
if(iLastIndexOf>0){
this.methodName=soapAction.substring(iLastIndexOf+1);
}
this.envelope = getSoapTemplate();
}

private String getSoapTemplate() {
String parameterXml="";
if(parameters!=null){
for (int i = 0; i < parameters.length; i++) {
KeyValuePair kv = parameters[i];
parameterXml+=String.format("<%s>%s",kv.getText(),kv.getValue(), kv.getText());
}

}
String envelope="<?xml version=\"1.0\" encoding=\"iso-8859-9\"?>"+
"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
"soap:encodingStyle=\"http://www.w3.org/2001/12/soap-encoding\">"+
"<soap:Body>"+
"<%s xmlns=\"http://tempuri.org/\">"+
"%s"+
"</%s>"+
"</soap:Body>"+
"</soap:Envelope>";
envelope = String.format(envelope, this.methodName, parameterXml, this.methodName);
return envelope;
}


@Override
protected String doInBackground(String... parameters) {
final DefaultHttpClient httpClient=new DefaultHttpClient();
HttpParams params = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(params, 10000);
HttpConnectionParams.setSoTimeout(params, 15000);

HttpProtocolParams.setUseExpectContinue(params, true);
HttpPost httppost = new HttpPost(uri);

httppost.setHeader("soapaction", soapAction);
httppost.setHeader("Content-Type", "text/xml; charset=iso-8859-9");

String responseString="";
try {
HttpEntity entity = new StringEntity(envelope, "iso-8859-9");
httppost.setEntity(entity);

ResponseHandler rh=new ResponseHandlerTr();
responseString=httpClient.execute(httppost, rh);
}
catch (Exception e) {
Log.e("exception", e.toString());
}

httpClient.getConnectionManager().shutdown();
return responseString;
}

@Override
protected void onPostExecute(final String responseString) {
       if(responseString != null){            
        dataDownloadListener.dataDownloadedSuccessfully(responseString);
       } else
        dataDownloadListener.dataDownloadFailed();
}

   public static interface DataDownloadListener {
       void dataDownloadedSuccessfully(String data);
       void dataDownloadFailed();
   }

}

Anlaşılmayan bir nokta olursa çekinmeden danışabilirsiniz.

İyi çalışmalar,
Mustafa Güven

6 Ekim 2011 Perşembe

3. party kütüphane kullanmadan (ksoap2) Android ile soap request işlemleri. Soap request on Android without using any third party library like ksoap2


Uzun bir aradan sonra tekrar merhaba.
(Hello again after a long time)

Büyük bir çoğunluk, android ile webservice'e bağlanmak istediğinde ksoap2'yi kullanıyor. Bunun zaman zaman dezavantajlarıyla karşılaşmış biri olarak size nasıl 3. party kütüphane kullanmadan kendi soap requestiniz ile bir webservice'e bağlanacağınızı açıklayacağım.
(A large majority of the android developers are using ksoap2 library when they want to connect to a webservice. As a man who encountered with disadvantages and advantages of these kind of libraries I will explain you how to send soap request without using any third party library -like soap2- on android)

HelloWorld adında bir webmethodumuz var, String türünde a değişkeni alıyor ve geriye a parametresinin değerine "türkçe karakterlerle doğru çalışıyor:" ibaresini ekleyerek dönüyor. Bilmeyenler .NET ile nasıl webservice yapılacağı konusunu anlatan ilgili örneğe buradan ulaşabilirler.
(There is a webmethod called HelloWorld. It takes a String as a parameter named a and returns with adding an expression which is "türkçe karakterlerle doğru çalışıyor" (which means it works correctly with turkish characters) to the return value. If you don't know how to create a webservice on .NET you can see the example by clicking here.)

[WebMethod]
public string HelloWorld(string a){
       return "türkçe karakterlerle doğru çalışıyor:  " + a;
}



Artık android tarafına geçebiliriz.
(Now we can go to the android side)

private void soapDeneme() {
  String envelope="<?xml version=\"1.0\" encoding=\"iso-8859-9\"?>"+
    "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
    "soap:encodingStyle=\"http://www.w3.org/2001/12/soap-encoding\">"+
    "<soap:Body>"+
    "<HelloWorld xmlns=\"http://tempuri.org/\">"+
    "<a>abcçdefgğhıijklmnoöprsştuüvyz</a>"+
    "</HelloWorld>"+
    "</soap:Body>"+
    "</soap:Envelope>";
  String url = "http://www.mustafaguven.com.tr/androidDenemeWebservice/Service1.asmx";
  String soapAction = "http://tempuri.org/HelloWorld";
  new CallWebService().execute(url,soapAction,envelope); 
 }

Yukarıda en çok dikkat edilmesi gereken şey request'imizi bir AsyncTask içerisinde call etmemiz. Aslında bu 3.0'ın altındaki herhangi bir versiyonda belki problem yaratmayabilir ancak honeycomb ile birlikte android bu tür işlemleri UI thread üzerinde yapmanıza izin vermeyecektir. (NetworkOnMainThreadException, Designing For Responsiveness) Bunun için ya bir handler içerisinde call işlemini gerçekleştirmelisiniz ya da bizim bu örnekte yaptığımız gibi asynctask içerisinde.
(The most noticeable think above is that you must use another thread to call a webservice if the application which you are developing runs on the honeycomb (3.0) because UI thread does not support for this action otherwise it will be throwed out an exception called NetworkOnMainThreadException. for further information: Designing For Responsiveness)

 class CallWebService extends AsyncTask<String, String, String>{

  @Override
  protected String doInBackground(String... parameters) { 
   final DefaultHttpClient httpClient=new DefaultHttpClient(); 
   HttpParams params = httpClient.getParams(); 
   HttpConnectionParams.setConnectionTimeout(params, 10000); 
   HttpConnectionParams.setSoTimeout(params, 15000); 
   HttpProtocolParams.setUseExpectContinue(params, true); 
   HttpPost httppost = new HttpPost(parameters[0]);
   httppost.setHeader("soapaction", parameters[1]);
   httppost.setHeader("Content-Type", "text/xml; charset=iso-8859-9");

   String responseString="";
   try {
    HttpEntity entity = new StringEntity(parameters[2], "iso-8859-9");
    httppost.setEntity(entity);
    ResponseHandler rh=new ResponseHandlerTr();
    responseString=httpClient.execute(httppost, rh);
   }
   catch (Exception e) {
    Log.e("hata", e.getMessage());
   }
   httpClient.getConnectionManager().shutdown();
   return responseString;
  }
 }
(Yukarıda HttpEntity entity = new StringEntity(parameters[2], "iso-8859-9"); bölümünde charset'inizi "iso-8859-9" şeklinde belirtmezseniz webservice tarafında türkçe karakterlerin hepsi düzgün çalışmayacaktır.)
(You need to describe the encoding type as above to display turkish characters correctly)

Gelen response'da encoding yapmak için bu response'u handle etmemiz gerekli bunun için BasicResponseHandler class'ından extend ettiğimiz ResponseHandlerTr class'ını yazıyoruz.
(We are creating ResponseHandlerTr class which extends BasicResponseHandler to handle the response and encode it)

package com.quadro.main.Util;
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpResponseException;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.util.EntityUtils;

public class ResponseHandlerTr extends BasicResponseHandler {
 @Override
 public String handleResponse(HttpResponse response) throws HttpResponseException, IOException      {
    StatusLine statusLine = response.getStatusLine();
         if (statusLine.getStatusCode() >= 300) {
             throw new HttpResponseException(statusLine.getStatusCode(),
                     statusLine.getReasonPhrase());
         }

         HttpEntity entity = response.getEntity();
         return entity == null ? null : EntityUtils.toString(entity, "iso-8859-9");
 }
 
}
Webservice'ten gelen cevap:
(The response comes from the webservice)



Anlaşılmayan bir nokta olursa çekinmeden danışabilirsiniz.
(Please feel free to contact me if you have any questions)