2011-05-23 69 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); 

       } 
      } 
     } 
    } 
}