AsynTask, запланированный в службе Android, выполняется правильно только один раз - PullRequest
1 голос
/ 18 января 2012

Я пытаюсь создать простую программу для Android, которая тянет веб-сервер каждые 30 * 1000 миллисекунд. В моем приложении есть выделенный сервис - 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;
};
}

Механизм просто создает экземпляр подкласса AsyncTask в потоке GUI и выполняет его. onPostExecute записывает строку через консоль, которая была назначена в Activity, и вызывает компоненты пользовательского интерфейса.

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

Як, я начал с простого создания экземпляра RequestTask, у меня сложилось впечатление, что он будет работать в потоке пользовательского интерфейса, но, пытаясь решить проблему, я, наконец, пришел к такому подходу, все еще бесполезному. Просто хочу сказать, что я много пробовал здесь.

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

Так что проблема в том, что он работает правильно только один раз, таймер планирует, вызывает первый раз Engine, он запускает RequestTask, он тянет сервер, получает ответ, печатает его в консоли. Но второй раз он попадает в метод таймера, и тогда никаких признаков жизни со стороны сервиса. Нет исключений в LogCat, вход в RequestTask не печатается.

Конечно, пришло время отладки, но, возможно, кто-то может спасти меня от этой боли и показать ошибки в коде? Сам исполнитель работает идеально непрерывно, если комментировать вызов Engine.tick ().

Будет очень благодарен за подсказки по разрешению.

Ответы [ 2 ]

6 голосов
/ 18 января 2012

Я пытаюсь создать простую программу для Android, которая тянет веб-сервер каждые 30 * 1000 миллисекунд.

Вы уверены, что идете по этому пути трудным путем.

Шаг# 1: Установите реальный канал связи между вашей деятельностью и вашим сервисом.Не используйте статический член данных, поскольку вы создаете возможную утечку памяти.Есть много кандидатов (createPendingResult(), Messenger и т. Д.).Ради этого ответа я буду предполагать, что вы собираетесь использовать трансляцию Intent, поэтому выберите какую-то уникальную строку действия и настройте BroadcastReceiver in onResume() в своей активности, чтобы прослушивать такую ​​трансляцию (иудалите этот получатель в onPause()).

Шаг # 2: Создайте в своей службе метод pollServer(), содержащий код из вашего метода doInBackground() из вашего RequestTask.Однако вместо того, чтобы возвращать строку, она отправляет широковещательную рассылку Intent с вашей дополнительной строкой.

Шаг # 3: Вызовите pollServer() со своего ScheduledExecutorService вместо Engine.tick().

Шаг № 4: Удалить Engine и RequestTask полностью.

2 голосов
/ 18 января 2012

В документации по AsyncTask, как правило, указано следующее, связанное с многопоточностью:

Задача может быть выполнена только один раз (исключение будет выдано при попытке второго выполнения.)

Все это означает, что вам нужно создавать новый экземпляр класса каждый раз, когда вы хотите его использовать.Другими словами, это должно быть сделано так:

new DownloadFilesTask().execute(url1, url2, url3);
new DownloadFilesTask().execute(url4, url5, url6);

Или, наоборот, вы НЕ МОЖЕТЕ делать следующее:

DownloadFilesTask dfTask = new DownloadFilesTask();
dfTask().execute(url1, url2, url3);
dfTask().execute(url4, url5, url6);
...