How to have a web service class to call in Async way? - android

I have a web service class to call my web methods. but this have to be called in AsyncTask class. Currently I have an AsyncTask class in all of my activities to call my web service methods. is it possible to mix them (Web service class And AsyncTask) to have a web service class which takes the name of web method and return the result after executing?
This is my web service class:
package ClassLibrary;
public class WebService {
private String namespace="";
private String url="";
public WebService(String namespace,String url) {
super();
this.namespace = namespace;
this.url = url;
}
public String CallMethod(String methodName,PropertyInfo pi) {
String result = "default";
SoapObject request = new SoapObject(namespace, methodName);
request.addProperty(pi);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(url);
try {
androidHttpTransport.call(namespace+methodName, envelope);
SoapPrimitive response = (SoapPrimitive) envelope.getResponse();
result= response.toString();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
This is how I'm accessing in AsyncTask:
private class AsyncCallWS extends AsyncTask<String, Void, Void> {
private ProgressDialog dialog;
private Activity activity;
public String wsOutput="";
public String methodName="";
private WebService ws;
public AsyncCallWS(Activity activity,String methodName) {
this.activity = activity;
this.dialog = new ProgressDialog(activity);
this.methodName = methodName;
}
#Override
protected Void doInBackground(String... params) {
ws = new WebService(PublicVariable.NAMESPACE, PublicVariable.URL);
PropertyInfo pi= new PropertyInfo();
pi.setName("UserID");
pi.setValue("1");
pi.setType(String.class);
wsOutput=ws.CallMethod("GetPersonalInfo", pi);
return null;
}
#Override
protected void onPostExecute(Void result) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
if (methodName == "GetPersonalInfo") {
Log.d("Ehsan","OUTPUT IS:"+ wsOutput);
}
}
}

I'd suggest to add (static?) methods to your WebService class for each webservice method and pass in a listener from the calling Activity which is then called in onPostExecute.
You can then call WebService.doThings(thingsListener) from your Activity, execute the AsyncTask with the according method and react in the provided listener to the result...

When I faced same problem, I did:
implemented all api calls as static methods. They are called in synchronous manner by
an IntentService descendant, who calls api and then
IntentService broadcasts results as intents. Interested activities subscribe for events from this IntentService
To make activities independent of network operations, consider using a db,a ContentProvider or some other storage mechanism, so may take all benefits of LoaderManager etc. This approach will cost you some time, but architecture will benefit from it greatly.

Related

Get data from webservice and bind to autotextview without freezing UI

I am stuck with this problem. Any help is appreciated.
In onCreate method of MainActivity, I call list of ingredients from a web service using soap and bind them to autotextview. Unfortunately, list of ingredient variable always null before binding since it couldn't retrieve faster than processor jumps to next line.
Could anybody propose me a method to overcome this problem without freezing UI at startup time?
---- Edit----
Inside Main Activity onCreate
globalVars = (MyApplication) this.getApplicationContext();//requested data will be stored in global variables.
populateSpinners(); // get spinner data using CallSoap
getIngredients(); // get ingredient names for autotextview using CallSoap
ArrayAdapter adapter = new ArrayAdapter(getApplicationContext(),android.R.layout.simple_spinner_item,globalVars.ingredientTitles);
// globalVars.ingredientTitles be initialized in onPostExecute of Caller class.
AutoCompleteTextView autoCompleteTextView = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView);
autoCompleteTextView.setAdapter(adapter);
here is populatespinners (in the same way it executes getIngredients)
private void populateSpinners(){
try
{
Caller c=new Caller(this.getApplicationContext());
c.functionName = "getDropDownData";
c.vil = null;
c.execute();
}catch(Exception ex) {
Log.e(TAG, "populateSpinners: "+ex.getMessage(),ex );
}
}
here is caller which extends AsyncTask
public CallSoap cs;
public List<variableInfo> vil;
public String functionName;
protected String doInBackground(String... params) {
String response;
try{
cs=new CallSoap();
String resp=cs.CallService(functionName,vil);
response=resp;
}catch(Exception ex)
{
response=ex.toString();
}
return response;
}
protected void onPostExecute(String result) {
progressDialog.dismiss();
if(functionName == "getDropDownData")
{
//here initializes globalVars
}
}
here is CallSoap Class- service call
public String CallService(String functionName, List<variableInfo> variables) {
OPERATION_NAME = functionName;
SOAP_ADDRESS = HOST_ADDRESS + ASMX_NAME;
WSDL_TARGET_NAMESPACE = "http://bulyapye.com/";
SOAP_ACTION = WSDL_TARGET_NAMESPACE + functionName;
SoapObject request = new SoapObject(WSDL_TARGET_NAMESPACE, OPERATION_NAME);
if (variables != null) {
for (Integer i = 0; i < variables.size(); i++) {
PropertyInfo pi = new PropertyInfo();
pi.setName(variables.get(i).name);
pi.setValue(toObject(variables.get(i).type, variables.get(i).value));
pi.setType(variables.get(i).type);
request.addProperty(pi);
}
}
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) {
response = exception.toString();
}
return response.toString();
}
Make an asynchronous function to call the webservice (using listener or LiveData). Here a sample using listener:
interface SoapGetterListener {
public success(String data);
public error(Exception e);
}
public class MainActivity extends Activity implements SoapGetterListener {
...
globalVars = (MyApplication) this.getApplicationContext();//requested data will be stored in global variables.
populateSpinners(this); // get spinner data using CallSoap
getIngredients(this); // get ingredient names for autotextview using CallSoap
...
public success(String data) {
ArrayAdapter adapter = new ArrayAdapter(getApplicationContext(),android.R.layout.simple_spinner_item,data);
AutoCompleteTextView autoCompleteTextView = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView);
autoCompleteTextView.setAdapter(adapter);
}
...
}
// Pass SoapGetterListener to CallSoap constructor so you can
// use in onPostExecute()
protected void onPostExecute(String result) {
progressDialog.dismiss();
if(functionName == "getDropDownData")
listener.success(result)
}

Return an Array of Strings from an ASP.NET Web Service to an Android client using SOAP

I want to return an array of strings to my Android client and populate a ListView.
I am using the SOAP library (org.ksoap2.*) to invoke an ASP.NET web service.
Here is the code for the web service:
1. ASP Web Service
Imports ...
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports ...
<WebService(Namespace:="...")>_
<WebService(ConformsTo:=...)> _
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Public Class EnquiryWS
Inherits System.Web.Services.WebService
' Web method
<WebMethod()> _
Public Function GetList() As String()
'Hardcoded list
Return New String() { "item1", "item2", "item3" }
End Function
I've tested the web service by accessing the asmx, there are no runtime errors.
I've also tested it with just a simple string, the web service returned the string to Android. Like this:
' Web method
<WebMethod()> _
Public Function GetString() As String
Return "My string."
End Function
2. Android Activity
Secondly, here is my Android code that is invoking the ASP.NET web service.
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
public class MainActivity extends AppCompatActivity {
private ArrayList<String> list;
private ListView listview;
private ArrayAdapter<String> adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
//...
new GetPersonList().execute("AsyncTask String");
//...
}
// Inner AsyncTask class
private class GetPersonList extends AsyncTask<String, Integer,String> {
private static final String SOAP_ACTION = "https://myNamespace/GetList";
private static final String METHOD_NAME = "GetList";
private static final String NAMESPACE = "https://myNamespace/";
private static final String URL =
"https://myIISsite/myASMXfile.asmx";
#Override
protected void onPreExecute() {
super.onPreExecute();
// onPreExecute stuff
}
#Override
protected String doInBackground(String... arg) {
String result = null;
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
//Create envelope
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
//Required for .net
envelope.dotNet = true;
//Set output SOAP object
envelope.setOutputSoapObject(request);
//Create HTTP call object
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
try {
//Invoke web service
androidHttpTransport.call(SOAP_ACTION, envelope);
//Get the response
SoapPrimitive response = (SoapPrimitive) envelope.getResponse();
//Assign it to response to a static variable
result = response.toString();
} catch (Exception e) {
result = "error " + e.getMessage();
}
return result;
}
#Override
protected void onPostExecute(String result) {
System.out.println("Returned SOAP XML: " + result);
MyFunction(result);
}
}
}
MyFunction is a method that I created to do some additional work.
3. MyFunction
Here is MyFunction method code:
public void MyFunction(String s) {
// Add Webservice response to list
list.add(s);
// Set adapter
adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item1, list);
listview.setAdapter(adapter);
}
The argument I pass to MyFunction is the SOAP response, I then add it to the list and set the adapter.
Okay, so the web service is returning an array of strings, but the overriden onPostExecute method is working with one string, if I declare the onPostExecute parameter as a Collection, it is obviously not overriding anymore.
This is the error that I am getting in logcat:
Return SOAP XML: error expected: START_TAG {http://schemas.xmlsoap.org/soap/envelope/}Envelope (position:START_TAG <html>#1:7 in java.io.InputStreamReader#4182d238)
Could anyone please advise?
I have found a solution. I am casting the response as a SoapObject and not as a SoapPrimitive, the reason for that is because a SoapPrimitive is for primitive data types, SoapObject supports composite data types. Therefore, I am casting my array as a SoapObject and not as a SoapPrimitive anymore.
I have removed the MyFunction() method, because I am setting the adapter in the onPostExecute() method by override run(). And finally, I have added a ProgressDialog, I am showing the ProgressDialog in the onPreExecute() method while it's processing, and then I am invoking dismiss() in the onPostExecute() method.
private class GetPersonList extends AsyncTask<Void, Void, String> {
private static final String SOAP_ACTION = "http://myNamespace/myMethod";
private static final String METHOD_NAME = "myMethod";
private static final String NAMESPACE = "http://myNamespace/";
private static final String URL =
"http://myURL/myAsmxFile.asmx";
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog= ProgressDialog.show(MainActivity.this,
"Wait",
"Retrieving data",
true
);
}
#Override
protected String doInBackground(Void... params) {
String finalResult = null;
//Create request object
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
//Create envelope to which we add our request object
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
//Required for .net
envelope.dotNet = true;
//Add the request object to the envelope
envelope.setOutputSoapObject(request);
//Create HTTP call object
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
try {
//Invoke web service
androidHttpTransport.call(SOAP_ACTION, envelope);
// Get the response
// Cast as SoapObject and not SoapPrimitive
SoapObject response = (SoapObject) envelope.getResponse();
//Assign it to response to a static variable
finalResult = response.toString();
// Now loop through the response (loop through the properties)
// and add them to the list
for(int i = 0; i < response.getPropertyCount(); i++) {
list.add(response.getProperty(i).toString());
}
} catch (Exception e) {
System.out.println("######## ERROR " + e.getMessage());
}
return finalResult;
}
#Override
protected void onPostExecute(String str) {
progressDialog.dismiss();
System.out.println("Returned SOAP XML: " + str);
runOnUiThread(new Runnable() {
#Override
public void run() {
// Set adapter
adapter = new ArrayAdapter<String>(MainActivity.this, R.layout.list_item, R.id.product_name, list);
listview.setAdapter(adapter);
}
});
}
}
I have heard that there is another way of doing this using Gson/Json, I will post that once I have figured it out.
Cheerz

Calling webservice on Android

Tried using Async but got can't handler even there is no toast in it,
also tried call calling method runUIThread but no luck ,
Async method works but it also gets run time exception
when i use Async method data gets on the Textview too late (5-10 mins) , but when i use it in debuggers it gets instantly ,
below webservice is test using wizdl application and response is instant
i'm confused please help
private final String NAMESPACE = "http://????????.com/EventGetter/";
private final String URL = "http://?????????.com/EventGetter.asmx";
private final String SOAP_ACTION = "http://????????.com/EventGetter/GetTimeTable";
private final String METHOD_NAME = "GetTimeTable";
private class TPaccessData extends AsyncTask<String, Void, Void>{
#Override
protected Void doInBackground(String... params) {
GetData();
return null;
}
#Override
protected void onPostExecute(Void result) {
Log.i(LogStr, "onPostExecute");
}
#Override
protected void onPreExecute() {
GetData();
Log.i(LogStr, "onPreExecute");
}
#Override
protected void onProgressUpdate(Void... values) {
Log.i(LogStr, "onProgressUpdate");
}
}
public void GetData(){
//Create request
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
//set properties aka param
request.addProperty("stream","where ttBatch = 'F.Y.J.C'");
//Create envelope
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
envelope.dotNet = true;
//Set output SOAP object
envelope.setOutputSoapObject(request);
//Create HTTP call object
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
try {
androidHttpTransport.debug = true;
//Invole web service
androidHttpTransport.call(SOAP_ACTION, envelope);
//Get the response
SoapPrimitive response = (SoapPrimitive) envelope.getResponse();
//Assign it to Text static variable
text.setText(response.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
also tried calling get data in oncreate method
NotifyList.this.runOnUiThread(new Runnable() {
#Override
public void run() {
GetData();
// TPaccessData task = new TPaccessData();
// task.execute();
}
});
Remove youe GetData() method from onPreExecute()
and call this line inside onPost
text.setText(response.toString());

How can I make a ksoap2 call in async task?

I am a newbie on android development. I am trying to develop an application which will connect with .net webservice in order to retrieve data. I would like to make the ksoap2 call with AsyncTask. How I call it asyncronus with asynctask?
My SoapCall class is
public class SoapCall {
public final static String SOAP_ACTION = "http://www.alpha.net.com/ExecuteEBSCommand";
public final static String OPERATION_NAME = "ExecuteEBSCommand";
public final static String NAMESPACE = "http://www.alpha.net.com";
public final static String URL = "http://192.168.2.100/Ebs2Alpha/Service.asmx";
public String connection(String Command, String CommandParameters) throws Throwable, Throwable {
String response = null;
SoapObject Request = new SoapObject(NAMESPACE, OPERATION_NAME);
Request.addProperty("strCommand", Command);
Request.addProperty("strCommandParameters", CommandParameters);
SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
soapEnvelope.dotNet = true;
soapEnvelope.setOutputSoapObject(Request);
// Needed to make the internet call
// Allow for debugging - needed to output the request
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.debug = true;
// this is the actual part that will call the webservice
androidHttpTransport.call(SOAP_ACTION, soapEnvelope);
// Get the SoapResult from the envelope body.
SoapObject result = (SoapObject) soapEnvelope.bodyIn;
response = result.getProperty(0).toString();
return response;
}
}
So far I am getting the response by calling the connection method in main activity with
SoapCall call1= new SoapCall();
call1.connection("get_clients", "%");
Using AsyncTask is straightforward. Here is an example.
public class MyTask extends AsyncTask<String, Integer, String>{
#Override
protected String doInBackground(String... params) {
String response = null;
SoapObject Request = new SoapObject(NAMESPACE, OPERATION_NAME);
Request.addProperty("strCommand", params[0]);
Request.addProperty("strCommandParameters", params[1]);
SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
soapEnvelope.dotNet = true;
soapEnvelope.setOutputSoapObject(Request);
// Needed to make the internet call
// Allow for debugging - needed to output the request
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.debug = true;
// this is the actual part that will call the webservice
androidHttpTransport.call(SOAP_ACTION, soapEnvelope);
// Get the SoapResult from the envelope body.
SoapObject result = (SoapObject) soapEnvelope.bodyIn;
response = result.getProperty(0).toString();
return response;
}
}
And the call to the task with parameters.
MyTask myTask = new MyTask();
myTask.execute(new String[] {Command, CommandParameters});
Hope it will help.
I'd suggest you use the AsyncTaskLoader which for my taste is easier than the AsyncTask.
Have a look here, the example is very extensive and looks intimidating at first, you'll probably find much simpler ones. The idea is that your Activity implements LoaderCallbacks for the creation of the loader and a method that is being called when the loader has finished. You 'start' a loader via the LoaderManager.
The AsynctaskLoader is a class that extends AsyncTaskLoader and does the asynchronous stuff.
I'll give you a simple example:
This is the AsyncTaskLoader:
public class StartupLoader extends AsyncTaskLoader<Boolean> {
Context context;
public StartupLoader(Context context) {
super(context);
this.context = context;
forceLoad();
}
#Override
public Boolean loadInBackground() {
// DO STUFF!
return true;
}
#Override
protected void onStopLoading() {
}
#Override
public void onCanceled(Boolean data) {
super.onCanceled(data);
}
#Override
protected void onReset() {
super.onReset();
}
}
This is what you have in the Activity that will start the loader, it is an inner class:
public class StartupCallback implements
LoaderManager.LoaderCallbacks<Boolean> {
#Override
public void onLoadFinished(Loader<Boolean> loader, Boolean succ) {
// Here you get your results back
}
#Override
public Loader<Boolean> onCreateLoader(int id, Bundle args) {
return new StartupLoader(getApplicationContext());
}
#Override
public void onLoaderReset(Loader<Boolean> loader) {
}
}
And this is how you start the loader from whereever you want (within that Activity):
StartupCallback startupCallback = new StartupCallback();
getSupportLoaderManager().initLoader(0, null, startupCallback);
where 0 is an ID that you give the loader, null is a Bundle of arguments.
Good luck :)

Showing ProgressDialog in AsyncTask only for specific parameters

I'm implementing an AsyncTask, that calls a WCF service methods in the doInBackground method.
the WCF method name is a parameter for the doInBackground method.
I want the progress dialog to show only for specific methods name sent to doInBackground.
My porgressdialog setting are set in onPreExecute methods.
Any way to make progressdialog appear for a specific doInBackground parameter (wcf method name)
public class WCFHelper extends AsyncTask<Object, Void, String[]>{
private static final String NAMESPACE = "http://tempuri.org/";
private static final String URL = "http://url";
final ProgressDialog pd;
public Context ctx;
public WCFHelper(Context _ctx)
{ this.ctx = _ctx;
pd = new ProgressDialog(_ctx);
}
#Override
protected void onPreExecute() {
pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pd.setMessage("login...");
pd.setIndeterminate(true);
pd.setCancelable(false);
pd.show();
}
#Override
protected String[] doInBackground(Object... params) {
String WCFmethod = (String)params[0];
Map<String,Object> parameterArgs = (Map<String,Object>)params[1];
Boolean isArr = (Boolean)params[2];
String [] Fail = {"Fail"};
String SOAP_ACTION = "http://tempuri.org/IService1/"+WCFmethod;
String METHOD_NAME = WCFmethod;
try {
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
for(Map.Entry<String,Object> entry: parameterArgs.entrySet())
request.addProperty(entry.getKey().toString(), entry.getValue().toString());
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(SOAP_ACTION, envelope);
if(!isArr)
{
SoapPrimitive result = (SoapPrimitive)envelope.getResponse();
String[] toReturn = new String[1];
toReturn[0] = result.toString();
return toReturn;
}
else{
envelope.implicitTypes = true ;
SoapObject listDataSet = (SoapObject) envelope.bodyIn;
int numOfStrings = ((SoapObject)listDataSet.getProperty(0)).getPropertyCount();
String[] toReturn = new String[numOfStrings];
for ( int i = 0 ; i <numOfStrings; i++) {
toReturn[i] = ((SoapObject)listDataSet.getProperty(0)).getProperty(i).toString();
}
return toReturn;
}
}
catch (Exception e) {
return Fail;
}
}
protected void onPostExecute(String res) {
// TODO: check this.exception
// TODO: do something with the feed
if(this.pd.isShowing())
pd.dismiss();
}
As you can see one of the params for doInBackground is WCF method name.
I want the progressdialog to show only to specific WCF methods (received as parameter)
Send parameters also during instantiating the WCHelper object.
Keep a variable in the WCFHelper class.
public class WCFHelper extends AsyncTask<Object, Void, String[]>{
int val;
public WCHelper(int param) //constructor
{
super();
val = param; //now you can use this val in onPreExecute
}
...
}
Send the same parameter you wanted to send to onPreExecute(). For example,
WCHelper task = new WCHelper(param); // this sends value to constructor
task.execute(param); //this sends value to doInBackground
You can create your own custom constructor of the AsyncTask to transfer necessary parameter for handling the progress dialog.
private class MyTask extends AsyncTask<Void, Void, Void> {
public MyTask(boolean showProgress){
....
}
....
}

Categories

Resources