我正在尝试创建每 30*1000 毫秒拉取一次 Web 服务器的简单 Android 程序。我的应用程序中有专门的服务 - PollerService
Android Manifest.xml:
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".PullServerAndListenActivivty"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".PollerService" />
</application>
该类创建计划执行器并注册其计时器任务以开始调用引擎,引擎按顺序拉取服务器。
PollerService.java:
public class PollerService extends Service {
public static final int INTERVAL = 20*1000;
private ScheduledExecutorService executor;
public void onCreate() {
super.onCreate();
executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleAtFixedRate(new TimerTask() {
public void run() {
Engine.tick ();
}
}, 0, INTERVAL, TimeUnit.MILLISECONDS);
}
public void onDestroy() {
executor.shutdownNow();
}
public IBinder onBind(Intent arg0) {
return null;
};
}
引擎只是在 GUI 线程中创建 AsyncTask 子类实例并执行它。 onPostExecute 通过在 Activity 中分配的控制台写入一行并调用 UI 组件。
public class Engine {
private static Console console; //Assigned in Activity onCreate
private static Activity context;//Assigned in Activity onCreate
...
public static void tick() {
final String requestURL = String.format(urlFormat, serverURL);
try {
context.runOnUiThread(
new Runnable () {
public void run() {
new RequestTask().execute(requestURL);
};
}
);
}
catch (Throwable e) {
Log.e("SBOX", e.getMessage(), e);
}
}
public static void processCommand(String result) {
try {
final Command command = fromJSONToCommand(result);
context.runOnUiThread(new Runnable() {
public void run() {
console.writeLine("Receieved command: " + command);
}
});
} catch (Exception e) {
Log.e ("SBOX", e.getMessage(), e);
}
}
Yak,我从简单的 RequestTask 实例创建开始,我的印象是它会自己在 UI 线程上运行,但试图解决这个问题我终于找到了这种方法,但仍然没有用。只想说我在这里尝试了很多。
RequestTask 看起来像这样,简单的 http 调用:
class RequestTask extends AsyncTask<String, Void, String>{
@Override
protected String doInBackground(String... uri) {
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
String responseString = null;
try {
response = httpclient.execute(new HttpGet(uri[0]));
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpStatus.SC_OK){
ByteArrayOutputStream out = new ByteArrayOutputStream();
response.getEntity().writeTo(out);
out.close();
responseString = out.toString();
} else{
response.getEntity().getContent().close();
throw new IOException(statusLine.getReasonPhrase());
}
} catch (Exception e) {
Log.e("SBOX", e.getMessage(), e);
}
return responseString;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Engine.processCommand (result);
}
}
所以问题是它只正确运行一次,定时器调度,第一次调用引擎,它运行 RequestTask,它拉服务器,获取响应,在控制台打印它。但是第二次它进入计时器方法,然后服务没有任何生命迹象。 LogCat 无异常,不打印 RequestTask 中的日志。
当然是时候开始调试了,但也许有人可以让我免于这种痛苦并在代码中显示错误?如果评论 Engine.tick() 调用,执行程序本身会完美连续地工作。
对于解决问题的线索将非常有用。
最佳答案
I am trying to create simple Android program that pulls web server every 30*1000 milliseconds.
你肯定是在努力解决它。
第 1 步:在您的 Activity 和服务之间建立一个真实的通信 channel 。不要使用静态数据成员,因为您可能会造成内存泄漏。有很多候选对象(createPendingResult()
、Messenger
等)。为了这个答案,我假设您将使用广播 Intent
,因此选择一些独特的操作字符串并在 onResume 中设置一个
在您的 Activity 中收听此类广播(并在 BroadcastReceiver
()onPause()
中删除该接收器)。
第 2 步:在您的服务中创建一个 pollServer()
方法,该方法具有来自 RequestTask
的 doInBackground()
方法的代码.但是,不是返回一个字符串,而是让它发送广播 Intent
,将您的字符串作为额外的。
第 3 步:从 ScheduledExecutorService
调用 pollServer()
,而不是 Engine.tick()
。
第 4 步:完全删除 Engine
和 RequestTask
。
关于java - Android 服务中调度的 AsyncTask 仅正确执行一次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8901825/