2010-01-07 5 views
2

XML 데이터를 서버에서 반복적으로 가져 오려면 Mark Murphy's suggestion에 따라 AsyncTask 및 Timer를 사용하려고합니다.AsyncTask와 Timer를 사용하여 XML을 얻는 방법?

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에서 이클립스 SDK 1.5을 사용하고 있습니다 :

나는 다음과 같은 오류가 발생합니다.

StackOverflow 및 Android Developers 그룹에서 설명서를 살펴 봤지만 오류의 원인이나 해결 방법을 명확하게 밝히지 않았습니다.

비동기 및 타이머가없는 데이터를 한 번 가져올 수 있으며 문제없이 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); 
      } 
     } 
    } 

} 

답변

7

문제는 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(""); 
       } 
      };  
     ) 
    } 
} 

이 조금 못생긴지고를, 그래서 익명의 클래스를 복용 추천 할 것입니다.

+0

제임스 고맙습니다. 나는 이것을 사용하는 대답을 추가했습니다. –

3

Looper.prepare()을 호출하지 않은 것 같습니다. documentation for Looper을 살펴볼 수 있습니다.

Handler은 메시지를 처리하기 위해 메시지 루프가 필요하며 스레드는 기본적으로 메시지 루프를 필요로하지 않습니다.

것 같습니다. run() 방법의 상단에 Looper.prepare()을 넣고 MyTimerTask에 입력하면 문제가 해결됩니다.

+0

시도해 보았지만 동일한 예외가 발생했습니다. MyTimerTask의 run() 맨 위에 Looper.prepare()를 추가하면 doInBackground()가 예외없이 한 번 호출되지만 onPostExecute()는 호출되지 않습니다. –

+0

샘의'MyHandler'는 안드로이드의 하위 클래스 인 것 같지 않습니다.'Handler' no ??? 그렇지 않으면'XmlReader'의 인수로 어떻게 전달 될 수 있습니까? 애플리케이션에 'android.os.Handler'를 만드는 다른 스레드가 있습니까? – tbruyelle

+0

내 실수. 미안. 문제는'AsyncTask'가'Handler'를 사용하므로'TimerTask' 스레드에서'Looper.prepare()'를 할 필요가 있다는 것입니다. –

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

AlarmManager는 이와 같은 작업에는 ** ** 적합하지 않습니다. AlarmManager 용 javadoc은 다음과 같이 말합니다 : "Alarm Manager는 응용 프로그램이 현재 실행 중이 아닌 경우에도 특정 시간에 응용 프로그램 코드를 실행하려는 경우에 사용됩니다. 정상적인 타이밍 작업 (틱, 시간 초과 등)은 다음과 같습니다. Handler를 사용하는 것이 쉽고 훨씬 효율적입니다. " http://developer.android.com/reference/android/app/AlarmManager.html –

+0

데이브 웹 (Dave Webb)의 의견에 따르면, 특정 시점이 아닌 반복적으로 백그라운드 작업을 수행해야합니다. –

+0

필자의 요구 사항은 "서버에서 XML 데이터를 반복적으로 가져 오는 것"이라는 명확한 요구 사항이라고 생각합니다. 코드는 매 초마다 업데이트를 얻으려는 것으로 나타났습니다. AlarmManager를 사용하여이 작업을 수행 할 수 있다는 점을 분명히 알았지 만, Dave Webb이이 작업을 수행하는 가장 좋은 방법은 아님을 동의합니다. –

0

문제는 당신이 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); 
+0

onPreExecute()는 UI 스레드에서 실행되며 처리를 위해 UI를 업데이트하기위한 것이 아닙니다. –

+0

UI 업데이트를 위해서만 사용해야한다는 UI 스레드에서 실행되기 때문에 나는 생각할 것입니다. 제 생각에는 onPreExecute()에서 약간의 빠른 설정을하는 것이 좋습니다. –

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); 
     } 
    } 
} 
관련 문제