Monday, March 25, 2013

Send data from IntentService to Activity, via additional Broadcast

The former post demonstrate "Perform background processing with IntentService". It's a standard approach for IntentService, inform the Activity end of job by sending a Broadcast with Extra of respond.

But how can main Activity know the status of IntentService before end of job? It's another exercise to send additional Broadcast with another IntentFilter while running, to update main Activity, from IntentService. Such that we can implement additional BroadcastReceiver in main Activity to receive the additional Broadcast , and then update a ProgressBar.

Send data from IntentService to Activity, via additional Broadcast


MyIntentService.java
package com.example.androidintentservice;

import android.app.IntentService;
import android.content.Intent;

public class MyIntentService extends IntentService {
 
 public static final String ACTION_MyIntentService = "com.example.androidintentservice.RESPONSE";
 public static final String ACTION_MyUpdate = "com.example.androidintentservice.UPDATE";
 public static final String EXTRA_KEY_IN = "EXTRA_IN";
 public static final String EXTRA_KEY_OUT = "EXTRA_OUT";
 public static final String EXTRA_KEY_UPDATE = "EXTRA_UPDATE";
 String msgFromActivity;
 String extraOut;

 public MyIntentService() {
  super("com.example.androidintentservice.MyIntentService");
 }

 @Override
 protected void onHandleIntent(Intent intent) {
  
  //get input
  msgFromActivity = intent.getStringExtra(EXTRA_KEY_IN);
  extraOut = "Hello: " +  msgFromActivity;
  
  for(int i = 0; i <=10; i++){
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   
   //send update 
   Intent intentUpdate = new Intent();
   intentUpdate.setAction(ACTION_MyUpdate);
   intentUpdate.addCategory(Intent.CATEGORY_DEFAULT);
   intentUpdate.putExtra(EXTRA_KEY_UPDATE, i);
   sendBroadcast(intentUpdate);
  }
  
  //return result
  Intent intentResponse = new Intent();
  intentResponse.setAction(ACTION_MyIntentService);
  intentResponse.addCategory(Intent.CATEGORY_DEFAULT);
  intentResponse.putExtra(EXTRA_KEY_OUT, extraOut);
  sendBroadcast(intentResponse);
 }

}


MainActivity.java
package com.example.androidintentservice;

import android.os.Bundle;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity {

 TextView textResult;
 ProgressBar progressBar;
 
 private MyBroadcastReceiver myBroadcastReceiver;
 private MyBroadcastReceiver_Update myBroadcastReceiver_Update;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  textResult = (TextView)findViewById(R.id.result);
  progressBar = (ProgressBar)findViewById(R.id.progressbar);

  //prepare MyParcelable passing to intentMyIntentService
  String msgToIntentService = "Android-er";

  //Start MyIntentService
  Intent intentMyIntentService = new Intent(this, MyIntentService.class);
  intentMyIntentService.putExtra(MyIntentService.EXTRA_KEY_IN, msgToIntentService);
  startService(intentMyIntentService);
  
  myBroadcastReceiver = new MyBroadcastReceiver();
  myBroadcastReceiver_Update = new MyBroadcastReceiver_Update();
  
  //register BroadcastReceiver
  IntentFilter intentFilter = new IntentFilter(MyIntentService.ACTION_MyIntentService);
  intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
  registerReceiver(myBroadcastReceiver, intentFilter);
  
  IntentFilter intentFilter_update = new IntentFilter(MyIntentService.ACTION_MyUpdate);
  intentFilter_update.addCategory(Intent.CATEGORY_DEFAULT);
  registerReceiver(myBroadcastReceiver_Update, intentFilter_update);
 }
 
 @Override
 protected void onDestroy() {
  super.onDestroy();
  //un-register BroadcastReceiver
  unregisterReceiver(myBroadcastReceiver);
  unregisterReceiver(myBroadcastReceiver_Update);
 }

 public class MyBroadcastReceiver extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {
   String result = intent.getStringExtra(MyIntentService.EXTRA_KEY_OUT);
   textResult.setText(result);
  }
 }
 
 public class MyBroadcastReceiver_Update extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {
   int update = intent.getIntExtra(MyIntentService.EXTRA_KEY_UPDATE, 0);
   progressBar.setProgress(update);
  }
 }

}


activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />
    <TextView
        android:id="@+id/result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <ProgressBar
        android:id="@+id/progressbar"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        style="?android:attr/progressBarStyleHorizontal"
        android:max="10"
        android:progress="0"/>

</LinearLayout>


Need to include <service> of "MyIntentService" in AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.androidintentservice"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.androidintentservice.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name="com.example.androidintentservice.MyIntentService"></service>
    </application>

</manifest>



download filesDownload the files.

Related:
- Generate Notification in IntentService


7 comments:

Unknown said...

Excellent example - clarifies a lot of broadcast concepts.

Just a little issue: While unrigestering the broadcasts in onDestroy() may work for this example, the whole purpose of services is that it can run even when the activity isn't running.

Also this interesting info: You can start multiple intents and they will execute serially; the updates would stack in a FIFO queue and update the database in the sequence of submission. IntentServices stop themselves, so your app can exit and they will keep running. 

Keep up the good work!

Erik said...

Hello Dirk Bertels,

Thanks for your comment:)

wasim said...

hey
can you tell me how i can pass that data to fragment ?
i mean i want broadcasted data in fragment, for example - i have A activity which hold 2 fragments fragment B > c. so how can i pass data to fragment c ?

Anonymous said...

Works fine !
Thanks for the nice example...

Faiz said...

Hello I have a basic question, will the app crash if sendBroadcast() is called after unregisterReceiver() is called?

Unknown said...

does it restart the main activity if i want to send data from service every second? please help me...

Frank said...

took a few minutes to understand this code but in no time i had it working! thanks man :)