How to get XML using AsyncTask and Timer?

In order to get XML data from a server repeatedly, I'm attempting to use AsyncTask and Timer as per Mark Murphy's suggestion.

I get the following error:

01-07 16:11:26.705: ERROR/AndroidRuntime(729): 
Caused by: java.lang.RuntimeException: 
Can't create handler inside thread that has not 
called Looper.prepare()

I'm using SDK 1.5 with Eclipse on Windows.

I've looked in documentation, on StackOverflow and in the Android Developers group, but I'm not clear what's causing the error or how to fix it.

I can get the data once -- i.e. without Async and Timer -- and parse it via SAX without problems.

Full app code below.

Please excuse any naive errors: I'm quite new to Android.

package com.foo.bar.myactivity;

import java.net.URL;
import java.util.Timer;
import java.util.TimerTask;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;

public class MyActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        Timer timer;
        timer = new Timer();
        timer.schedule(new MyTimerTask(), 0, 1000); 
    }

    public class MyAsyncTask extends AsyncTask<String, Integer, MyData> {
        protected MyData doInBackground(String... string) {
            MyData myData = new MyData();
            try {
                URL url = new URL("http://www.example.com/my.xml");
                SAXParserFactory spf = SAXParserFactory.newInstance();
                SAXParser sp = spf.newSAXParser();

                XMLReader xr = sp.getXMLReader();

                MyHandler myHandler = new MyHandler();
                xr.setContentHandler(myHandler);

                System.setProperty("http.proxyHost", "www-cache.example.com");
                System.setProperty("http.proxyPort", "80");

                xr.parse(new InputSource(url.openStream()));

                myData = myHandler.getParsedData();
                return myData;

            } catch (Exception e) {
                Log.e(">>>>>>>>>>>> Error getting myData: ", e.getMessage(), e);
                return myData;
            }

        }

        protected void onProgressUpdate(Integer... progress) {
            // setProgressPercent(progress[0]);
        }

        protected void onPostExecute(MyData myData) {
            Log.d(">>>>>>>>>>>>>My data: ", myData.toString());
        }
    }

    public class MyTimerTask extends TimerTask {
        public void run() {
            try {
                new MyAsyncTask().execute("");
            } catch (Exception e) {
                Log.e(">>>>>>>>>>>> Error executing MyAsyncTask: ", e.getMessage(), e);
            }
        }
    }

}


Asked by: David512 | Posted: 25-01-2022






Answer 1

The problem is in the use of TimerTask. TimerTask run should post to a handler, something like this:

private Handler mHandler = new Handler(); 

public class MyTimerTask extends TimerTask {
    public void run() {
        mHandler.post(
            new Runnable() { 
                public void run() { 
                    new MyAsyncTask().execute("");
                } 
            };     
        )
    }
}

Of course this is getting a bit ugly, so would recommend taking out the anonymous class.

Answered by: Miranda944 | Posted: 26-02-2022



Answer 2

I got this to work thanks to James's answer.

I've included the code below in case it's useful to anyone.

Caveat developer! The code works for me, but may contain errors.

package com.example.test;

import java.net.URL;
import java.util.Timer;
import java.util.TimerTask;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;

public class MyXmlPoller extends Activity {

    private Handler handler = new Handler();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        new Timer().schedule(new MyTimerTask(), 0, 1000);
    }

    private class MyAsyncTask extends AsyncTask<Integer, Integer, MyData> {

        protected MyData doInBackground(Integer... counter) {
            MyData myData = new MyData();

            try {
                URL url = new URL("http://www.example.com/my.xml");
                SAXParserFactory spf = SAXParserFactory.newInstance();
                SAXParser sp = spf.newSAXParser();

                XMLReader xr = sp.getXMLReader();

                MySAXHandler mySAXHandler = new Handler();
                xr.setContentHandler(mySAXHandler);

                xr.parse(new InputSource(url.openStream()));

                myData = mySAXHandler.getParsedData();

                return myData;

            } catch (Exception e) {
                Log.e("!!!!!!!!!! MyAsyncTask doInBackground error", e.getMessage(), e);
                return myData;
            }

        }

        protected void onPostExecute(MyData myData) {
            Log.d("+++++++++++++ MyAsyncTask onPostExecute", myData.toString());
        }
    } // MyAsyncTask

    public class MyTimerTask extends TimerTask {
        private Runnable runnable = new Runnable() {
            public void run() {
                new MyAsyncTask().execute();
            }
        };

        public void run() {
            handler.post(runnable);
        }
    }
}

Answered by: Anna919 | Posted: 26-02-2022



Answer 3

The problem seems to be that you haven't called Looper.prepare(). You could have a look at the documentation for Looper.

A Handler needs a message loop in order to process messages and a Thread by default doesn't have one.

It seems that AsyncTask uses a Handler internally so add Looper.prepare() at the top of your run() method in MyTimerTask and that should solve your problem.

Answered by: Clark101 | Posted: 26-02-2022



Answer 4

I'd use the service with alarm manager

   I    Intent updateIntent = new Intent(ACTION_UPDATE_ALL);
        updateIntent.setClass(this, UpdateService.class);
        PendingIntent pendingIntent = PendingIntent.getService(this, 0, updateIntent, 0);
        AlarmManager alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
        alarmManager.set(AlarmManager.RTC, nextUpdate, pendingIntent);

Answered by: Thomas435 | Posted: 26-02-2022



Answer 5

The problem is you can't create the Handler object in the thread that doInBackground() runs in. I would implement the onPreExecute() method and put your setup code in there. Try moving these lines into the onPreExecute() method:

            URL url = new URL("http://www.example.com/my.xml");
            SAXParserFactory spf = SAXParserFactory.newInstance();
            SAXParser sp = spf.newSAXParser();

            XMLReader xr = sp.getXMLReader();

            MyHandler myHandler = new MyHandler();
            xr.setContentHandler(myHandler);

Answered by: Miranda443 | Posted: 26-02-2022



Similar questions

android - AsyncTask Bug on HTC Sense

Im using HTC Hero with HTS sense. Im experience that sometimes AsyncTask not will run doInBackground method on execute(); Its only on my Hero this appears. Someone have come across same problem? / Martin


android - Is it possible to use AsyncTask in a Service class?

Everything is in the title. On the official documentations it is stated that Note that services, like other application objects, run in the main thread of their hosting process and AsyncTask only works if it is executed in the UIThread. So is it possible to use AsyncTask in a Service class? I am trying to do so but I'm always getting the same error 05-01 18:09:25.487: E...


android - What to do with AsyncTask in onPause()?

I'm using an AsyncTask in my activity. Looks like: public class MyActivity { private AsyncTask mTask; private void doSomethingCool() { mTask = new AsyncTask(...); mTask.execute(); } @Override protected void onPause() { super.onPause(); // How do I let the task keep running if just rotating? if (isFinishing() == false) { ... ...


android - AsyncTask and SQLite Database

What's the best way to access the database through an async task? I don't think I should pass in a reference to the DbAdapter that the activity is using (could be closed as the activity may be garbage-collected). Also, the db needs a context to be opened and closed, but I don't have that with the async task.


java - Problem with AsyncTask on rooted Droid

I've got a widget on the Android market called DigiClock widget, and after the last update i've been having some extremely rare and random problems on rooted Motorola Droids ( there may be other handsets with the problem, but the only responses i've had are from rooted droid users ). The problem occurs when an activity is launched that runs an AsyncTask that retrieves all the installed applications from the device while sh...


junit - Android AsyncTask testing with Android Test Framework

I have a very simple AsyncTask implementation example and am having problem in testing it using Android JUnit framework. It works just fine when I instantiate and execute it in normal application. However when it's executed from any of Android Testing framework classes (i.e. AndroidTestCase, ActivityUnitTestCase, ActivityInstrumentationTestCase2...


android - AsyncTask Bug on HTC Sense

Im using HTC Hero with HTS sense. Im experience that sometimes AsyncTask not will run doInBackground method on execute(); Its only on my Hero this appears. Someone have come across same problem? / Martin


java - I have one Activity. In this Activity, I executed a AsyncTask , but it's not working

private class ExecuteLocations extends AsyncTask&lt;String, Void, Void&gt;{ private final ProgressDialog dialog = new ProgressDialog(ListProfiles.this); protected void onPreExecute() { //this.dialog.setMessage("Starting pre-execute..."); //this.dialog.show(); } @Override protected Void doInBackground(String... arg0) { check_profiles_lm=(LocationManager) ListProfiles.thi...


java - When to use a Service or AsyncTask or Handler?

Can someone tell me the TRUE difference?


android - How to cancel AsyncTask when Activity finishes?

In my Activity I use multiple AsyncTask classes. How to cancel AsyncTask when Activity finishes?


android - AsyncTask won't stop even when the Activity has destroyed

I have an AsyncTask object which starts executing when the Activity is created and does stuff in the background (downloads up to 100 images). Everything works fine but there is this peculiar behavior which i'm not able to understand. For eg: when the android screen's orientation changes then the Activity is destroyed and created again. So I override the o...


android - AsyncTask Threading Rule - Can it really only be used once?

In the documentation on AsyncTask it gives the following as a rule related to threading: The task can be executed only once (an exception will be thrown if a second execution is attempted.) All this means is that you have to create a new instance of the class every ti...






Still can't find your answer? Check out these communities...



Android Google Support | Android Community | Android Community (Facebook) | Dev.io Android



top