Pages

Wednesday, May 28, 2014

Android Background Service, Contoh Penggunaan IntentService

Android Platform

Kebanyakan proses yang terjadi pada suatu aplikasi Android berjalan pada layer teratas (Foreground), berjalan diatas spesial Thread yang disebut UI Thread atau Main Thread. Hal ini dapat menyebabkan masalah jika suatu aplikasi harus menjalankan proses yang lama (long-running operations) pada UI Thread, karena hal tersebut dapat menganggu kecepatan UI suatu aplikasi, bahkan dapat menyebabkan System error. Untuk menghindari masalah tersebut android telah menyediakan beberapa class yang dapat menjalankan suatu proses pada thread terpisah dan berjalan pada background aplikasi. Salah satu class tersebut adalah IntentService.


Dibawah ini merupakan contoh penggunaan IntentService pada pemrograman android. Pertama sebuah Activity (MainActivity.java) akan mengambil referensi terhadap file .txt dari system, kemudian Activity tersebut akan mengirimkan path absoluth sebagai String kepada sebuah IntentService (Services.java). IntentService akan membaca file tersebut kemudian mengembalikan isi file sebagai String ke Activity, selanjutnya Activity akan menampilkan isi file yang diterima dari IntentService pada sebuah TextView. Berikut source code nya:

src/com.me.intentservicesample/MainActivity.java
package com.me.intentservicesample;

import java.net.URISyntaxException;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {

 private static final int REQ_CODE = 0;
 //private ResponseReciever mResponseReciever = new ResponseReciever();
 
 private BroadcastReceiver reciever = new BroadcastReceiver() {
  
  @Override
  public void onReceive(Context context, Intent intent) {
   // TODO Auto-generated method stub
   Bundle bundle = intent.getExtras();
   if (bundle != null) {
    String data = bundle.getString(Services.DATA);
    int status = bundle.getInt(Services.STATUS);
    if (status == RESULT_OK) {
     //MainActivity mainActivity = new MainActivity();
     Toast.makeText(MainActivity.this, "Finished",
       Toast.LENGTH_LONG).show();
     updateTextView(data);
    }
   }
  }
 };

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);

  setContentView(R.layout.activity_main);

  if (savedInstanceState == null) {
   getSupportFragmentManager().beginTransaction()
     .add(R.id.container, new PlaceholderFragment()).commit();
  }
 }

 @Override
 protected void onResume() {
  super.onResume();
  IntentFilter intentFilter = new IntentFilter(Services.ACTION_BROADCAST);
  //intentFilter.addDataScheme("text/plain");
  
  LocalBroadcastManager.getInstance(MainActivity.this).registerReceiver(
    reciever, intentFilter);
 }

 @Override
 protected void onPause() {
  super.onPause();
  LocalBroadcastManager.getInstance(MainActivity.this)
    .unregisterReceiver(reciever);
 }
 
 /**
 private class ResponseReciever extends BroadcastReceiver {

  @Override
  public void onReceive(Context ctx, Intent intent) {
   // TODO Auto-generated method stub
   Bundle bundle = intent.getExtras();
   if (bundle != null) {
    String data = bundle.getString(Services.DATA);
    int status = bundle.getInt(Services.STATUS);
    if (status == RESULT_OK) {
     //MainActivity mainActivity = new MainActivity();
     Toast.makeText(MainActivity.this, "Finished",
       Toast.LENGTH_LONG).show();
     //mainActivity.updateTextView(data);
    }
   }

  }

 }
 */

 protected void updateTextView(String data) {
  TextView tv = (TextView) findViewById(R.id.textView);
  tv.setText(data.toString());
 }

 /** called when button "Open a File" clicked */
 public void openFile(View v) {

  // use implicit Intent to open a file
  Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
  intent.setType("*/.txt");
  intent.addCategory(Intent.CATEGORY_OPENABLE);

  try {
   startActivityForResult(
     Intent.createChooser(intent, "Select a file txt"), REQ_CODE);
  } catch (android.content.ActivityNotFoundException ex) {
   Toast.makeText(getBaseContext(), "You a need a File Manager",
     Toast.LENGTH_LONG).show();
   ex.printStackTrace();
  }
 }

 @Override
 protected void onActivityResult(int reqCode, int resultCode, Intent data) {

  // check activity result base on reqCode
  // reqCode must be same as REQ_CODE
  switch (reqCode) {
  case REQ_CODE:
   if (resultCode == RESULT_OK) {

    // get Uri data from intent
    Uri uri = data.getData();

    String path = null;
    try {

     // convert Uri to file path (String)
     path = getPath(getBaseContext(), uri);

     // send the file path to Service
     this.sendToService(path);
    } catch (URISyntaxException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }
 }

 /** called to start the Service */
 private void sendToService(String s) {

  // create an explicit Intent for the Service
  Intent intentService = new Intent(MainActivity.this, Services.class);
  intentService.putExtra(Services.PATH, s);
  startService(intentService);
 }

 public static String getPath(Context context, Uri uri)
   throws URISyntaxException {
  if ("content".equalsIgnoreCase(uri.getScheme())) {
   String[] projection = { "_data" };
   Cursor cursor = null;

   try {
    cursor = context.getContentResolver().query(uri, projection,
      null, null, null);
    int column_index = cursor.getColumnIndexOrThrow("_data");
    if (cursor.moveToFirst()) {
     return cursor.getString(column_index);
    }
   } catch (Exception e) {
    e.printStackTrace();
   }
  } else if ("file".equalsIgnoreCase(uri.getScheme())) {
   return uri.getPath();
  }

  return null;
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {

  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  // Handle action bar item clicks here. The action bar will
  // automatically handle clicks on the Home/Up button, so long
  // as you specify a parent activity in AndroidManifest.xml.
  int id = item.getItemId();
  if (id == R.id.action_settings) {
   return true;
  }
  return super.onOptionsItemSelected(item);
 }

 /**
  * A placeholder fragment containing a simple view.
  */
 public static class PlaceholderFragment extends Fragment {

  public PlaceholderFragment() {
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
    Bundle savedInstanceState) {
   View rootView = inflater.inflate(R.layout.fragment_main, container,
     false);
   return rootView;
  }
 }

}

src/com.me.intentservicesample/Services.java
package com.me.intentservicesample;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import android.app.Activity;
import android.app.IntentService;
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;

public class Services extends IntentService {

 private static int mStatus = Activity.RESULT_CANCELED;
 public static final String PATH = "com.me.intentservicesample.PATH";
 public static final String ACTION_BROADCAST = "com.me.intentservicesample.BROADCAST";
 public static final String STATUS = "com.me.intentservicesample.STATUS";
 public static final String DATA = "com.me.intentservicesample.DATA";

 public Services() {
  super("Services");
  // TODO Auto-generated constructor stub
 }

 @Override
 protected void onHandleIntent(Intent intent) {
  // TODO Auto-generated method stub

  // get data from incoming intent
  String filePath = intent.getStringExtra(PATH);

  String fileContent = this.readFile(filePath);
  if (fileContent != null) {

   // report the work status to registered components
   publishResult(mStatus, fileContent);

  }
 }

 private void publishResult(int status, String data) {
  Intent localIntent = new Intent(Services.ACTION_BROADCAST);
  localIntent.putExtra(Services.STATUS, status);
  localIntent.putExtra(Services.DATA, data);
  LocalBroadcastManager.getInstance(Services.this).sendBroadcast(
    localIntent);
 }

 /** read the incoming file to get the file content as String */
 private String readFile(String path) {
  File file = new File(path);
  int i, j = 0;
  byte[] data = new byte[(int) file.length()];
  String string = null;
  InputStream in = null;
  try {
   in = new BufferedInputStream(new FileInputStream(file));
   while ((i = in.read()) != -1) {
    data[j++] = (byte) i;
   }
   string = byteToString(data).toString();
   mStatus = Activity.RESULT_OK;
   return string;
  } catch (FileNotFoundException ex) {
   ex.printStackTrace();
  } catch (IOException ex) {
   // TODO Auto-generated catch block
   ex.printStackTrace();
  } finally {
   if (in != null) {
    try {
     in.close();
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }
  return string;

 }

 /** called to cast byte array to String */
 private static String byteToString(byte[] b) {
  char[] c = new char[b.length];
  StringBuilder sb = new StringBuilder();

  for (int i = 0; i < c.length; i++) {
   c[i] = (char) b[i];
   sb.append(c[i]);
  }

  return sb.toString();
 }
}

res/layout/activity_main.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.me.intentservicesample.MainActivity"
    tools:ignore="MergeRootFrame" />


res/layout/fragment_main.xml
<RelativeLayout 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"
    tools:context="com.me.intentservicesample.MainActivity$PlaceholderFragment" >

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:onClick="openFile"
        android:text="Open a File" />

    <LinearLayout
        android:id="@+id/linear"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/button"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/textView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="10dp"
            android:singleLine="false"
            android:text="@string/hello_world" />
    </LinearLayout>

</RelativeLayout>

IntentServiceManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.me.intentservicesample"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="7"
        android:targetSdkVersion="19" />

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <service
            android:name="com.me.intentservicesample.Services"
            android:exported="false" >
        </service>

        <activity
            android:name="com.me.intentservicesample.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>
    </application>

</manifest>

Note: contoh aplikasi diatas membutuhkan sebuah File Manager dan sebuah file .txt yang akan dibaca oleh aplikasi.

Dibawah ini adalah tampilan aplikasi pada saat dijalankan.

Tampilan utama aplikasi:

Android Platform

Pada saat button "Open a File" di pilih:

Android Platform

Isi dari sebuah file .txt ditampilkan pada sebuah TextView:

Android Platform

Download: IntentServiceSample.apk (Apk file)

Source: Android Developer

No comments:

Post a Comment

Related Posts Plugin for WordPress, Blogger...