Foreground Service с проблемой таймера - PullRequest
0 голосов
/ 01 июня 2011

Я разрабатываю приложение, которое проверяет соединение с сервером через заданный интервал. Я использую сервис переднего плана с уведомлениями для этого. Проблема в том, что все работает нормально, пока телефон не спит (экран включен). С того момента, как я поворачиваю экран нажатием кнопки питания, сервис начинает вести себя странно. Я сделал урезанную версию своего сервиса, чтобы показать вам.
ForegroundService.java:

package service.App;
import android.R.drawable;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.IBinder;
import android.util.Log;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Timer;
import java.util.TimerTask;

public class ForegroundService extends Service {
static final String ACTION_FOREGROUND = "com.example.android.apis.FOREGROUND";
static final String ACTION_BACKGROUND = "com.example.android.apis.BACKGROUND";
private static final Class<?>[] mStartForegroundSignature = new Class[] {int.class, Notification.class };
private static final Class<?>[] mStopForegroundSignature = new Class[] { boolean.class };
private Method mStartForeground;
private Method mStopForeground;
private Object[] mStartForegroundArgs = new Object[2];
private Object[] mStopForegroundArgs = new Object[1];
private Timer timer = new Timer();
long interv=10000;
int timeout=3000;
Intent notificationIntent;
PendingIntent contentIntent;
Notification notification;
CharSequence text;
SimpleDateFormat df;

void invokeMethod(Method method, Object[] args) {
    try {
        mStartForeground.invoke(this, mStartForegroundArgs);
    } catch (InvocationTargetException e) {
        Log.w("ApiDemos", "Unable to invoke method", e);
    } catch (IllegalAccessException e) {
        Log.w("ApiDemos", "Unable to invoke method", e);
    }
}

void startForegroundCompat(int id, Notification notification) {
    Scan();
    if (mStartForeground != null) {
        mStartForegroundArgs[0] = Integer.valueOf(id);
        mStartForegroundArgs[1] = notification;
        invokeMethod(mStartForeground, mStartForegroundArgs);
        return;
    }
}

void stopForegroundCompat(int id) {
    if (mStopForeground != null) {
        mStopForegroundArgs[0] = Boolean.TRUE;
        try {
            mStopForeground.invoke(this, mStopForegroundArgs);
        } catch (InvocationTargetException e) {
            Log.w("ApiDemos", "Unable to invoke stopForeground", e);
        } catch (IllegalAccessException e) {
            Log.w("ApiDemos", "Unable to invoke stopForeground", e);
        }
        return;
    }
}

@Override
public void onCreate() {

    notificationIntent = new Intent(this, ForegroundService.class);
    contentIntent = PendingIntent.getActivity(this, 0, notificationIntent,0);
    try {
        mStartForeground = getClass().getMethod("startForeground",mStartForegroundSignature);
        mStopForeground = getClass().getMethod("stopForeground",mStopForegroundSignature);
    } catch (NoSuchMethodException e) {
        return;
    }
}

@Override
public void onDestroy() {
    stopForegroundCompat(R.string.foreground_service_started);

    if (timer != null) {

        timer.cancel();
    }
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    handleCommand(intent);
    return START_STICKY;
}

void handleCommand(Intent intent) {
    if (ACTION_FOREGROUND.equals(intent.getAction())) {
        text = getText(R.string.foreground_service_started);

        notification = new Notification(R.drawable.icon, text, System
                .currentTimeMillis());

        contentIntent = PendingIntent.getActivity(this, 0, new Intent(this,
                Start.class), 0);

        notification.setLatestEventInfo(this,
                getText(R.string.local_service_label), text, contentIntent);

        startForegroundCompat(R.string.foreground_service_started,
                notification);

    } else if (ACTION_BACKGROUND.equals(intent.getAction())) {
        stopForegroundCompat(R.string.foreground_service_started);
    }

}

@Override
public IBinder onBind(Intent intent) {
    return null;
}


private void Scan() {
    timer.scheduleAtFixedRate(new TimerTask() {

        @Override
        public void run() {

            Socket s = null;
            int p = 81;
            long time;
            String url="www.google.com";
            SimpleDateFormat df;
            InetAddress ipaddress;
                try {

                    ipaddress = InetAddress.getByName(url);

                    try {
                        s = new Socket();
                        s.connect(new InetSocketAddress(url, p), timeout);
                        time = System.currentTimeMillis();
                        df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        Log.i("Server Monitor",
                                "A server is running on port " + p + " "
                                        + "@ IP address "
                                        + ipaddress.getHostAddress()
                                        + ". Date/Time: "
                                        + df.format(new Date(time)));
                        s.close();
                    } catch (IOException e) {
                        String ns = Context.NOTIFICATION_SERVICE;
                        NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
                        long when = System.currentTimeMillis();
                        Notification notification = new Notification(drawable.ic_dialog_alert,"Server Monitor", when);
                        Context context = getApplicationContext();
                        CharSequence contentTitle = "Server Monitor";
                        CharSequence contentText = "No server on port." + p;
                        notification.setLatestEventInfo(context,contentTitle, contentText, contentIntent);
                        notification.defaults |= Notification.DEFAULT_SOUND;
                        final int HELLO_ID = 1;
                        mNotificationManager.notify(HELLO_ID, notification);

                    }
                } catch (UnknownHostException e) {
                    String ns = Context.NOTIFICATION_SERVICE;
                    NotificationManager mNotificationManager = (NotificationManager) getSystemService(ns);
                    long when = System.currentTimeMillis();
                    Notification notification = new Notification(drawable.ic_dialog_alert,"Server Monitor", when);
                    Context context = getApplicationContext();
                    CharSequence contentTitle = "Server Monitor";
                    CharSequence contentText = "Could not find host.";
                    notification.setLatestEventInfo(context,contentTitle, contentText, contentIntent);
                    notification.defaults |= Notification.DEFAULT_SOUND;
                    final int HELLO_ID = 1;
                    mNotificationManager.notify(HELLO_ID, notification);

                }

                if (s != null) {
                    try {
                        s.close();
                    } catch (IOException ioEx) {
                        Log.i("Server Monitor", "Unable to close socket "+ s);
                    }
                }
    }

    }, 0, interv);
}
}

Таким образом, этот сервис проверяет соединение с www.google.com через порт 81 каждые 10 секунд. Я установил это на порт 81, чтобы он не работал, и протестировал уведомления. Когда это терпит неудачу, это показывает уведомление. С того момента, как я поворачиваю экран, в течение одной или нескольких минут нет никаких уведомлений, а затем он дает мне все уведомления одновременно. Ниже приведено действие, которое запускает службу.
Start.java:

package service.App;
import service.App.R;
import service.App.ForegroundService;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class Start extends Activity{
private Button ButtonStartService;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    ButtonStartService = (Button)findViewById(R.id.ButtonStartService);

    ButtonStartService.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            Intent intent = new Intent(ForegroundService.ACTION_FOREGROUND);
            intent.setClass(Start.this, ForegroundService.class);
            startService(intent);
        }

    });
}
}

Так что я здесь делаю что-то не так? Это действительно важная часть моего приложения, поэтому эту ошибку действительно нужно исправить. Может кто-нибудь помочь мне, пожалуйста?

1 Ответ

1 голос
/ 22 ноября 2011

В спящем режиме (процессор выключен) Android не будет выполнять код приложения.

Чтобы избежать этого, вы можете использовать класс AlarmManager для планирования намерения, которое будет запускаться телефоном, ослабляя его из спящего режима, перехватывая его с помощью специального широковещательного приемника: http://developer.android.com/reference/android/app/AlarmManager.html

Затем вы должны приобрести WakeLock, используя класс PowerManager, чтобы гарантировать, что по крайней мере процессор будет поддерживаться, чтобы можно было выполнять код вашего приложения и выпускать его, когда он больше не нужен (это позволит телефону чтобы вернуться в спящий режим, чтобы избежать бесполезного использования батареи): http://developer.android.com/reference/android/os/PowerManager.html

Конечно, вы также можете просто получить WakeLock, как только ваш сервис начнет его хранить до тех пор, пока ваш сервис не будет закрыт, но этот подход не очень экономит батарею.

...