سؤال

من أجل الحصول على بيانات XML من خادم مرارا وتكرارا، أحاول استخدام 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()

أنا أستخدم SDK 1.5 مع Eclipse على Windows.

لقد بحثت في الوثائق، على Stackoverflow وفي مجموعة مطوري Android، لكنني لست واضحا ما الذي يسبب الخطأ أو كيفية إصلاحه.

يمكنني الحصول على البيانات مرة واحدة - أي بدون ASYNC والموقت - وتحليلها عبر SAX دون مشاكل.

رمز التطبيق الكامل أدناه.

يرجى إظهار أي أخطاء ساذجة: أنا جديد تماما على الروبوت.

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);
            }
        }
    }

}
هل كانت مفيدة؟

المحلول

المشكلة هي في استخدام 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("");
                } 
            };     
        )
    }
}

بالطبع هذا هو الحصول على القبيح قليلا، لذلك سوف يوصي بإخراج الطبقة المجهولة.

نصائح أخرى

حصلت على هذا للعمل بفضل إجابة جيمس.

لقد قمت بتضمين الرمز أدناه في حالة أنه من المفيد لأي شخص.

مطور التحذير! يعمل الرمز بالنسبة لي، ولكن قد يحتوي على أخطاء.

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);
        }
    }
}

يبدو أن المشكلة هي أنك لم تستدعي Looper.prepare(). وبعد هل يمكن أن يكون لديك نظرة على وثائق ل Looper.

أ Handler يحتاج إلى حلقة رسالة من أجل معالجة الرسائل وخيطه افتراضيا ليس لديه واحد.

يبدو أن AsyncTask يستخدم أ Handler داخليا لذلك أضف Looper.prepare() في الجزء العلوي من الخاص بك run() طريقة في MyTimerTask وهذا يجب أن يحل مشكلتك.

سأستمر الخدمة مع مدير الإنذار

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

المشكلة هي أنه لا يمكنك إنشاء كائن المعالج في مؤشر الترابط الذي يعمل فيه DoinBackground (). سأقوم بتطبيق أسلوب 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);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top