Using AsyncTask with passing a value
I have been working on this and I have hit a point where I dont know what to do. What I am trying to do is use one class to download and parse out a file into a string and then send that string to another class to parse out the JSON stuff. All the parts work fine by themselves and I have tested everything separately. I just dont know how to send the value to the Json parses to start the parsing.
So this is my filedownloader class.
public class JsonFileDownloader extends AsyncTask<String, Void, String> {
//used to access the website
String username = "admin";
String password = "admin";
public String ret = "";
@Override
protected String doInBackground(String... params) {
Log.d("Params ", params[0].toString());
readFromFile(params[0]);
return ret;
}
private String readFromFile(String myWebpage) {
HttpURLConnection urlConnection = null;
try {
//Get the url connection
URL url = new URL(myWebpage);
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
}
});
urlConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
if (inputStream != null) {
ret = streamToString(inputStream);
inputStream.close();
Log.d("Final String", ret);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
return ret;
}
}
public static String streamToString(InputStream is) throws IOException {
StringBuilder sb = new StringBuilder();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = rd.readLine()) != null) {
sb.append(line);
}
return sb.toString();
}
public String getJsonData()
{
return ret;
}
}
This works fine I have tested it over and over with no errors. The next is the Json parser which is like this.
public class JSONParser {
JSONObject jsonResponse;
String jsonData;
//Consturctor
public JSONParser()
{
//this.jsonData = jsonData;
// this.OutputData = outPutData;
}
public void parsesData(String promo,
ArrayList<String> pictureHTTP,
ArrayList<String> pathHTTP,
ArrayList<String> labelText) throws IOException {
//Build the Json String
JsonFileDownloader jfd = new JsonFileDownloader();
// jsonData = String.valueOf(jfd.execute(promo));
jfd.execute(promo);
//jfd.getResuts(jsonData);
//jsonData = jfd.ret;
Log.d("JsonData String = " , jsonData);
//Try to parse the data
try
{
Log.d("Jsondata " , jsonData);
//Creaate a new JSONObject ith the name/value mapping from the JSON string
jsonResponse = new JSONObject(jsonData);
//Returns the value mapped by the name if it exists and is a JSONArry
JSONArray jsonMainNode = jsonResponse.optJSONArray("");
//Proccess the JSON node
int lenghtJsonArrar = jsonMainNode.length();
for (int i = 0; i<lenghtJsonArrar; i++)
{
//Get object for each json node
JSONObject jsonChildNode = jsonMainNode.getJSONObject(i);
//Get the node values
//int song_id = Integer.parseInt(jsonChildNode.optString("song_id").toString());
String picture = jsonChildNode.optString("picture").toString();
String pathName = jsonChildNode.optString("path").toString();
String lableName = jsonChildNode.optString("label".toString());
//Debug Testing code
pictureHTTP.add(picture);
pathHTTP.add(pathName);
labelText.add(lableName);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
Now I know where the problem is occurring. When i try to assign a value to the jsonData it never is assigned so it is null and the system fails. I have tried a few things after the jfd.exicute() but I just dont know how to get the value from the final string output into the jsonData. Thank you for any help with this.
Solution 1:
Alright, here is a pretty flexible pattern for the overall usage of using AsyncTask to download web content and getting the results from it back to the UI thread.
Step 1 Define an interface that will act as a message bus between the AsyncTask and where you want the data.
public interface AsyncResponse<T> {
void onResponse(T response);
}
Step 2 Create a generic AsyncTask extension that will take any URL and return the results from it. You basically had this already, but I made some tweaks. Most importantly, allowing the setting of the AsyncResponse callback interface.
public class WebDownloadTask extends AsyncTask<String, Void, String> {
private AsyncResponse<String> callback;
// Optional parameters
private String username;
private String password;
// Make a constuctor to store the parameters
public WebDownloadTask(String username, String password) {
this.username = username;
this.password = password;
}
// Don't forget to call this
public void setCallback(AsyncResponse<String> callback) {
this.callback = callback;
}
@Override
protected String doInBackground(String... params) {
String url = params[0];
return readFromFile(url);
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
if (callback != null) {
callback.onResponse(s);
} else {
Log.w(WebDownloadTask.class.getSimpleName(), "The response was ignored");
}
}
/******* private helper methods *******/
private String streamToString(InputStream is) throws IOException {
StringBuilder sb = new StringBuilder();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = rd.readLine()) != null) {
sb.append(line);
}
return sb.toString();
}
private String readFromFile(String myWebpage) {
String response = null;
HttpURLConnection urlConnection = null;
try {
//Get the url connection
URL url = new URL(myWebpage);
// Unnecessary for general AsyncTask usage
/*
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password.toCharArray());
}
});
*/
urlConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
if (inputStream != null) {
response = streamToString(inputStream);
inputStream.close();
Log.d("Final String", response);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
return response;
}
}
Step 3 Go forth and use that AsyncTask wherever you wish. Here is an example. Note that if you do not use setCallback
, you will be unable to get the data that came from the AsyncTask.
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebDownloadTask task = new WebDownloadTask("username", "password");
task.setCallback(new AsyncResponse<String>() {
@Override
public void onResponse(String response) {
// Handle response here. E.g. parse into a JSON object
// Then put objects into some list, then place into an adapter...
Toast.makeText(getApplicationContext(), response, Toast.LENGTH_SHORT).show();
}
});
// Use any URL, this one returns a list of 10 users in JSON
task.execute("http://jsonplaceholder.typicode.com/users");
}
}