This question is reproduced from this question, the code given is a minimalistic example of the problem. In this example, we are consuming the temperature conversion SOAP web service of w3schools, using ksoap2
library:
The problem is that I get a NullPointerException on ed = (EditText) mainActivity.findViewById(R.id.mainActivity_editText1);
in MyTask.
I know I can implement the AsyncTask as an inner class but I read that it can be implemented as a separate class, so why this problem.
This application has a main activity named MainActivity
. The MainActivity
has an onclick-listener method, inside which another activity by the name of SecondActivity
is started.
MainActivity.java:
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void StartSecondActivity(View v) {
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);
}
}
Then there is a separate AsyncTask
class called MyTask
. We provide a constructor of MyTask
for assigning an activity (an instance of MainActivity
here) passed to it to an activity object we are creating inside MyTask
called mainActivity
, the reason for which is to invoke Activity's method findViewById
.
From the SecondActivity
, we create an object of MyTask
using that constructor and passing to it an instance of the main activity in our app; and then call execute on that MyTask
object.
SecondActivity.java:
public class SecondActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
new MyTask(new MainActivity()).execute();
}
}
Now inside MyTask
, I am reading an EditText
from the main activity. Then using it as a celsius value and adding it to the SOAP request to call the web service. Then in the end I am displaying the result from the web service in a TextView
in the SecondActivity
in onPostExecute
.
MyTask.java:
public class MyTask extends AsyncTask<Void, Void, String> {
Activity mainActivity;
EditText ed;
TextView tv;
String searchString;
private static final String TAG = MyTask.class.getSimpleName();
public static final String SOAP_ACTION = "http://www.w3schools.com/webservices/CelsiusToFahrenheit";
public static final String METHOD_NAME ="CelsiusToFahrenheit";
public static final String URL = "http://www.w3schools.com/webservices/tempconvert.asmx";
public static final String NAMESPACE = "http://www.w3schools.com/webservices/";
MyTask(Activity activity) {
mainActivity = activity;
}
@Override
protected void onPreExecute() {
if (mainActivity!=null) {
ed = (EditText) mainActivity.findViewById(R.id.mainActivity_editText1);
} else {
Log.i(TAG, "mainActivity is null.");
}
searchString = ed.getText().toString();
}
@Override
protected String doInBackground(Void... params) {
SoapObject requestSoapObject = new SoapObject(NAMESPACE, METHOD_NAME);
requestSoapObject.addProperty("Celsius", searchString);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(requestSoapObject);
HttpTransportSE htse = new HttpTransportSE(URL);
SoapPrimitive webServiceResultSoapPrimitive = null;
try {
htse.call(SOAP_ACTION, envelope);
webServiceResultSoapPrimitive = (SoapPrimitive) envelope.getResponse();
} catch (HttpResponseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (XmlPullParserException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return webServiceResultSoapPrimitive.toString();
}
@Override
protected void onPostExecute (String webServiceResultString) {
System.out.println("Sysout : " + webServiceResultString);
tv = (TextView) mainActivity.findViewById(R.id.secondActivity_textView1);
tv.setText("Fahrenheit : " + webServiceResultString);
}
}
As Pedro stated in his comment you don't want to try and instantiate an Activity
the way you are.
All you need to do is to pass the value from the first to second Activity
. Then you can pass that value to the constructor of your AsyncTask
.
So, in your onClick()
of the first Activity
you pass it as an Extra
.
public void StartSecondActivity(View v) {
Intent intent = new Intent(this, SecondActivity.class);
EditText et = (EditText) findViewById(R.id.mainActivity_editText1);
String temp = et.getText().toString();
intent.putExtra("temp", temp);
startActivity(intent);
}
then retrieve it and pass it to the task
public class SecondActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// get the String
Intent i = getIntent();
String temp = i.getStringExtra("temp");
setContentView(R.layout.activity_second);
// and pass it here
new MyTask(temp).execute();
}
}
now get it in your task
MyTask(String value) {
searchString= value;
}