Search code examples
androidasp.netweb-servicesarraylistandroid-ksoap2

consuming list of object from asp.net webservice using ksoap in android app


i am stuck in asituation where i have to consume an asp.net webservice that returns a list of objects in my android app the webservice in question returns a list of programmedflights which contains parameters like flightCode,flightDate,flightType and the like, below is the xml result i get from the webservice when i call it in my browser

enter image description here

i want my app to be able to read the programmedflights as above and set them as new programmedflights objects as the class is in my android app below is my class of programmedflights in android app

public class programmed_flights {
    private int    id;
    private String company;
    private String flight_date;
    private String flight_num;
    private String air_port;
    private String flight_type;
    private String status;

    public programmed_flights(){

    }

    public programmed_flights(String company, String flight_date, String flight_num, String air_port,String flight_type,String status ) {
        this.company = company;
        this.flight_date = flight_date;
        this.flight_num = flight_num;
        this.air_port = air_port;
        this.flight_type = flight_type;
        this.status = status;
    }

    public String flightToString() {
        return  company+" "+flight_date+" "+flight_num+" "+air_port+" "+flight_type+" "+status;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getCompany() {
        return company;
    }

    public void setCompany(String company) {
        this.company = company;
    }

    public String getFlight_date() {
        return flight_date;
    }

    public void setFlight_date(String flight_date) {
        this.flight_date = flight_date;
    }

    public String getFlight_num() {
        return flight_num;
    }

    public void setFlight_num(String flight_num) {
        this.flight_num = flight_num;
    }

    public String getAir_port() {
        return air_port;
    }

    public void setAir_port(String air_port) {
        this.air_port = air_port;
    }

    public String getFlight_type() {
        return flight_type;
    }

    public void setFlight_type(String flight_type) {
        this.flight_type = flight_type;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }


}

it my first time using ksoap in android an i am totally void of any possible solution to this, i checked various post online on how to get this done but none was what i expected, any help will be greatly apreciated

also this is the code i use to consume the service

public String getSoap(long option, String dt){

        SoapObject request = new SoapObject(WSDL_TARGET_NAMESPACE,OPERATION_NAME);
        PropertyInfo opt=new PropertyInfo();
        opt.setName("option");
        opt.setValue(option);
        opt.setType(long.class);
        request.addProperty(opt);

        PropertyInfo date=new PropertyInfo();
        date.setName("dt");
        date.setValue(dt);
        date.setType(String.class);
        request.addProperty(date);

        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
        envelope.dotNet = true;
        envelope.setOutputSoapObject(request);
        HttpTransportSE httpTransport = new HttpTransportSE(SOAP_ADDRESS);
        Object response=null;

        try
        {
            httpTransport.call(SOAP_ACTION, envelope);
            response = envelope.getResponse();
        }
        catch (Exception exception)
        {
            exception.printStackTrace();
            response=exception.toString();
        }
        return response.toString();
        }
    } 

Solution

  • After fighting with this trouble for one week i finally found the right way of doing this, after doing much research about the subject i found out that most post regarding the consumption of list of object from dotnet web services in android application all left out an important aspect of doing that mainly because the post are not updated now back to my issue

    calling a webservice from android means you are initiating a task that probably takes time to give a result since the app has to communicate with the server and then recieve a response, to do this correctly you have to implement threading which means doing a task in background while the app runs normally waiting for a response to do this in android you have to user the AsyncTask or Service Classes but for our web service i will forcus on AsyncTask

    so to solve the problem above correctly we have to first create a programmedFlights class that implement KvmSerialisation since our web service returns a list of programmedFlights objects we need to send that serialised class in our SoapEnvelope to help the server identify an do a correct mapping of our objects properties so as to recieve the correct response we want ,to know more about ksoap2 KvmSerialisation visit this link

    below is our programmedFlights class tha implements KvmSerialasation

    package com.YouPakageName.serialisation;
    
    //importing needed classes
    import org.ksoap2.serialization.KvmSerializable;
    import org.ksoap2.serialization.PropertyInfo;
    import java.util.Hashtable;
    
    public class programmedFlights  implements KvmSerializable {
        //setting properties
        public int    id;
        public String company;
        public String flight_date;
        public String flight_num;
        public String flight_type;
        public String air_port;
        public String status;
    
        //default constructor
        public programmedFlights(){
    
        }
        //constructor with parameters
        public programmedFlights(int id,String company,String flight_date,String flight_num,String flight_type,String air_port,String status){
    
            this.id = id;
            this.company = company;
            this.flight_date = flight_date;
            this.flight_num = flight_num;
            this.flight_type = flight_type;
            this.air_port = air_port;
            this.status = status;
        }
    
        //here we override our kvmSerialisation methods an adapt to our class
    
        //needed method
        @Override
        public Object getProperty(int index) {
    
            switch(index)
            {
                case 0:
                    return id;
                case 1:
                    return company;
                case 2:
                    return flight_date;
                case 3:
                    return flight_num;
                case 4:
                    return flight_type;
                case 5:
                    return air_port;
                case 6:
                    return status;
            }
    
            return null;
        }
        //needed method
        //here just return the sum of properties in the class
        @Override
        public int getPropertyCount() {
    
            return 7;
        }
    
        //needed method
        @Override
        public void setProperty(int index, Object value) {
    
            switch(index)
            {
                case 0:
                    id = Integer.parseInt(value.toString());
                    break;
                case 1:
                    company = value.toString();
                    break;
                case 2:
                    flight_date = value.toString();
                    break;
                case 3:
                    flight_num = value.toString();
                    break;
                case 4:
                    flight_type = value.toString();
                    break;
                case 5:
                    air_port = value.toString();
                    break;
                case 6:
                    status = value.toString();
                    break;
                default:
                    break;
            }
        }
    
    
    
        //needed method
        @Override
        public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info) {
    
            switch(index)
            {
                case 0:
                    info.type = PropertyInfo.INTEGER_CLASS;
                    info.name = "id";
                    break;
                case 1:
                    info.type = PropertyInfo.STRING_CLASS;
                    info.name = "company";
                    break;
                case 2:
                    info.type = PropertyInfo.STRING_CLASS;
                    info.name = "flight_date";
                    break;
                case 3:
                    info.type = PropertyInfo.STRING_CLASS;
                    info.name = "flight_num";
                    break;
                case 4:
                    info.type = PropertyInfo.STRING_CLASS;
                    info.name = "flight_type";
                    break;
                case 5:
                    info.type = PropertyInfo.STRING_CLASS;
                    info.name = "air_port";
                    break;
                case 6:
                    info.type = PropertyInfo.STRING_CLASS;
                    info.name = "status";
                    break;
                default:break;
            }
        }
    
        //just a method to present our class in String form 
        //not actually needed
        @Override
        public String toString() {
            return "flightPrograms{" +
                    "id=" + id +
                    ", company='" + company + '\'' +
                    ", flight_date='" + flight_date + '\'' +
                    ", flight_num='" + flight_num + '\'' +
                    ", flight_type='" + flight_type + '\'' +
                    ", air_port='" + air_port + '\'' +
                    ", status='" + status + '\'' +
                    '}';
        }
    }
    

    after creating our serialisation class now this is our main activity with a private AsyncTask class that we will use to call our web service and return our objects

    the objects will be returned in a list and we will display one of them in a TextView with the length of the list

    //importing needed classes
    import org.ksoap2.SoapEnvelope;
    import org.ksoap2.SoapFault;
    import org.ksoap2.serialization.PropertyInfo;
    import org.ksoap2.serialization.SoapObject;
    import org.ksoap2.serialization.SoapSerializationEnvelope;
    import org.ksoap2.transport.HttpResponseException;
    import org.ksoap2.transport.HttpTransportSE;
    import org.xmlpull.v1.XmlPullParserException;
    import android.widget.TextView;
    
    public class test_db extends FragmentActivity implements AdapterView.OnItemSelectedListener{
    
    TextView tdate = null;
    
     //variables needed to call our web service
        private final String SOAP_ACTION = "http://yourOwnNAMESPACE.org/getTodayFlights";
    
        private final String OPERATION_NAME = "getTodayFlights";
    
        private final String WSDL_TARGET_NAMESPACE = "http://yourOwnNAMESPACE/";
    
        private final String SOAP_ADDRESS = "http://www.yourServiceHost/WebServicePage.asmx";
    
        //holds the recieved list of objects 
        public programmedFlights[] list;
    
        //property we send to WebMethod
        Long getnet = Long.valueOf(1);
    
    //method for looping into response to get out objects (deserialisation)
        public static programmedFlights[] RetrieveFromSoap(SoapObject response)
            {
                programmedFlights[] flights = new programmedFlights[response.getPropertyCount()];
                for (int i = 0; i < flights.length; i++) {
                    SoapObject obj = (SoapObject)response.getProperty(i);
                    programmedFlights flyer = new programmedFlights();
                    flyer.id = Integer.parseInt(obj.getProperty(0).toString());
                    flyer.company = obj.getProperty(1).toString();
                    flyer.flight_date = obj.getProperty(2).toString();
                    flyer.flight_num = obj.getProperty(3).toString();
                    flyer.flight_type = obj.getProperty(4).toString();
                    flyer.air_port = obj.getProperty(5).toString();
                    flyer.status = obj.getProperty(6).toString();
                    flights[i] = flyer;
                }
                return flights;
            }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_test_db);
    
    //setting our TextView
    tdate = findViewById(R.id.textView6);
    
    //calling the AsyncTask to execute our Wedservice in doinBackground
         final AsyncTask<Object, Void, Object> execute = new mycall().execute((Object) null);
    
       }
    
    private class mycall extends AsyncTask<Object,Void,Object>{
        @Override
        protected Object doInBackground(Object... objects) {
            SoapObject request = new SoapObject(WSDL_TARGET_NAMESPACE, OPERATION_NAME);
    //setting request properties
                PropertyInfo opt = new PropertyInfo();
                opt.setName("option");
                opt.setValue(getnet);
                opt.setType(long.class);
                request.addProperty(opt);
    //creating our envelope
                SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
                envelope.dotNet = true;
                envelope.setOutputSoapObject(request);
    //this part is important for getting our list of objects, never forget to add
    //it to the envelope ******
                envelope.addMapping(WSDL_TARGET_NAMESPACE, "programmedFlights", new programmedFlights().getClass());
                Log.e("request",request.toString());
                HttpTransportSE httpTransport = new HttpTransportSE(SOAP_ADDRESS,100000);
                httpTransport.debug = true;
                try {
    //calling WebMethod
                    httpTransport.call(SOAP_ACTION, envelope);
    //getting WebMethod response 
                    SoapObject response = (SoapObject) envelope.getResponse();
    //Getting our objects from soap response
                    list = RetrieveFromSoap(response);
        //catching errors
                } catch (HttpResponseException e) {
                    e.printStackTrace();
                    errors = errors+"http_response_error "+e.toString();
                    return errors;
                } catch (SoapFault soapFault) {
                    soapFault.printStackTrace();
                    errors = errors+"soapFault_error "+soapFault.toString();
                    return errors;
                } catch (XmlPullParserException e) {
                    e.printStackTrace();
                    errors = errors+"Xml_pull_error "+e.toString();
                    return errors;
                } catch (IOException e) {
                    e.printStackTrace();
                    errors = errors+"I/O_error "+e.toString();
                    return errors;
                }
                return list;
            }
    
    
            @Override
            protected void onPostExecute(Object list) {
                if(list.getClass() == programmedFlights[].class ){
                    programmedFlights[] data = (programmedFlights[]) list;
                    tdate.setText(data.length+" "+data[0].toString());
                    tdate.append(data[1].toString());
                }else if(list.getClass() == String.class){
                    String error = (String) list;
                    tdate.setText(error);
                }
                super.onPostExecute(list);
            }
        }
    
     }
    

    NOTE:Never get your WebMethod response from doinBackground directly, this will result to an empty response and a java.io.IOException always use the onPostExecute to get your response like i did above with this line

    final AsyncTask<Object, Void, Object> execute = new mycall().execute((Object) null);
    

    it in the onPostExecute method that your tell your activity what to do with your response after doinBackground has executed in background and returned the response to onPostExecute

    i hope this will help many guys out there getting stuck on this kind of issue with webservices on android, post a comment if you don't understand something i will be back to briefly explain