3

为了重复从服务器获取 XML 数据,我尝试按照Mark Murphy 的建议使用 AsyncTask 和 Timer 。

我收到以下错误:

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()

我在 Windows 上使用带有 Eclipse 的 SDK 1.5。

我查看了文档、StackOverflow 和 Android 开发人员组,但我不清楚是什么导致了错误或如何修复它。

我可以一次获取数据——即没有异步和计时器——并通过 SAX 解析它而不会出现问题。

完整的应用程序代码如下。

请原谅任何天真的错误:我对 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);
            }
        }
    }

}
4

5 回答 5

8

问题在于 TimerTask 的使用。TimerTask 运行应该发布到处理程序,如下所示:

private Handler mHandler = new Handler(); 

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

当然这有点难看,所以建议去掉匿名类。

于 2010-01-07T20:25:45.293 回答
6

感谢詹姆斯的回答,我得到了这个工作。

我已经包含了下面的代码,以防它对任何人有用。

警告开发商!该代码适用于我,但可能包含错误。

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);
        }
    }
}
于 2010-01-08T11:55:19.850 回答
3

问题似乎是您没有调用Looper.prepare(). 您可以查看Looper.

AHandler需要一个消息循环来处理消息,而 Thread 默认情况下没有。

似乎在内部AsyncTask使用了一个Handler,所以在你的方法Looper.prepare()的顶部添加,这应该可以解决你的问题。run()MyTimerTask

于 2010-01-07T16:39:43.860 回答
0

我会将该服务与警报管理器一起使用

   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);
于 2010-01-07T19:07:41.307 回答
0

问题是你不能在 doInBackground() 运行的线程中创建 Handler 对象。我会实现 onPreExecute() 方法并将你的设置代码放在那里。尝试将这些行移到 onPreExecute() 方法中:

            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);
于 2010-01-07T19:49:44.170 回答