(Tutorial Android) Simplify Code with AndroidAnnotations

Wednesday, September 21, 2016

AndroidAnnotations adalah sebuah framework open source yang diklaim mampu mempercepat pengembangan aplikasi Android. Selain itu juga menulis code menjadi lebih simpel dan ringkas (less code) dan mudah untuk di-maintenance. AndroidAnnotations ini menggunakan annotations yang berfungsi menggantikan boilerplate code yang umum pada project Android.

Lalu, apa itu Annotation? Annotation adalah sebuah meta tag yang memberikan informasi tentang code program tetapi tidak berpenngaruh secara langsung pada code dan bukan bagian dari code program itu sendiri.

Beberapa fitur yang dimiliki oleh AndroidAnnotations :

- Dependency Injection : kita dapat menginjeksi pada kelas yang membutuhkan seperti inject views, extras, system services, resource dan lain-lain.
- Simplified threading model : annotation dapat digunakan untuk menjalankan method di UI thread maupun background thread.
- Event binding : Event handling menggunakan annotation.
- REST Client : Request ke REST cukup dengan membuat client interface.
- AndroidAnnotations akan mengenerate subsclasses pada saat compile.
- Size kurang dari 150kb !

Daftar annotation yang tersedia bisa dilihat di https://github.com/excilys/androidannotations/wiki/AvailableAnnotations 

Pada tutorial kali ini saya akan coba berbagi informasi sedikit tentang AndroidAnnotations.

Configuration

Langkah pertama adalah melakukan konfigurasi AndroidAnnotations dan library-library yang kita perlukan di gradle.

Top-level
dependencies {
    ...
    classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
Module-level
apply plugin: 'com.android.application'
apply plugin: 'android-apt'
def AAVersion = '4.1.0'
def AppVersion = '23.3.0'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"

    defaultConfig {
        applicationId "com.wimso.android_aa"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

repositories {
    mavenCentral()
    mavenLocal()
    maven {
        url 'https://repo.spring.io/libs-milestone'
    }
}
android {
    packagingOptions {
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/license.txt'
    }
}

apt {
    arguments {
        androidManifestFile variant.outputs[0]?.processResources?.manifestFile
        // if you have multiple outputs (when using splits), you may want to have other index than 0
        // you should set your package name here if you are using different application IDs
        // resourcePackageName "your.package.name"
        // You can set optional annotation processing options here, like these commented options:
        // logLevel 'INFO'
        // logFile '/var/log/aa.log'
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile "com.android.support:appcompat-v7:$AppVersion"
    compile "com.android.support:design:$AppVersion"
    compile "com.android.support:cardview-v7:$AppVersion"

    apt "org.androidannotations:androidannotations:$AAVersion"
    compile "org.androidannotations:androidannotations-api:$AAVersion"

    apt "org.androidannotations:rest-spring:$AAVersion"
    compile "org.androidannotations:rest-spring-api:$AAVersion"

    compile 'org.springframework.android:spring-android-rest-template:2.0.0.M3'
    compile 'com.google.code.gson:gson:2.7'
}

Creating Layout

Disini tidak ada yang berbeda ketika membuat layout, sama seperti membuat layout di Android pada umumnya. Buat sebuah layout dengan nama activity_main.xml. Tambahkan beberapa komponen seperti TextView, EditText dan Button.
<?xml version="1.0" encoding="utf-8"?>
<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:orientation="vertical"
    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.wimso.android_aa.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/post_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:hint="Post ID undefined1 - 100)"/>

        <Button
            android:id="@+id/btn_post"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="SHOW POST"/>

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="@dimen/activity_vertical_margin"
        android:orientation="vertical">

        <TextView
            android:id="@+id/post_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"/>

        <TextView
            android:id="@+id/post_body"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            android:textAppearance="?android:attr/textAppearanceSmall"/>

    </LinearLayout>


</LinearLayout>

Enhanced Activity and Injecting Views

Mendefinisikan layout pada Activity biasanya dengan cara memanggil method setContentView() yang ada di dalam method onCreate(). Nah, kalau di AndroidAnnotations cara mendefinisikannya dapat diringkas dengan menggunakan annotation @EActivity.

@EActivity : annotation yang menunjukkan bahwa suatu activity akan di enhanced oleh AndroidAnnotations.

Memanggil komponen tidak menggunakan findViewById seperti pada umumnya. Tapi dengan menginjeksi view menggunakan annotation @ViewById.

@ViewById : annotation yang menunjukkan injeksi dari component view pada layout.
 *Perlu diperhatikan bahwa ketika field disisipi annotation @ViewById ini field masih kosong dan field tidak boleh private.

Ketika onCreate() dipanggil, maka field @ViewById sebenarnya masih kosong, jadi kita dapat mengeset valuenya pada method yang ditambahin annotation @AfterViews.

@AfterViews : annotation yang menunjukkan bahwa method harus dipanggil setelah views binding. *yak, kurang lebih begitu :v

Tapi intinya, kita dapat mengeset value sebuah field dari @ViewById dengan cara memanggil annotation @AfterViews.

Berikut contohnya pada MainActivity :
@EActivity(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {

    @ViewById(R.id.post_text) EditText postText;
    @ViewById(R.id.post_title) TextView postTitle;
    @ViewById(R.id.post_body) TextView postBody;
    @RestService ApiService apiService;

    private ProgressDialog progressDialog;

    @AfterViews
    public void bindViews() {
        // Default Text
        postText.setText("1");
        progressDialog = new ProgressDialog(this);
        progressDialog.setMessage("Loading...");
        progressDialog.setCancelable(true);
    }
    
}

Event Binding

AndroidAnnotations menyediakan annotation untuk menhandel event listener. Contohnya untuk menhandel event click menggunakan annotation @Click.

@Click : annotation yang menunjukkan method di activity bisa memanggil event click pada view.

Contohnya penggunaannya :
@Click(R.id.btn_post)
void getPostClicked() {

   // do something
}

REST Client

Untuk melakukan request ke REST API yakni dengan membuat client interface. REST API dapat bekerja dengan annotation @Rest. Pada kasus ini kita menggunakan REST Client Spring Android  yang terintegrasi dengan AndroidAnnotations.

Contohnya :
@Rest(rootUrl = "https://jsonplaceholder.typicode.com", converters = { GsonHttpMessageConverter.class })
public interface ApiService {

    @Get("/posts/{id}")
    Post getPost(@Path String id);

}
rootUrl merupakan base url nya, sedangkan converters wajib di definisikan. Converters ini berfungsi menconvert hasil respon yang di dapat yang kemudian dapat di mapping. Pada contoh di atas kita menggunakan converter dari GSON.

Request ke REST API dapat berupa GET atau POST, gunakan @Get atau @Post untuk mendefinisikan sebuah request GET atau POST.

Background Task

Annotation @Background dan @UiThread dapat digunakan untuk menjalankan Background Task. Annotation @Background bekerja sama halnya seperti AsyncTask. Sedangkan @UiThread berjalan secara background untuk menangani jika ada perubahan pada UI.

@Background : annotation yang menunjukkan sebuah method berjalan di thread selain ui thread.
@UiThread : annotation yang menunjukkan sebuah method berjalan di thread ui.

Contoh penggunaan annotation @Background yaitu untuk melakukan proses request data ke REST API. Kemudian respon yang diterima di jalankan di @UiThread sehingga UI ter-update.
@Background
void requestPost(String id) {
    Post post = apiService.getPost(id);
    updateViews(post);
}

@UiThread
void updateViews(Post post) {
    progressDialog.dismiss();

    if(post == null) {
        Toast.makeText(this, "Cannot load data", Toast.LENGTH_SHORT).show();
        return;
    }

    postTitle.setText(post.getTitle());
    postBody.setText(post.getBody());
}
Nah setelah saya menjelaskan panjang lebar di atas, mari kita ke tahap implementasi selanjutnya.

Buat kelas POJOS sebagai berikut.
package com.wimso.android_aa.model;

/**
 * Created by Wim on 9/21/16.
 */
public class Post {

    private int userId;
    private int id;
    private String title;
    private String body;

    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }
}

Lengkapi source code MainActivity berikut :
package com.wimso.android_aa;

import android.app.ProgressDialog;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.wimso.android_aa.model.Post;
import com.wimso.android_aa.network.ApiService;

import org.androidannotations.annotations.AfterViews;
import org.androidannotations.annotations.Background;
import org.androidannotations.annotations.Click;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.UiThread;
import org.androidannotations.annotations.ViewById;
import org.androidannotations.rest.spring.annotations.RestService;

@EActivity(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {

    @ViewById(R.id.post_text) EditText postText;
    @ViewById(R.id.post_title) TextView postTitle;
    @ViewById(R.id.post_body) TextView postBody;

    @RestService ApiService apiService;

    private ProgressDialog progressDialog;

    @AfterViews
    public void bindViews() {
        // Default Text
        postText.setText("1");

        progressDialog = new ProgressDialog(this);
        progressDialog.setMessage("Loading...");
        progressDialog.setCancelable(true);
    }

    @Click(R.id.btn_post)
    void getPostClicked() {
        progressDialog.show();

        if(!TextUtils.isEmpty(postText.getText())) {
            requestPost(postText.getText().toString());
        }
    }

    @Background
    void requestPost(String id) {
        Post post = apiService.getPost(id);
        updateViews(post);
    }

    @UiThread
    void updateViews(Post post) {
        progressDialog.dismiss();

        if(post == null) {
            Toast.makeText(this, "Cannot load data", Toast.LENGTH_SHORT).show();
            return;
        }

        postTitle.setText(post.getTitle());
        postBody.setText(post.getBody());
    }

}
Setelah itu, Build → Make Project. Maka Android Studio akan men-generate kelas MainActivity menjadi subclass dengan nama MainActivity_. Setiap subclass memiliki nama yang sama dengan tambahan sufix _ (undescore).

Langkah terakhir adalah register MainActivity di AndroidManifest.xml. Activity yang diregister adalah subclassnya yang terdapat suffix _ (undescore).
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.wimso.android_aa">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity_">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
Selesai, build dan jalankan maka hasilnya sebagai berikut :


Source code lengkap dapat dilihat di https://github.com/wimsonevel/Android-AA

Sekian tutorial kali ini. Terima kasih sudah menyimak.
Semoga bermanfaat. :)

Share this :

Previous
Next Post »
0 Komentar

Penulisan markup di komentar
  • Silakan tinggalkan komentar sesuai topik. Komentar yang menyertakan link aktif, iklan, atau sejenisnya akan dihapus.
  • Untuk menyisipkan kode gunakan <i rel="code"> kode yang akan disisipkan </i>
  • Untuk menyisipkan kode panjang gunakan <i rel="pre"> kode yang akan disisipkan </i>
  • Untuk menyisipkan quote gunakan <i rel="quote"> catatan anda </i>
  • Untuk menyisipkan gambar gunakan <i rel="image"> URL gambar </i>
  • Untuk menyisipkan video gunakan [iframe] URL embed video [/iframe]
  • Kemudian parse kode tersebut pada kotak di bawah ini
  • © 2015 Simple SEO ✔

Ads