How to use the ksoap2 library

0

I have the following situation, I have a PHP server:

class Teste {
    function obtemStatus(){ 
        return 'ok'; 
    }
}

$server = new SoapServer(null, array('uri'=>'http://test-uri/'));
$server->setClass('Teste');
$server->handle();

And a PHP client too:

$options = array(
    'location'  => 'http://localhost/android/server/index.php',
    'uri'       => 'http://test-uri/'
);
$client = new SoapClient(null, $options);
echo $client->obtemStatus();

This is working perfectly, but now I want to use this service by Anndroid, I have the following code:

private String NAMESPACE = "urn://http://localhost";
private String METHOD_NAME = "obtemStatus";
private String URL = "localhost/android/client/index.php";
private String SOAP_ACTION = "localhost/android/client/index.php/obtemStatus";

// observação: antes do localhost está o http:// mas tive que tirar para postar aqui
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);

SoapObject soap = new SoapObject(NAMESPACE, METHOD_NAME);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(soap);

HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);

try {
    androidHttpTransport.call(SOAP_ACTION, envelope);
} catch (IOException e) {
    e.printStackTrace();
} catch (XmlPullParserException e) {
    e.printStackTrace();
}

}

You are giving the following error:

09-22 20:59:27.501    9637-9637/com.anderson.soap D/HyLog﹕ I : /data/font/config/dfactpre.dat, No such file or directory (2)
09-22 20:59:27.661    9637-9637/com.anderson.soap D/AndroidRuntime﹕ Shutting down VM
09-22 20:59:27.661    9637-9637/com.anderson.soap E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.anderson.soap, PID: 9637
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.anderson.soap/com.anderson.soap.MyActivity}: android.os.NetworkOnMainThreadException
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2202)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2252)
            at android.app.ActivityThread.access$800(ActivityThread.java:139)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1200)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5103)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:606)
     Caused by: android.os.NetworkOnMainThreadException
            at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1148)
            at java.net.InetAddress.lookupHostByName(InetAddress.java:405)
            at java.net.InetAddress.getAllByNameImpl(InetAddress.java:251)
            at java.net.InetAddress.getAllByName(InetAddress.java:229)
            at com.android.okhttp.internal.Dns$1.getAllByName(Dns.java:28)
            at com.android.okhttp.internal.http.RouteSelector.resetNextInetSocketAddress(RouteSelector.java:216)
            at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:122)
            at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:292)
            at com.android.okhttp.internal.http.HttpEngine.sendSocketRequest(HttpEngine.java:255)
            at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:206)
            at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:345)
            at com.android.okhttp.internal.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:89)
            at com.android.okhttp.internal.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:197)
            at org.ksoap2.transport.ServiceConnectionSE.openOutputStream(ServiceConnectionSE.java:120)
            at org.ksoap2.transport.HttpTransportSE.call(HttpTransportSE.java:176)
            at org.ksoap2.transport.HttpTransportSE.call(HttpTransportSE.java:114)
            at com.anderson.soap.MyActivity.onCreate(MyActivity.java:39)
            at android.app.Activity.performCreate(Activity.java:5275)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2166)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2252)
            at android.app.ActivityThread.access$800(ActivityThread.java:139)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1200)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5103)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:606)

Does anyone know what it can be?

    
asked by anonymous 23.09.2014 / 02:07

1 answer

1

Anderson, this error you gave is not directly with your connection code. This error is due to the location where you are running an internet connection, in MainThread .

It is not recommended to perform network operations or I / O (some are allowed, eg SharedPreferences) usually in MainThread .

The MainThread is responsible for many essential operations (View drawing, event handling, creation and destruction of Activities , Fragments and other entities, saving state operations of Activity , Fragment and Views hierarchy), so it is not good to break MainThread .

To learn more about Main Thread , take a look at A journey on the Android Main Thread

Often it is because of too much slow processing in the MainThread you see that Dialog of ANR .

Forthisitisrecommendedthatyoustarta AsyncTask to execute network processes and < in> I / O .

AsyncTask abstracts the use of Threads and communication with MainThread . In the background your code will run in a Thread separated (method doInBackground ), but at some moments ( onPreExecute and onPostExecute ) the code will run in Main Thread .

You can also publish a progress, to update the interface. For this, use the publishProgress method within doInBackground . The onProgressUpdate method will be executed in MainThread .

In addition, AsyncTask is highly parameterized: AsyncTask<Params, Progress, Result> , so you can specify a type for each value that is used in it. If it is a AsyncTask just for processing in Background , the most common is to use AsyncTask<Void, Void, Void> .

For more details, take a look at Keeping Your App Responsive and AsyncTask .

Using AsyncTask , your code would look like:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my);

    new AsyncTask<Void, Void, Void>() {
        @Override
        public Void doInBackground(Void... params) {
            // Todo codigo executado nesse metodo sera feito em um Thread
            // Fora da MainThread.
            // Nao atualize elementos de interface (Views) aqui!

            SoapObject soap = new SoapObject(NAMESPACE, METHOD_NAME);
            SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
            envelope.dotNet = true;
            envelope.setOutputSoapObject(soap);

            HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);

            try {
                androidHttpTransport.call(SOAP_ACTION, envelope);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (XmlPullParserException e) {
                e.printStackTrace();
            }

            // Nao ha nenhum resultado no processamento, nao retorno nada.
            // Voce pode retornar algo se achar necessario
            return null;
        }

        @Override
        public void onPostExecute(Void result) {
            // Esse metodo é executado na MainThread!
            // O "result" é o retorno do metodo doInBackground
            // Atualize elementos de interface aqui.
        }
    }.execute();
}

This is the basics of AsyncTask , for more details I recommend seeing some of the Android tutorials, specifically the Connecting to the Network .

When you have more time, take a look at Loaders , they do a processing in a Thread separated but are managed by the Activity lifecycle automatically, greatly simplifying the work.

    
23.09.2014 / 02:59