I am a newbie in Android development. Now I am trying to parse. I have got many tutorials for parsing XML. But I would like to know parse XML asynchronously. I have found somewhere, xml can be loaded asynchronously using AsyncTask. Can anybody help me to find it out.
Thanks in advance
Here's a tutorial for using AsyncTask:
http://droidapp.co.uk/?p=177
And one for parsing RSS / XML:
http://droidapp.co.uk/?p=166
You need to call your parse function in doInBackground in the AsyncTask.
public class _StackOverflowActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String yourXmlString = "<put your xml String here>";
ParseXMLTask parseXMLTask = new ParseXMLTask();
parseXMLTask.execute(yourXmlString);
}
class ParseXMLTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... params) {
String yourXml = params[0];
//Parse your xml here
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
//do something after parsing is done
}
}
}
First, you have to extend the class AsyncTask. In my example I named it ParseXMLTask.
AsyncTask requires you to implement one method which is "doInBackground". doInBackground runs in a separate thread, put your code for parsing the xml there.
After the thread finishes, onPostExecute is called. onPostExecute runs in your main thread, you can use this if you wish to perform something after doInBackground finishes
To use ParseXMLTask, you have to instantiate it to an object. Then run the command .execute(). You can pass objects in execute similar to what I have done parseXMLTask.execute(yourXmlString); . You can pass as many variables as you like and be sure to handle them in doInBackground similar to String yourXml = params[0]; . If you have a second variable passed in .execute say... parseXml.execute(yourXmlString, my2ndVariable); , handle it in doInBackground through
String yourXml = params[0];
String the2ndVariable = params[1];
When you call .execute you tell AsyncTask to run whatever code you have placed in doInBackground in a separate thread.
Related
I'm a beginner in Android development. I'm trying to learn multi-threading and working with the internet so I'm doing that by downloading a PDF file from a link through the background thread using AsyncTask. I have confusions about what the best way is to go about it.
Do I create the URI and other necessary connectivity objects in the onCreate or in the doInBackground method of the AsyncTask class?
To download just a single PDF file, what sort of objects do I need to call?
I have checked the documentation but I couldn't really understand it. I'd appreciate a layman's explanation and possibly pseudo-code.
Here is the code I have so far:
public class MainActivity extends AppCompatActivity {
Button downloadPDF;
DownloadingClass downPDF;
private static final String TAG = "omar.asynctaskdemo;";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String urlExample = "https://doc.lagout.org/programmation/Actionscript%20-%20Flash%20-%20Flex%20-%20Air/Flash%20Development%20for%20Android%20Cookbook%20-%20Labrecque%20-%20Packt%20%282011%29/Flash%20Development%20for%20Android%20Cookbook%20-%20Labrecque%20-%20Packt%20%282011%29.pdf");
downloadPDF = findViewById(R.id.download_pdf);
downPDF = new DownloadingClass();
downloadPDF.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
downPDF.execute();
}
});
}
private class DownloadingClass extends AsyncTask<String, Integer, Void>{
#Override
protected Void doInBackground(String... strings) {
return null;
}
}
}
AsyncTask just runs your code in the background thread. To download a pdf file is like any other file.
You will require to use HttpUrlConnection, Create a FileOutputStream and write the inputstream. Refer this
Have the above code executed in doInBackground of AsyncTask class and better pass the url in the constructor and do everything inside the doInBackground method. Since you don't want to block the UI thread.
In a fragment I'm using an 'AsyncTask' to retrieve data from a URL. The main purpose of my code is to access the data (via AsyncTask) and to pass a 'JSONArray' to the fragment.
Problem is, on the fragment side, that when I check the variable that should have the result i get an error saying that the variable is null.
Here is the code:
public class MyFragment extends ListFragment {
//this is the variable that should have the result from the AsyncTask
JSONArray myResult = null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
(...)
//execute the asyncTask
new GetResult().execute(email, password);
(...)
}
//The AsyncTask
private class GetResult extends AsyncTask<String, Void, JSONArray> {
#Override
protected JSONArray doInBackground(String... params) {
(...)
JSONArray jsonArray = (JSONArray) json.get("customer");
return jsonArray;
}
protected void onPostExecute(JSONArray result){
(...)
//this is where I try to pass the data to the fragment
MyFragment.this.myResult = result;
}
}
}
Can someone can help me with that? Thank you in advance.
Are you using the value after postExecute method. You should know that after calling execute, your code on the main thread still runs and only after postExecute has completed, will you have the value.
Try to use this code, and make sure that your jsonstring is not null, because you won't post your complete code and I can't see if myResult variable was changed:
try {
JSONArray json = new JSONArray(jsonstring);
JSONObject json_customer = json.getJSONObject("customer");
return json_customer;
} catch (JSONException e) {
return null
}
For me it looks like problem with deserialization from String data to json's. We are lack of information what exactly data you are parsing. Consider using for this some more advanced json processing library lika Gson or Jackson. Usually its easier with them.
It sounds like you are trying to read from myResult variable before the AsyncTask finishes retrieving it. To make sure it populates properly, put this into your onPostExecute function, after this line MyFragment.this.myResult = result;:
Log.i("my result value is: ", MyFragment.this.myResult.toString())
It should print it out in the LogCat if you are retrieving it correctly, and you should be able to access that variable after that.
On a separate note, consider using Volley or Retrofit or another networking plugin to make your life easier.
Maybe you can use a clear way to transfer data back from the task to the fragment.
1) define an interface as the event listener to be called in the AsyncTask, like
public interface TaskEventListener(){
public void onTaskStarted(int messageId);
public void onTaskStopped(int messageId, int resultCode);
public void onDataReady(Object parameter);
}
2) let the fragment implement this EventListener, put the processing code in the onDataReady() function.
3) pass the fragment instance as the EventListener instance.
4) in the class extended from the AsyncTask, call the onTaskStarted() in the onPreExecute() function, call the onDataReady() and onTaskStopped() in the onPostExecute() function, and call the onTaskStopped() only in the onCancelled() function.
5) please use the weak references in the background task class to prevent crashing for referring the invalid UI component.
This question already has answers here:
AsyncTask Android example
(21 answers)
Closed 9 years ago.
I have a splash screen with a TextView to displays what the app is doing such as "Updating Library"... "Updating Shipping"... etc. I'm using AsyncTask to updated my database via an API.
I'm passing the update text to the AsyncTask. I need to change the text in TextView statusMessage. I'm attempting to do this:
public class JSONParser extends AsyncTask<String, String, JSONObject> {
static InputStream is = null;
static JSONObject json = null;
static String outPut = "";
TextView statusMessage;
#Override
protected void onPreExecute() {
statusMessage = (TextView) findViewById(R.id.statusMessage);
}
...
My plan is to change the text in the doInBackground method but findViewById isn't accessible in AsyncTask. I think I need to use setContentView to allow findViewById to work but I'm not sure how.
My java file is SplashScreen.java and my xml is activity_splash_screen.xml
----- EDIT -----
For more info I have three pieces talking to each other:
SplashScreen.java -> calls to method in baseActivity.java -> method sends data to JSONParser.java -> sends parsed JSON from the API to baseActivity.java to update database
Per suggestions below I've declared
statusMessage = (TextView) findViewById(R.id.statusMessage);
In baseActivity.java's onCreate since it's the file calling the AsyncTask.
In JSONParser.java I've done this, now:
public class JSONParser extends AsyncTask<String, String, JSONObject> {
static InputStream is = null;
static JSONObject json = null;
static String outPut = "";
TextView statusMessage;
#Override
protected JSONObject doInBackground(String... params) {
// TODO Auto-generated method stub
...
}
protected void onProgressUpdate() {
statusMessage.setText("testing");
}
protected void onPostExecute(JSONObject result) {
}
}
I'm just using "testing" there for testing purposes.
My plan is to change the text in the doInBackground
Bad plan! You can't update the UI from a background Thread. You will need to do this in either onPostExecute() or onProgressUpdate().
but findViewById isn't accessible in AsyncTask.
If this is an inner class of your Activity then initialize the View in the Activity then update it in your task as described above.
If it is its own file then you will want to use an interface and have a callback to the Acitivty in onPostExecute(), onPreExecute(), or onProgressUpdate(). You can see an example of that in this SO answer.
I think I need to use setContentView to allow findViewById
Definitely! But as stated above, do this before the task such as in onCreate() of your Activity.
Edit
onProgressUpdate() takes a param but your onProgressUpdate() doesn't so it isn't the same method. That's why it complained when you had #Override which is the point of the annotation. It complains and you know you are suppose to be overriding a method so you know something is wrong with it.
Change it to
protected void onProgressUpdate(Void...values) {
statusMessage.setText("testing");
}
onProgressUpdate() link
http://developer.android.com/reference/android/os/AsyncTask.html#onProgressUpdate(Progress...)
You should use onProgressUpdate, that method has acces to the ui thread.
public class yourAsync extends AsyncTask<> {
#Override
protected void onProgressUpdate() {
textView.setText();
}
}
put something like this in your activity
Handler statusUpdateHandeler = new Handler()........
In your thread, call the handler (send it a message)
MainActivity.statusUpdateHandler.sendEmptyMessage(1);
In you actual handler code, set the status message.
I think I need to use setContentView to allow findViewById to work but I'm not sure how.
Yes. You need to use setContentView(R.layout.activity_splash_screen) in onCreate.
You can initialize your view in onCreate make asynctask an inner class of activity and update ui in onPreExecute.
TextView statusMessage;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
statusMessage = (TextView) findViewById(R.id.statusMessage);
}
Also you can use a progressdialog and display the message. I think using progressdialog would be a better choice than textview. You can publish progress in doInbackground and update progress dialog in onProgressUpdate()
http://developer.android.com/reference/android/os/AsyncTask.html
I have set up an async task that will get a list of countries from a wsdl and from the result i create a bunch of country objects and add the objects to an arraylist in the country class file.
I want to be able to run this async task that will populate the array list then from another view be able to call specific indexes from the array list based on what the user has selected.
i have tried creating a class that extends AsyncTask and i have inserted the same code from the gingerbread version of the app i created which worked fine because network actions could be ran from the main thread
The type getWSDL2 must implement the inherited abstract method AsyncTask.doInBackground(Object...)
i dont have any objects to pass to this i all variables and stuff to get the wsdl data is within the async task and all the data i need from it is assigned to the arraylist from within the async task.
public class getWSDL2 extends AsyncTask {
protected void doInBackground()
{
........
}
Pass Void... as a parameter for doInBackground
protected void doInBackground(Void... params)
{
........
}
The way I understand your question you're not sure how to implement the AsyncTask because you have no need to pass values into it. All of the variables and data you need are included within the code that will execute the transaction with your server to download whatever it is you intend to display.
public class getWSDL2 extends AsyncTask {
protected Void doInBackground(Void... params) {
//All I/O code here
}
protected Void onPostExecute(){
//Anything that needs to run on the UI thread here
}
}
The general structure of the AsyncTask is listed above. The doInBackground method must contain any I/O functions while any thing you do tha touches a view, i.e. displaying the results of you're query as saved in a array list, must be called from onPostExecute, which runs on the UI thread.
From what I gather the solution is simple. Put all the code that is required for your server transaction within the doInBackground method. If you need to display the results of that transaction in a view just add a return statment to doInBackground and include the type of object/variable you will return in the varargs listed for the AsyncTask. For example if you were going to display the result of an ArrayList generated in your doInBackground method
public class getWSDL2 extends AsyncTask {
protected ArrayList<String> doInBackground(Void... params) {
//All I/O code here
return nameOfArrayListYouBuild
}
protected Void onPostExecute(ArrayList<String> whatever){
//use ArraList whatever to display your stuff
}
}
In the alternative if you don't need to display anything or run any functions on the UI thread then don't use the onPostExecute method at all.
public class getWSDL2 extends AsyncTask {
protected Void doInBackground(Void... params) {
//All I/O code here
return null
}
}
You can structure you're task so that it just uses doInBackground
Now i am doing an android application.In that application I am using asynchtask class to parse json data and i have to set that values in to ui.My program is like this.
class Activity
{
textview tv;
oncreate()
{
setcontentview(layout);
tv=(textview)findviewbyid(id);
call to pageload()
}
class PageLoad extends AsyncTask<String, Void, Boolean>
{
doInBackground()
{
json parsing
tv.setText(data);
}
}
}
But I couldn't set the value from pageload class.Please help me friends.
You need to understand that doInBackground() runs on a different thread to the UI, therefore you cannot access the UI here. AsyncTask has two other methods:
onPreExecute() - before doInBackground() is run
onPostExecute() - after doInBackground() is run, can receive the result of the work done by doInBackground()
You need to pass the result of doInBackground() to onPostExecute() where you can then set the TextView's text.
I would suggest you read Google's article on how to use the Asynctask which can be found at http://developer.android.com/resources/articles/painless-threading.html and look at the class AsyncTask.
Example Code
private class MyAsynctask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
//do something heavy or resource intensive
String data = resultOfSomeWork();
return data;
}
protected void onPostExecute(String result) {
myTextView.setText(result);
}
}
you can also use onProgressUpdate() of AsyncTask
You can call it using publishProgress(values) from your doInBackGround().
And set Text in your textbox in the onProgressUpdate().
You can't use UI thread in doInBack..() of AsyncTask (As its only worker thread). Use onPostExecute() for it (If you want to make any ui related changes do in onPreExecute() or onPostExecuted()).
Just go through Android-AsyncTask and look at how it works.
You can't update UI from AsyncTask thread, it most be done on the main thread. You can use handler for this.