在Android服务中安排的AsynTask只执行一次

kir*_*off 1 java multithreading android httpclient android-asynctask

我正在尝试创建简单的Android程序,每30*1000毫秒拉一次Web服务器.我在我的应用程序中有专门的服务 - 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>
Run Code Online (Sandbox Code Playgroud)

该类创建计划执行程序并注册其计时器任务以开始调用Engine,以便拉出服务器.

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;
};
}
Run Code Online (Sandbox Code Playgroud)

Engine只在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);      
    }
}
Run Code Online (Sandbox Code Playgroud)

牦牛,我从简单的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);
}
}
Run Code Online (Sandbox Code Playgroud)

所以问题是它只运行一次,定时器调度,第一次调用Engine,它运行RequestTask,它拉动服务器,获取响应,在控制台中打印它.但第二次它进入计时器方法,然后从服务没有生命迹象.LogCat中没有例外,不打印登录RequestTask.

当然是时候调试了,但可能有人可以免除这种痛苦并在代码中显示错误?如果要对Engine.tick()调用进行注释,则执行程序本身可以完全连续工作.

对解决问题的线索非常感兴趣.

Com*_*are 6

我正在尝试创建简单的Android程序,每30*1000毫秒拉一次Web服务器.

你肯定会以艰难的方式去做.

步骤1:在您的活动和服务之间建立真实的沟通渠道.不要使用静态数据成员,因为您正在创建可能的内存泄漏.有很多考生(createPendingResult(),Messenger,等).为了这个答案,我将假设您将使用广播Intent,因此选择一些独特的动作字符串并在您的活动中设置一个BroadcastReceiverin onResume()来监听这样的广播(并删除该接收者onPause()).

第2步:pollServer()在您的服务中创建一个方法,该方法包含来自您的doInBackground()方法的代码RequestTask.但是,不是返回一个字符串,而是让它发送广播Intent,并将你的字符串作为额外的.

第3步:pollServer()来自你的呼叫ScheduledExecutorService,而不是Engine.tick().

第四步:删除EngineRequestTask完全删除.