2016-02-06 29 views
1

我想獨立運行像Pushbullet,SmartLockScreen或WhatsApp一樣的服務,它正在等待一些事件發生。我已經嘗試了前臺服務,在onStartCommand中返回START_STICKY,在onTaskRemoved中重新啓動服務並使用android:process在單獨的進程中運行服務。爲什麼我的後臺服務或我的廣播接收器在主要活動中死亡?

我的服務類:

public class CallService extends Service { 

@Override 
public IBinder onBind(Intent intent) { 
    // TODO Auto-generated method stub 
    return null; 
} 

@Override 
public int onStartCommand (Intent intent, int flags, int startId){ 
    NotificationCompat.Builder builder = new NotificationCompat.Builder(this); 
    builder.setSmallIcon(R.drawable.icon) 
      .setContentTitle("title") 
      .setContentText("text") 
      .setAutoCancel(true) 
      .setOngoing(true); 
    Intent startIntent = new Intent(this, MainActivity.class); 
    PendingIntent contentIntent = PendingIntent.getActivity(this, 1, startIntent, 0); 
    builder.setContentIntent(contentIntent); 
    this.startForeground(1, builder.build()); 
    super.onStartCommand(intent, flags, startId); 
    return START_STICKY; 
} 

@Override 
public void onCreate() { 
    super.onCreate(); 
} 

@Override 
public void onDestroy() { 
    super.onDestroy(); 

} 
@Override 
public void onTaskRemoved(Intent rootIntent){ 
    Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass()); 
    restartServiceIntent.setPackage(getPackageName()); 

    PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT); 
    AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE); 
    alarmService.set(
      AlarmManager.ELAPSED_REALTIME, 
      SystemClock.elapsedRealtime() + 1000, 
      restartServicePendingIntent); 

    super.onTaskRemoved(rootIntent); 
} 

我的AndroidManifest.xml

<service android:name=".CallService" android:persistent="true"> 
      <intent-filter> 
       <action android:name="cz.volamakler.CallService" /> 
      </intent-filter> 
</service> 
    <receiver android:name=".CallReceiver"> 
     <intent-filter> 
      <action android:name="android.intent.action.PHONE_STATE" /> 
     </intent-filter> 
     <intent-filter> 
      <action android:name="android.intent.action.NEW_OUTGOING_CALL" /> 
     </intent-filter> 
    </receiver> 

我嘗試使用廣播接收器,並獲取與主要活動殺死了。

public abstract class PhoneCallReceiver extends BroadcastReceiver { 

    //The receiver will be recreated whenever android feels like it. We need a static variable to remember data between instantiations 

    private static int lastState = TelephonyManager.CALL_STATE_IDLE; 
    private static Date callStartTime; 
    private static boolean isIncoming; 
    private static String savedNumber; //because the passed incoming is only valid in ringing 


    @Override 
    public void onReceive(Context context, Intent intent) { 

     //We listen to two intents. The new outgoing call only tells us of an outgoing call. We use it to get the number. 
     if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) { 
      savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER"); 
     } 
     else{ 
      String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE); 
      String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER); 
      int state = 0; 
      if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)){ 
       state = TelephonyManager.CALL_STATE_IDLE; 
      } 
      else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){ 
       state = TelephonyManager.CALL_STATE_OFFHOOK; 
      } 
      else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)){ 
       state = TelephonyManager.CALL_STATE_RINGING; 
      } 

      onCallStateChanged(context, state, number); 
     } 
    } 

    //Derived classes should override these to respond to specific events of interest 
    protected void onIncomingCallStarted(Context ctx, String number, Date start){} 
    protected void onOutgoingCallStarted(Context ctx, String number, Date start){} 
    protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end){} 
    protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end){} 
    protected void onMissedCall(Context ctx, String number, Date start){} 

    //Deals with actual events 

    //Incoming call- goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up 
    //Outgoing call- goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up 
    public void onCallStateChanged(Context context, int state, String number) { 
     if(lastState == state){ 
      //No change, debounce extras 
      return; 
     } 
     switch (state) { 
      case TelephonyManager.CALL_STATE_RINGING: 
       isIncoming = true; 
       callStartTime = new Date(); 
       savedNumber = number; 
       onIncomingCallStarted(context, number, callStartTime); 
       break; 
      case TelephonyManager.CALL_STATE_OFFHOOK: 
       //Transition of ringing->offhook are pickups of incoming calls. Nothing done on them 
       if(lastState != TelephonyManager.CALL_STATE_RINGING){ 
        isIncoming = false; 
        callStartTime = new Date(); 
        onOutgoingCallStarted(context, savedNumber, callStartTime); 
       } 
       break; 
      case TelephonyManager.CALL_STATE_IDLE: 
       //Went to idle- this is the end of a call. What type depends on previous state(s) 
       if(lastState == TelephonyManager.CALL_STATE_RINGING){ 
        //Ring but no pickup- a miss 
        onMissedCall(context, savedNumber, callStartTime); 
       } 
       else if(isIncoming){ 
        onIncomingCallEnded(context, savedNumber, callStartTime, new Date()); 
       } 
       else{ 
        onOutgoingCallEnded(context, savedNumber, callStartTime, new Date()); 
       } 
       break; 
     } 
     lastState = state; 
    } 
} 

public class CallReceiver extends PhoneCallReceiver { 

    @Override 
    protected void onIncomingCallStarted(Context ctx, String number, Date start) { 
     Toast.makeText(ctx, "Call!", Toast.LENGTH_LONG).show(); 
    } 

    @Override 
    protected void onOutgoingCallStarted(Context ctx, String number, Date start) { 
    } 

    @Override 
    protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end) { 
    } 

    @Override 
    protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end) { 
    } 

    @Override 
    protected void onMissedCall(Context ctx, String number, Date start) { 
    } 
} 
+0

什麼時候死亡? – pskink

+0

當我關閉應用程序(UI) – user5892860

+0

意味着當你按下「返回」你的主要活動? (當調用finish()方法時) – pskink

回答

1

發生這種情況是因爲您在相同的UI線程中運行您的服務。使用的Looper與啓動服務的應用程序的ui線程相同。您需要執行以下操作:

創建一個單獨的處理程序線程。然後在處理消息中執行你的任務。

public class CallService extends Service { 
      private Looper mServiceLooper; 
      private ServiceHandler mServiceHandler; 

      // Handler that receives messages from the thread 
      private final class ServiceHandler extends Handler { 
       public ServiceHandler(Looper looper) { 
        super(looper); 
       } 
       @Override 
       public void handleMessage(Message msg) { 
        // Normally we would do some work here, like download a file. 
        // For our sample, we just sleep for 5 seconds. 
        long endTime = System.currentTimeMillis() + 5*1000; 
        while (System.currentTimeMillis() < endTime) { 
         synchronized (this) { 
          try { 
           wait(endTime - System.currentTimeMillis()); 
          } catch (Exception e) { 
          } 
         } 
        } 
        // Stop the service using the startId, so that we don't stop 
        // the service in the middle of handling another job 
        stopSelf(msg.arg1); 
       } 
      } 
      @Override 
      public IBinder onBind(Intent intent) { 
       // TODO Auto-generated method stub 
       return null; 
      } 

      @Override 
      public int onStartCommand (Intent intent, int flags, int startId){ 
// For each start request, send a message to start a job and deliver the 
     // start ID so we know which request we're stopping when we finish the job 
     Message msg = mServiceHandler.obtainMessage(); 
     msg.arg1 = startId; 
     mServiceHandler.sendMessage(msg); 

       return START_STICKY; 
      } 
      @Override 
     public void onCreate() { 
     // Start up the thread running the service. Note that we create a 
     // separate thread because the service normally runs in the process's 
     // main thread, which we don't want to block. We also make it 
     // background priority so CPU-intensive work will not disrupt our UI. 
     HandlerThread thread = new HandlerThread("ServiceStartArguments", 
       Process.THREAD_PRIORITY_BACKGROUND); 
     thread.start(); 

     // Get the HandlerThread's Looper and use it for our Handler 
     mServiceLooper = thread.getLooper(); 
     mServiceHandler = new ServiceHandler(mServiceLooper); 
     } 
      @Override 
      public void onDestroy() { 
       super.onDestroy(); 

      } 
      @Override 
      public void onTaskRemoved(Intent rootIntent){ 
       Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass()); 
       restartServiceIntent.setPackage(getPackageName()); 

       PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT); 
       AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE); 
       alarmService.set(
         AlarmManager.ELAPSED_REALTIME, 
         SystemClock.elapsedRealtime() + 1000, 
         restartServicePendingIntent); 

       super.onTaskRemoved(rootIntent); 
      } 
      } 

我希望這會有所幫助。

+0

我會試試看,謝謝! – user5892860

+0

這不是我想要的。我想獨立運行像Pushbullet,SmartLockScreen或WhatsApp一樣的服務,它正在等待一些事件發生。 – user5892860

+0

你想聽哪個事件?在這種情況下,您可以使用廣播接收器。 –