Friday, March 15, 2013

How to use IntentSerivce with Broadcast Receiver Android (Flickr Feed)


IntentService is similar solution like AysnTask, but it's purpose is meant for background process like downloading, uploading, or other blocking operations that don't need user interaction to transform this idea into the real so I created the example of flickr feeds to do download operation in background with Broadcast Receiver.

This is how my DownloadService class look like.

DownloadService.java

public class DownloadService extends IntentService {

  private String requestType;

  public DownloadService() {
    super("DownloadService");
  // TODO Auto-generated constructor stub
  }
  
  @Override
  protected void onHandleIntent(Intent intent) {
     
    // TODO Auto-generated method stub
    Bundle bundle = intent.getBundleExtra(AppConstants.FLICKR_BUNDLE);
    requestType = bundle.getString(AppConstants.REQUEST_TYPE);
    if(requestType.equals("FlickrFeeds")) {
        String urlpath = bundle.getString("urlpath");
        getFlickrFeed(urlpath);
    }
  } // onHanlderIntent

}

getFlickrFeed method i created to hit the GET request to flickr api to get feeds from flickr and send the response back to my broadcast receiver using sendBroadcast (Intent intent) method to handle and process it further to display in ListView.

private void getFlickrFeed(String url) {

  DefaultHttpClient httpClient = new DefaultHttpClient();
  HttpGet request = new HttpGet(url);
  String responseData = "";
  try {
   HttpResponse response = httpClient.execute(request);
   if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
    InputStream instream = response.getEntity().getContent();
    BufferedReader rd = new BufferedReader(new InputStreamReader(
      instream));
    StringBuilder total = new StringBuilder();
    String line;
    if (rd != null) {
     while ((line = rd.readLine()) != null) {
      total.append(line);
     }
    }
    // instream.close();
    responseData = total.toString();
    rd.close();
   } else {

    Log.w("HTTP1:", response.getStatusLine().getReasonPhrase());
    response.getEntity().getContent().close();
    throw new IOException(response.getStatusLine()
      .getReasonPhrase());
   }
  } catch (Exception e) {
   e.printStackTrace();
  }

  Intent broadcastIntent = new Intent();
  broadcastIntent.setAction(AppBroadCastReceiver.PROCESS_RESPONSE);
  broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);

  /* parepare bundle for broadcase */
  Bundle finishBundle = new Bundle();
  finishBundle.putString(AppConstants.RESPONSE_TYPE, "FlickrFeeds");
  finishBundle.putString(AppConstants.RESPONSE_DATA, responseData);
  broadcastIntent.putExtra(AppConstants.FLICKR_BUNDLE, finishBundle);
  sendBroadcast(broadcastIntent);
 }

Now our service class looks ready to hit the wall, Ahem!! Flickr :)
Not Finished Yet!! Its time to call this service from our Activity. As we following this example using BroadCastReceiver Class.

A broadcast receiver extends the BroadcastReceiver class and which is registered as a receiver in an Android Application via the AndroidManifest.xml file or dynamically via the Context.registerReceiver() method.

Alternatively to this static registration, you can also register a broadcast receiver dynamically via the Context.registerReceiver() method.

Note: If registering a receiver in your Activity.onResume() implementation, you should unregister it in Activity.onPause(). Otherwise the system will report a leaked broadcast receiver error. For instance if you registered a receive in in onResume() methods of your activity, you should unregister it in the onPause() by using Context.unregisterReceiver() method.

For retrieving flickr feeds I used Adeel Ansari Flickr PhotoStream.

MainActivity.java with nested AppBroadCastReceiver Code Snippet;

public class MainActivity extends FragmentActivity {
   AppBroadCastReceiver receiver;
   private static DataListFragment list;
   private Button loadFlickrBtn;
   // Adeel Ansari Flickr PhotoStream
   public static String flickrPath = "http://api.flickr.com/services/"
    +"feeds/photos_public.gne?id=47906772@N05&lang=en-us&format=json";

   /**
    * onCreate
    * 
    **/
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        System.out.println("MainActivity onCreate called ");
 }
    
    public void onClick(View view) {

       Intent msgIntent = new Intent(this, DownloadService.class);
       Bundle bundle = new Bundle();
       bundle.putString(AppConstants.REQUEST_TYPE, "FlickrFeeds");
       bundle.putString("urlpath", flickrPath);
       msgIntent.putExtra(AppConstants.FLICKR_BUNDLE, bundle);
       startService(msgIntent);
    }

    @Override
    protected void onResume() {
       // TODO Auto-generated method stub
       IntentFilter filter = new IntentFilter(
       AppBroadCastReceiver.PROCESS_RESPONSE);
       filter.addCategory(Intent.CATEGORY_DEFAULT);
       receiver = new AppBroadCastReceiver();
       registerReceiver(receiver, filter);
       System.out.println("MainActivity onResume called ");
       super.onResume();
    }

    @Override
    protected void onPause() {
       // TODO Auto-generated method stub
       super.onPause();
       System.out.println("MainActivity onPause Called");
       unregisterReceiver(receiver);
    }
}

In onClick method Activity send requests through startService(Intent) calls. The service is started and handle Intent in turn using a worker thread, and stops itself when it runs out of work.

Our Broadcast Receiver class with name AppBroadCastReceiver is defined as nested class in MainActivity.
When implementing a broadcast receiver you have to create a subclass of Android’s BroadcastReceiver and have to implement the onReceive() method.

Android calls the onReceive() method on all registered broadcast receivers whenever the event occurs or sendBroadcast() method allows you to send Intents to your registered receivers.

// nested AppBroadCastReceiver class 
public class AppBroadCastReceiver extends BroadcastReceiver {

  public static final String PROCESS_RESPONSE = Intent.ACTION_VIEW;
 
  @Override
  public void onReceive(Context context, Intent intent) {
   String response = null;
   Bundle receiveBundle = intent
       .getBundleExtra(AppConstants.FLICKR_BUNDLE);
   String responseType = receiveBundle
       .getString(AppConstants.RESPONSE_TYPE);
   System.out.println("onReceive " + responseType);
   if (responseType.equals("FlickrFeeds")) {
 /* Receiving Feeds from url */
 response = receiveBundle.getString(AppConstants.RESPONSE_DATA);
 response = fixJsonResult(response);
 ArrayList flickrFeedsList = parepareList(response);
 FragmentManager fm = getSupportFragmentManager();
 
 // Create the list fragment and add it as our sole content.
 list = new DataListFragment(flickrFeedsList);
 fm.beginTransaction().add(R.id.fragment_container, list)
 .commit();
 }
  }

  public String fixJsonResult(String json) {
   json = json.replace("jsonFlickrFeed(", "");
   json = json.replace("})", "}");
   return json;
  } // fixJsonResult

  private ArrayList parepareList(String response) {
  
   ArrayList flickrFeedsList = new ArrayList();

   try {
      if (response != null && response != "") {
        JSONObject jsonObj = new JSONObject(response);
          if (jsonObj.getJSONArray("items") != null) {
     JSONArray jobPosts = jsonObj.getJSONArray("items");
            
            for (int i = 0; i < jobPosts.length(); i++) {
              flickrFeedsList.add(new FlikrFeed(jobPosts
  .getJSONObject(i)));
            }
         }
       }
     } catch (JSONException e) {
        e.printStackTrace();
     }
     return flickrFeedsList;
  } // parepareList

} // AppBroadCastReceiver

In onReceive method this receive a json data fetch by service and displaying feeds in listView, I used DataListFragment class which extends ListFragment and prepare the result to view in the list.

App Screen Shots:


Download Source Code.: https://github.com/m-saifuddin/AndroidProjOne

Reference :
1) Android Service Tutorial by (By Lars Vogel)
2) Android Tutorial: BroadcastReceiver by Wolfram Rittmeyer

No comments: