2011-05-23 77 views
25

我一直在Android開發者網站上閱讀以下文字,特別是在Framework Topics -> Services -> Starting a Service之下。如何使用PendingIntent從服務通信到客戶端/活動?

在那裏,它指出以下:

如果該服務不提供也結合,()與startService遞送的目的是應用程序組件和服務之間的通信的唯一的模式。但是,如果您希望服務發回結果,則啓動該服務的客戶端可以爲廣播創建一個PendingIntent(使用getBroadcast()),並將其傳遞到啓動該服務的Intent中的服務。該服務然後可以使用廣播來傳送結果。

我有一個關於這幾個問題:

  1. 這是否文本既適用於Service小號IntentService S'
  2. 如何(codewise)這應該從Service內實現; 服務可以使用廣播來傳遞結果。以及提到的廣播將結果傳遞給原始客戶/活動的位置?是否有一些方法應該被覆蓋(如onActivityResult())或其他?

回答

45


問題是,幾個月前問過,但在任何情況下,仍然在尋找答案,我希望我可以幫助。

在下面的例子中,我們有本地服務,負責執行一些耗時的操作。活動向服務發出請求,但不綁定到它 - 只是發送請求的意圖。另外,Activity包含BroadcastReceiver的信息,當服務完成所請求的任務時應該回調該信息。該信息由PendingIntent傳遞。該服務在後臺線程中處理該任務,並且在任務完成時,服務通過回答廣播BroadcastReceiver。

1.創建BroadcastReceiver的子類:

public class DataBroadcastReceiver extends BroadcastReceiver { 
    static Logger log = LoggerFactory.getLogger(DataRequestService.class); 
    @Override 
    public void onReceive(Context context, Intent intent) { 
     log.info(" onReceive"); 
    } 
} 

該廣播接收器將從服務通知,當任務完成。

2.創建服務

public class DataRequestService extends Service { 

    private final class ServiceHandler extends Handler { 
     public ServiceHandler(Looper looper) { 
     super(looper); 
     } 

     @Override 
     public void handleMessage(Message msg) { 
     log.info("handleMessage"); 
     //... performing some time-consuming operation   
     Bundle bundle = msg.getData(); 
     PendingIntent receiver = bundle.getParcelable("receiver"); 
     // Perform the operation associated with PendingIntent 
     try {    
      //you can attach data from the operation in the intent. 
      Intent intent = new Intent(); 
      Bundle b = new Bundle(); 
      //b.putString("key", value); 
      intent.putExtras(b); 
      receiver.send(getApplicationContext(), status, intent); 
     } catch (CanceledException e) {   
     e.printStackTrace(); 
     }   
     } 
    } 

    @Override 
    public void onStart(Intent intent, int startId) { 
     Bundle bundle = intent.getExtras(); 
     msg.setData(bundle); 
     mServiceHandler.sendMessage(msg); 
    } 

嘛,最重要的部分是的h​​andleMessage()方法。服務只是將廣播操作發送給廣播接收器。

3.您還需要註冊您的廣播接收器和服務的Manifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.ramps.servicetest" 
    android:versionCode="1" 
    android:versionName="1.0" > 
    .... 
     <service android:name=".service.DataRequestService" android:exported="false"/> 
     <receiver android:name=".service.DataBroadcastReceiver"></receiver> 
    </application> 
</manifest><br> 

4。最後,從活動也求您服務:

Intent serviceIntent = new Intent(context, DataRequestService.class); 
    @Override 
    public void onClick(View v) { 
     //this is the intent that will be broadcasted by service. 
     Intent broadcastReceiverIntent = new Intent(context, DataBroadcastReceiver.class);  
     //create pending intent for broadcasting the DataBroadcastReceiver 
     PendingIntent pi = PendingIntent.getBroadcast(context, 0, broadcastReceiverIntent, 0);  
     Bundle bundle = new Bundle();    
     bundle.putParcelable("receiver", pi); 
     //we want to start our service (for handling our time-consuming operation) 
     Intent serviceIntent = new Intent(context, DataRequestService.class); 
     serviceIntent.putExtras(bundle); 
     context.startService(serviceIntent); 
    } 



5.發應答原始客戶端/活動

您可以從中抽取活動,從中可以擴展所有活動。這種絕對活動可以在廣播接收器中自動註冊/註銷自己作爲響應監聽器。實際上這裏沒有太多的選項,但重要的是,如果您保留對活動的靜態引用,那麼當活動被破壞時,您必須刪除引用。

問候,
坡道

+1

爲什麼不直接調用從服務的廣播接收器。所有這些只是爲了隱藏ServiceReader的名稱? – Kiran 2015-05-12 09:19:18

+0

需要在這裏創建處理程序是什麼?我們可以在onStart()中發送廣播。 – 2016-08-04 14:10:34

+1

@RohitBandil'服務'在UI線程上運行,因此在那裏執行後臺操作併發送結果會挫敗後臺服務的目的。 'IntentService'旨在隱藏你的Handler複雜性;不知道爲什麼@Ramps不使用它。 – TWiStErRob 2016-09-07 20:50:32

0

隨着服務和活動之間的書面here

通信可以使用 完成PendingIntent.For我們可以使用 createPendingResult() .createPendi ngResult()創建一個新的PendingIntent對象,您可以交給服務使用並將結果數據發送回onActivityResult(int,int, Intent)callback中的活動。由於PendingIntent是Parcelable,因此可以將 進入一個意圖額外,您的活動可以將這個 PendingIntent傳遞給該服務。該服務反過來可以調用PendingIntent上的send() 方法來通過 onActivityResult通知該活動的一個事件。

活動

public class PendingIntentActivity extends AppCompatActivity 
{ 
@Override 
protected void onCreate(@Nullable Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.activity_main); 

PendingIntent pendingResult = createPendingResult(
100, new Intent(), 0); 
Intent intent = new Intent(getApplicationContext(), PendingIntentService.class); 
intent.putExtra("pendingIntent", pendingResult); 
startService(intent); 

} 

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
if (requestCode == 100 && resultCode==200) { 
Toast.makeText(this,data.getStringExtra("name"),Toast.LENGTH_LONG).show(); 
} 
super.onActivityResult(requestCode, resultCode, data); 
} 
} 

服務

public class PendingIntentService extends Service { 

    private static final String[] items= { "lorem", "ipsum", "dolor", 
      "sit", "amet", "consectetuer", "adipiscing", "elit", "morbi", 
      "vel", "ligula", "vitae", "arcu", "aliquet", "mollis", "etiam", 
      "vel", "erat", "placerat", "ante", "porttitor", "sodales", 
      "pellentesque", "augue", "purus" }; 
    private PendingIntent data; 

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

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 

     data = intent.getParcelableExtra("pendingIntent"); 

     new LoadWordsThread().start(); 
     return START_NOT_STICKY; 
    } 

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

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

    class LoadWordsThread extends Thread { 
     @Override 
     public void run() { 
      for (String item : items) { 
       if (!isInterrupted()) { 

        Intent result = new Intent(); 
        result.putExtra("name", item); 
        try { 
         data.send(PendingIntentService.this,200,result); 
        } catch (PendingIntent.CanceledException e) { 

         e.printStackTrace(); 
        } 
        SystemClock.sleep(400); 

       } 
      } 
     } 
    } 
}