Search This Blog

Friday, July 22, 2011

SOAPy Deux

I moved my small Android test app ahead a bit by adding threading via an AsyncTask. All you need to do is subclass AsyncTask and implement a few methods and Bob is your uncle. The only things that required some real thought and trial and error was displaying dialogs and error handling.

The ProgressDialog was very easy to use. I just took the base activity as an argument and created on in the constructor for my CallServiceTask:

        // constructor creates progress dialog on activity
        public CallServiceTask(Activity activity) {
            dialog = new ProgressDialog(activity);
        }


The error dialog was a bit more tricky. To implement exception handling, I created another class called MyResult which contains the results of the web service call (in this simple case, a String) and an Exception. I used this class to catch the exceptions:

        @Override
        protected MyResult doInBackground(String... operation) {
            MyResult result = new MyResult();
            SoapObject request = new SoapObject(WSDL_TARGET_NAMESPACE,
                    operation[0]);
            request.addProperty("arg0", operation[1]);
            SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
                    SoapEnvelope.VER11);
            envelope.setOutputSoapObject(request);
            HttpTransportSE httpTransport = new HttpTransportSE(SOAP_ADDRESS);
            httpTransport.debug = true;

            try {
                httpTransport.call(SOAP_ACTION, envelope);
                Object response = envelope.getResponse();
                result.setAnswer(response.toString());
            } catch (Exception ex) {
                // log it, set the exception flag and return
                Log.i("L10Systems", ex.toString());
                result.setError(ex);
            }
            return result;
        }

Then when returning the results in onPostExecute, I checked for the exception. If we had an exception, I show an AlertDialog. This took me a lot of trial and error and looking around to figure out. It certainly is a bit more complex than the typical ShowDialog() method you find in most desktop development environments.

The full code is below. Next, I'm going to add user input to the web service to actually interact with it and try some more complex data types.

package com.l10systems.helloandroid;

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

import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class HelloAndroid extends Activity {
    private static final String SOAP_ACTION = "http://l10systems.appspot.com/hellosoapserver";
    private static final String GOODBYE_OPERATION_NAME = "sayGoodbye";
    private static final String HELLO_OPERATION_NAME = "sayHello";
    private static final String WSDL_TARGET_NAMESPACE = "http://hellosoap.l10systems.com/";
    private static final String SOAP_ADDRESS = "http://l10systems.appspot.com/hellosoapserver";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        final Button buttonGoodbye = (Button) findViewById(R.id.button1);
        buttonGoodbye.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                new CallServiceTask(HelloAndroid.this).execute(
                        GOODBYE_OPERATION_NAME, "Blargh");
            }
        });
        final Button buttonHello = (Button) findViewById(R.id.button2);
        buttonHello.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                new CallServiceTask(HelloAndroid.this).execute(
                        HELLO_OPERATION_NAME, "Blargh");
            }
        });
    }

    private class CallServiceTask extends AsyncTask {
        private ProgressDialog dialog;

        // constructor creates progress dialog on activity
        public CallServiceTask(Activity activity) {
            dialog = new ProgressDialog(activity);
        }

        @Override
        protected void onPreExecute() {
            this.dialog.setMessage("Calling web service");
            this.dialog.show();
        }

        @Override
        protected MyResult doInBackground(String... operation) {
            MyResult result = new MyResult();
            SoapObject request = new SoapObject(WSDL_TARGET_NAMESPACE,
                    operation[0]);
            request.addProperty("arg0", operation[1]);
            SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
                    SoapEnvelope.VER11);
            envelope.setOutputSoapObject(request);
            HttpTransportSE httpTransport = new HttpTransportSE(SOAP_ADDRESS);
            httpTransport.debug = true;

            try {
                httpTransport.call(SOAP_ACTION, envelope);
                Object response = envelope.getResponse();
                result.setAnswer(response.toString());
            } catch (Exception ex) {
                // log it, set the exception flag and return
                Log.i("L10Systems", ex.toString());
                result.setError(ex);
            }
            return result;
        }

        @Override
        protected void onPostExecute(MyResult result) {
            // close the progress dialog
            if (dialog.isShowing()) {
                dialog.dismiss();
            }
            // if we have an error, show a dialog
            if (result.getError() != null) {
                AlertDialog.Builder builder = new AlertDialog.Builder(dialog
                        .getContext());
                builder.setMessage("There was a problem with the web service.")
                        .setCancelable(false).setPositiveButton("OK",
                                new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog,
                                            int id) {
                                        dialog.cancel();
                                    }
                                });
                AlertDialog alert = builder.create();
                alert.show();
                // otherwise, set the text view with the result
            } else {
                TextView textView = (TextView) findViewById(R.id.textView1);
                textView.setText(result.getAnswer());
            }
        }
    }
}

No comments: