2011-06-01 22 views
0

我正在開發一個應用程序,以給定間隔檢查與服務器的連接。 我使用前臺服務和通知。問題是,只要手機處於清醒狀態(屏幕打開),一切都可以正常工作。從按下電源按鈕開始屏幕開始,服務開始表現異常。 我做了一個精簡版的我的服務向你展示。
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在端口每10秒81。我把它放在端口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); 
     } 

    }); 
} 
} 

所以我做錯了什麼嗎?這是我的應用程序中非常重要的一部分,所以這個bug必須修復。有人能幫助我嗎?

回答

1

當處於睡眠模式(CPU關閉)時,Android不會執行應用程序代碼。

爲了避免它,你可以使用AlarmManager類安排的意圖,通過手機推出從睡眠削弱它,使用自定義廣播接收器捕獲它: http://developer.android.com/reference/android/app/AlarmManager.html

然後,你應該獲得一個激活鎖定使用PowerManager類來確保至少CPU將保持開啓狀態,以便允許執行應用程序代碼,並在不再需要時釋放它(這將允許手機以睡眠模式返回以避免無用的電池用法): http://developer.android.com/reference/android/os/PowerManager.html

當然,你也可以簡單地取得一旦你的服務開始保持它直到你的服務關閉,WakeLock是一種方式,但這種方法不是非常適合電池使用。