• Android

    Android realtime chat dengan menggunakan Firebase Realtime Database

    Pada artikel kali ini, saya akan membuat realtime chat yang sederhana dengan menggunakan Firebase Realtime Database. Firebase Realtime Database adalah database yang di-host di cloud. Data disimpan sebagai JSON dan disinkronkan secara realtime ke setiap klien yang terhubung. Ketika membuat aplikasi cross-platform dengan SDK Android, iOS, dan JavaScript, semua klien akan berbagi sebuah instance Realtime Database dan menerima update data terbaru secara otomatis.

    Langkah pertama yang perlu dilakukan adalah membuat firebase project pada:

    https://console.firebase.google.com

    Setelah project berhasil dibuat, selanjutnya adalah membuat database pada firebase.

    Ganti permission pada database, dengan cara buka menu Develop > Database. Pada dropdown pilih Realtime Database kemudian klik tab Rules. Edit rules menjadi:

    {
      "rules": {
        ".read": true,
        ".write": true
      }
    }

    Langkah berikutnya adalah membuat Project baru pada Android Studio, dengan cara File -> New -> New Project.

    Pada aplikasi android yang dibuat, akan dibagi menjadi tiga halaman utama, yaitu halaman untuk join. Yang kedua adalah halaman untuk membuat room. Dan yang terakhir adalah halaman untuk chatting.

    Klik kanan pada project -> Activity -> Empty Activity. Kemudian beri nama JoinActivity.

    Jangan lupa jadikan JoinActivity ini menjadi main activity dengan cara buka AndroidManifest.xml. Tambahkan intent-filter pada konfigurasi JoinActivity.

    <activity
        android:name=".ui.login.LoginActivity"
        android:label="@string/title_activity_login">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    Buka JoinActivity kemudian buat kode seperti berikut ini:

    package org.akhal.example.qchat;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.TextView;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import com.google.firebase.database.ChildEventListener;
    import com.google.firebase.database.DataSnapshot;
    import com.google.firebase.database.DatabaseError;
    import com.google.firebase.database.DatabaseReference;
    import com.google.firebase.database.FirebaseDatabase;
    
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    
    public class ChatActivity extends AppCompatActivity {
    
        private Button btnSend;
        private EditText etMessage;
        private TextView tvMessage;
        private DatabaseReference rootDb;
        private String username, room;
        private String tempKey;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_chat);
    
            btnSend = findViewById(R.id.btn_send);
            etMessage = findViewById(R.id.et_message);
            tvMessage = findViewById(R.id.tv_message);
    
            QPrefs qPrefs = new QPrefs(this);
            username = qPrefs.getUsername();
            room = qPrefs.getRoom();
            setTitle("Room - "+room);
    
            rootDb = FirebaseDatabase.getInstance().getReference().child(room);
    
            btnSend.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
    
                    Map<String, Object> map = new HashMap<String, Object>();
                    tempKey = rootDb.push().getKey();
                    rootDb.updateChildren(map);
    
                    DatabaseReference msgRoot = rootDb.child(tempKey);
                    Map<String, Object> map2 = new HashMap<String, Object>();
                    map2.put("name",username);
                    map2.put("msg",etMessage.getText().toString());
                    msgRoot.updateChildren(map2);
                }
            });
    
            rootDb.addChildEventListener(new ChildEventListener() {
                @Override
                public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                    append_chat_conversatin(dataSnapshot);
                }
    
                @Override
                public void onChildChanged(DataSnapshot dataSnapshot, String s) {
                    append_chat_conversatin(dataSnapshot);
                }
    
                @Override
                public void onChildRemoved(DataSnapshot dataSnapshot) {
    
                }
    
                @Override
                public void onChildMoved(DataSnapshot dataSnapshot, String s) {
    
                }
    
                @Override
                public void onCancelled(DatabaseError databaseError) {
    
                }
            });
    
        }
    
        private void append_chat_conversatin(DataSnapshot dataSnapshot) {
            Iterator i = dataSnapshot.getChildren().iterator();
            while (i.hasNext()){
                String msg = (String) ((DataSnapshot)i.next()).getValue();
                String username = (String) ((DataSnapshot)i.next()).getValue();
                tvMessage.append(username + " : "+msg +"\n");
    
    
            }
        }
    }
    

    Untuk activiy_join.xml buat menjadi seperti berikut:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingBottom="@dimen/activity_vertical_margin">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:gravity="center"
            android:orientation="vertical">
    
            <EditText
                android:id="@+id/et_join"
                android:layout_width="300dp"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:hint="username"/>
    
            <Button
                android:id="@+id/btn_join"
                android:layout_marginTop="20dp"
                android:layout_width="200dp"
                android:layout_height="wrap_content"
                android:text="Join"/>
    
        </LinearLayout>
    </LinearLayout>

    Kemudian buka MainActivity dan tambahkan kode sehingga menjadi seperti di bawah ini:

    package org.akhal.example.qchat;
    
    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.ArrayAdapter;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.ListView;
    import android.widget.TextView;
    import androidx.appcompat.app.AppCompatActivity;
    import com.google.firebase.database.DataSnapshot;
    import com.google.firebase.database.DatabaseError;
    import com.google.firebase.database.DatabaseReference;
    import com.google.firebase.database.FirebaseDatabase;
    import com.google.firebase.database.ValueEventListener;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;
    
    public class MainActivity extends AppCompatActivity {
    
        private Button btnRoom;
        private EditText etRoom;
        private ListView lvRoom;
        private Context context;
        private DatabaseReference dbRoot = FirebaseDatabase.getInstance().getReference().getRoot();
        private ArrayAdapter<String> arrayAdapter;
        private ArrayList<String> list_of_rooms = new ArrayList();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            context = this;
            btnRoom = findViewById(R.id.btn_room);
            etRoom = findViewById(R.id.et_room);
            lvRoom = findViewById(R.id.lv_room);
    
            arrayAdapter = new ArrayAdapter<String>(context,android.R.layout.simple_list_item_1,list_of_rooms);
            lvRoom.setAdapter(arrayAdapter);
    
            btnRoom.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Map<String, Object> map = new HashMap<String, Object>();
                    map.put(etRoom.getText().toString(),"");
                    dbRoot.updateChildren(map);
                }
            });
    
            dbRoot.addValueEventListener(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    Set<String> set = new HashSet<String>();
                    Iterator i = dataSnapshot.getChildren().iterator();
                    while ( i.hasNext()) {
                        set.add(((DataSnapshot)i.next()).getKey());
                    }
                    list_of_rooms.clear();
                    list_of_rooms.addAll(set);
                    arrayAdapter.notifyDataSetChanged();
                }
    
                @Override
                public void onCancelled(DatabaseError databaseError) {
    
                }
            });
    
            lvRoom.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                    QPrefs qPrefs = new QPrefs(context);
                    qPrefs.setRoom(((TextView)view).getText().toString());
                    Intent I = new Intent(getApplicationContext(), ChatActivity.class);
                    startActivity(I);
                }
            });
    
        }
    }
    

    Untuk activity_main.xml menjadi seperti berikut:

    <?xml version="1.0" encoding="utf-8"?>
    <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">
    
        <ListView
            android:id="@+id/lv_room"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_alignParentRight="true"
            android:layout_alignParentEnd="true"
            android:layout_above="@+id/et_room">
        </ListView>
    
        <EditText
            android:id="@+id/et_room"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentStart="true"
            android:layout_toStartOf="@+id/btn_room"
            android:layout_alignParentLeft="true"
            android:layout_toLeftOf="@+id/btn_room" />
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Room"
            android:id="@+id/btn_room"
            android:layout_gravity="right"
            style="?android:attr/borderlessButtonStyle"
            android:layout_alignParentBottom="true"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:drawableLeft="@drawable/ic_add_black_24dp" />
    </RelativeLayout>
    

    Halaman terakhir adalah ChatActivity. Buat ChatActivity kemudian ganti code menjadi seperti berikut ini:

    package org.akhal.example.qchat;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.TextView;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import com.google.firebase.database.ChildEventListener;
    import com.google.firebase.database.DataSnapshot;
    import com.google.firebase.database.DatabaseError;
    import com.google.firebase.database.DatabaseReference;
    import com.google.firebase.database.FirebaseDatabase;
    
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    
    public class ChatActivity extends AppCompatActivity {
    
        private Button btnSend;
        private EditText etMessage;
        private TextView tvMessage;
        private DatabaseReference rootDb;
        private String username, room;
        private String tempKey;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_chat);
    
            btnSend = findViewById(R.id.btn_send);
            etMessage = findViewById(R.id.et_message);
            tvMessage = findViewById(R.id.tv_message);
    
            QPrefs qPrefs = new QPrefs(this);
            username = qPrefs.getUsername();
            room = qPrefs.getRoom();
            setTitle("Room - "+room);
    
            rootDb = FirebaseDatabase.getInstance().getReference().child(room);
    
            btnSend.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
    
                    Map<String, Object> map = new HashMap<String, Object>();
                    tempKey = rootDb.push().getKey();
                    rootDb.updateChildren(map);
    
                    DatabaseReference msgRoot = rootDb.child(tempKey);
                    Map<String, Object> map2 = new HashMap<String, Object>();
                    map2.put("name",username);
                    map2.put("msg",etMessage.getText().toString());
                    msgRoot.updateChildren(map2);
                }
            });
    
            rootDb.addChildEventListener(new ChildEventListener() {
                @Override
                public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                    append_chat_conversatin(dataSnapshot);
                }
    
                @Override
                public void onChildChanged(DataSnapshot dataSnapshot, String s) {
                    append_chat_conversatin(dataSnapshot);
                }
    
                @Override
                public void onChildRemoved(DataSnapshot dataSnapshot) {
    
                }
    
                @Override
                public void onChildMoved(DataSnapshot dataSnapshot, String s) {
    
                }
    
                @Override
                public void onCancelled(DatabaseError databaseError) {
    
                }
            });
    
        }
    
        private void append_chat_conversatin(DataSnapshot dataSnapshot) {
            Iterator i = dataSnapshot.getChildren().iterator();
            while (i.hasNext()){
                String msg = (String) ((DataSnapshot)i.next()).getValue();
                String username = (String) ((DataSnapshot)i.next()).getValue();
                tvMessage.append(username + " : "+msg +"\n");
    
    
            }
        }
    }
    

    Dan activity_chat.xml menjadi seperti berikut:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        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"
        android:weightSum="1">
    
        <ScrollView
            android:id="@+id/sv_message"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:layout_alignParentTop="true"
            android:layout_alignParentStart="true"
            android:layout_alignParentLeft="true">
    
            <TextView
                android:id="@+id/tv_message"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceMedium" />
        </ScrollView>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:weightSum="1">
            <EditText
                android:id="@+id/et_message"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignTop="@+id/button"
                android:layout_alignParentStart="true"
                android:layout_toStartOf="@+id/button"
                android:layout_weight="1"
                android:layout_alignParentLeft="true"
                android:layout_toLeftOf="@+id/button" />
    
            <Button
                android:id="@+id/btn_send"
                android:layout_width="56dp"
                android:layout_height="wrap_content"
                style="?android:attr/borderlessButtonStyle"
                android:drawableLeft="@drawable/ic_send_black_24dp"
                android:layout_alignParentBottom="true"
                android:layout_alignParentEnd="true"
                android:layout_alignParentRight="true" />
    
        </LinearLayout>
    
    </LinearLayout>
    

    Langkah terakhir adalah membuat shared preferences. Shared preferences digunakan untuk menyimpan username yang digunakan dan room yang dipilih. Buat file dengan nama QPrefs.

    package org.akhal.example.qchat;
    
    import android.content.Context;
    import android.content.SharedPreferences;
    
    /**
     * Created by Akhal on 2020/06/3.
     */
    public class QPrefs {
    
        private SharedPreferences pref;
    
        public QPrefs(Context context) {
            pref = context.getSharedPreferences("qpref", context.MODE_PRIVATE);
        }
    
        public void setUsername(String username) {
            pref.edit().putString("username", username).commit();
        }
    
        public String getUsername() {
            return  pref.getString("username", "");
        }
    
        public void setRoom(String room) {
            pref.edit().putString("room", room).commit();
        }
    
        public String getRoom() {
            return  pref.getString("room", "");
        }
    }
    

    Jika sudah selesai, jalankan aplikasi yang dibuat.

  • Android

    Android Bounce Animation

    Buat android project.

    Langkah selanjutnya adalah membuat layout dengan menggunakan ImageButton.

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <ImageButton
            android:id="@+id/ibtn_book"
            android:layout_width="180dp"
            android:layout_height="180dp"
            android:background="@null"
            android:scaleType="fitCenter"
            android:src="@drawable/img_book"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </android.support.constraint.ConstraintLayout>

    Buat transisi untuk bounce.

    • Klik kanan pada res, kemudian buat folder anim.
    • Untuk membuat animasi yang berjalan terus menerus, tambahkan atribut android:repeatCount="infinite" pada elemen <scale>.
    • Buat file bounce.xml, kemudian tambahkan code berikut:
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android" >
        <scale
            android:duration="2000"
            android:fromXScale="0.4"
            android:toXScale="1.0"
            android:fromYScale="0.4"
            android:toYScale="1.0"
            android:pivotX="50%"
            android:pivotY="50%" />
    </set>

    Buat class QBounceInterpolator.java sebagai interpolator pada animasi yang akan dibuat.

    package org.akhal.example.buttonanimation;
    
    import android.view.animation.Interpolator;
    
    public class QBounceInterpolator implements Interpolator {
        private double mAmplitude = 1;
        private double mFrequency = 10;
    
        public QBounceInterpolator(double amplitude, double frequency) {
            mAmplitude = amplitude;
            mFrequency = frequency;
        }
    
        public float getInterpolation(float time) {
            return (float) (-1 * Math.pow(Math.E, -time/ mAmplitude) *
                    Math.cos(mFrequency * time) + 1);
        }
    }

    Agar menjadi animasi, tambahkan code AnimationUtils pada MainActivity.java sehingga menjadi superti berikut:

    package org.akhal.example.buttonanimation;
    
    import android.content.Context;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.view.animation.Animation;
    import android.view.animation.AnimationUtils;
    import android.widget.ImageButton;
    
    public class MainActivity extends AppCompatActivity {
    
        private Animation bounceAnimation;
        private Context context;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            bounceAnimation = AnimationUtils.loadAnimation(this, R.anim.bounce);
            QBounceInterpolator interpolator = new QBounceInterpolator(0.2, 20);
            bounceAnimation.setInterpolator(interpolator);
    
            final ImageButton imageButton = findViewById(R.id.ibtn_book);
            imageButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    imageButton.startAnimation(bounceAnimation);
                }
            });
    
            imageButton.startAnimation(bounceAnimation);
        }
    }

    Jalankan aplikasi, sehingga nampak seperti gambar berikut ini:

    Untuk program lengkapnya, dapat diunduh di link di bawah ini:

  • Android

    BottomAppBar

    Salah satu komponen yang diperkenalkan pada acara Google I/O 2018 atalha BottomAppBar yang merupakan extension dari Toolbar yang peletakannya berada pada bagana bawah jendela aplikasi. Bersaam dengan BottomAppBar penempatan Floating Action Button (FAB) juga telah berubah. Dengan dessin baru, FAB data ditempatkan pada posisi yang bervariasi. Pada artikel kali ini, akan ditunjukkan bagaimana cara menggunakan material BottomAppBar pada sebuah layout.

    Langkah pertama adalah buat project baru.

    Tambahkan dependency pada file build.gradle.

    implementation 'com.android.support:design:28.0.0'

    untuk AndroidX

    implementation 'com.google.android.material:material:1.0.0'

    Langkah selanjutnya adalah membuat layout.

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <android.support.design.bottomappbar.BottomAppBar
            android:id="@+id/bottom_appbar"
            android:layout_gravity="bottom"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:navigationIcon="@drawable/ic_menu_black"
            style="@style/Widget.MaterialComponents.BottomAppBar.Colored">
    
        </android.support.design.bottomappbar.BottomAppBar>
    
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/floating"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/ic_camera_alt_black"
            app:backgroundTint="@color/colorPrimary"
            app:fabSize="normal"
            app:layout_anchor="@id/bottom_appbar" />
    
    </android.support.design.widget.CoordinatorLayout>

    Langah berikutnya adalah membuat file menu dengan nama file bottomappbar_menu.xml.

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <item
    android:id="@+id/app_bar_share"
    android:icon="@drawable/ic_share_black"
    android:title="Share"
    app:showAsAction="ifRoom"/>

    <item
    android:id="@+id/app_bar_favorite"
    android:icon="@drawable/ic_favorite_black"
    android:title="Favorite"
    app:showAsAction="ifRoom"/>
    </menu>

    Untuk menangani tombol ketika diklik, buat beberapa tambahan program pada file activity.

    package org.akhal.example.bottomappbar;
    
    import android.content.Context;
    import android.os.Bundle;
    import android.support.design.bottomappbar.BottomAppBar;
    import android.support.design.widget.FloatingActionButton;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.Toolbar;
    import android.view.MenuItem;
    import android.view.View;
    import android.widget.Toast;
    
    public class MainActivity extends AppCompatActivity {
    
        private BottomAppBar bottomAppBar;
        private FloatingActionButton fab;
        private Context context;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            context = this;
            bottomAppBar = findViewById(R.id.bottom_appbar);
            bottomAppBar.replaceMenu(R.menu.bottomappbar_menu);
    
            bottomAppBar.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context, "On click menu!", Toast.LENGTH_SHORT).show();
                }
            });
    
            fab = findViewById(R.id.floating);
            fab.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context, "On click camera!", Toast.LENGTH_SHORT).show();
                }
            });
    
            bottomAppBar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem menuItem) {
                    int item = menuItem.getItemId();
                    switch (item)  {
                        case R.id.app_bar_share:
                            Toast.makeText(context, "On click share!", Toast.LENGTH_SHORT).show();
                            break;
                        case R.id.app_bar_favorite:
                            Toast.makeText(context, "On click favorite!", Toast.LENGTH_SHORT).show();
                            break;
    
                    }
                    return false;
                }
            });
    
        }
    }




  • Android

    ListView on ScrollView

    Buat custom ListView tanpa fitur scroll.

    package al.akh.example.testing.view;
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.ViewGroup;
    import android.widget.ListView;
    
    public class ListViewNonScroll extends ListView {
    
        public ListViewNonScroll(Context context) {
            super(context);
        }
        public ListViewNonScroll(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
        public ListViewNonScroll(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
        @Override
        public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int heightMeasureSpec_custom = MeasureSpec.makeMeasureSpec(
                    Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
            super.onMeasure(widthMeasureSpec, heightMeasureSpec_custom);
            ViewGroup.LayoutParams params = getLayoutParams();
            params.height = getMeasuredHeight();
        }
    }

     

    Pada layout resource file, gunakan custom ListView yang telah dibuat di atas.

    <?xml version="1.0" encoding="utf-8"?>
    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fadingEdgeLength="0dp"
        android:fillViewport="true"
        android:overScrollMode="never"
        android:scrollbars="none" >
    
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content" >
    
            <al.akh.example.testing.view.ListViewNonScroll
                android:id="@+id/list_view"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/ >
    
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@+id/list_view" >
                ...
            </RelativeLayout>
        </RelativeLayout>
    
    </ScrollView>
  • Android

    Custom ActionBar on Android

    Buat activity untuk ActionBar. Misal saya beri nama custom_actionbar_center.xml.

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:background="@android:color/transparent">
    
        <TextView
            android:id="@+id/title_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:textSize="25sp"
            android:textColor="#fff"
            android:gravity="center"
            android:text="title"
            />
    
        <ImageButton
            android:id="@+id/ibtn_bluetooth"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginRight="15dp"
            android:layout_alignParentRight="true"
            android:foregroundGravity="center"
            android:background="@null"
            android:src="@drawable/ic_settings_white_32dp" />
    
    </RelativeLayout>

    Tambahkan code berikut pada activity

    ActionBar mActionBar = getSupportActionBar();
    assert mActionBar != null;
    mActionBar.setDisplayShowHomeEnabled(false);
    mActionBar.setDisplayShowTitleEnabled(false);
    LayoutInflater mInflater = LayoutInflater.from(this);
    View actionBar = mInflater.inflate(R.layout.custom_actionbar_center, null);
    TextView mTitleTextView = actionBar.findViewById(R.id.title_text);
    mTitleTextView.setText(R.string.app_name);
    mActionBar.setCustomView(actionBar);
    mActionBar.setDisplayShowCustomEnabled(true);
    ((Toolbar) actionBar.getParent()).setContentInsetsAbsolute(0,0);
    

    Jika ingin menghilangkan shadow di bawah ActionBar, tambahkan code berikut pada activity:

    getSupportActionBar().setElevation(0);
  • Android

    apache2: Could not reliably determine the server’s fully qualified domain name

    Ada yang pernah mencoba menjalankan ubuntu di perangkat android? Mungkin teman-teman yang pernah mencobanya mengalami masalah yang sama dengan yang saya alami. ketika  mencoba menginstall lamp server, muncul error “AH00558: apache2: Could not reliably determine the server’s fully qualified domain name, using ::1. Set the ‘ServerName’ directive globally to suppress this message” ketika akan menjalankan apache server.

    Solusi:
    tambahkan ServerName pada /etc/apache2/apache2.conf.

    sudo nano /etc/apache2/apache2.conf

    Pada contoh ini saya tambahkan dibawah Global configuration.

    # Global configuration
    #
    ServerName localhost

    Langkah selanjutnya, restart apache2.

    sudo service apache2 restart
  • Android

    No directory, logging in with HOME=/

    Ada yang pernah mencoba menjalankan ubuntu di perangkat android? Mungkin teman-teman yang pernah mencobanya mengalami masalah yang sama dengan yang saya alami. ketika  mencoba menginstall lamp server, muncul error “No directory, logging in with HOME=/” ketika akan menjalankan mysql server. Hal ini mungkin disebabkan karena kernel android dicompile dengan konfigurasi CONFIG_ANDROID_PARANOID_NETWORK. Masalah ini dapat diperbaiki dengan menambahkan mysql user pada aid_inet dan aid_net_raw groups.

    usermod -a -G aid_inet,aid_net_raw mysql
    su mysql
    

    Langkah selanjutnya tinggal menjalankan mysql.

    sudo service mysql start
  • Android

    Simpan Layout sebagai Image

       

     

    Ketika kita membuat suatu aplikasi, terkadang membutuhkan dokumentasi berupa gambar (image).

    Berikut adalah salah satu cara untuk membuat image dari layout yang telah dibuat.

    Buat method untuk konversi dari view ke bitmap:

    private Bitmap getBitmap(View view) {
        view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
        view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
        view.buildDrawingCache(true);
        Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
    
        Drawable background =view.getBackground();
        if (background!=null) {
            background.draw(canvas);
        }else{
            canvas.drawColor(Color.WHITE);
        }
        view.draw(canvas);
        
        return bitmap;
    }

    Buat method untuk simpan ke dalam bentuk file:

    public void save(Bitmap image, String path) {
        try {
            FileOutputStream output = new FileOutputStream(path);
            image.compress(Bitmap.CompressFormat.PNG, 100, output);
            output.close();
            Toast.makeText(context,"File berhasil disimpan di: "+path+".",Toast.LENGTH_LONG).show();
        } catch (FileNotFoundException e) {
    //        e.printStackTrace();
            Log.e(TAG, e.toString());
            Toast.makeText(context,"Gagal menyimpan file.",Toast.LENGTH_LONG).show();
        } catch (IOException e) {
    //        e.printStackTrace();
            Log.e(TAG, e.toString());
            Toast.makeText(context,"Gagal menyimpan file.",Toast.LENGTH_LONG).show();
        }
    }
    

    Panggil method yang telah dibuat:

    image = getBitmap(layout);

    Buat fungsi untuk menyimpan image:

    btnSave.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            String path = Environment.getExternalStorageDirectory()+"/image.png";
            save(image, path);
        }
    });
     Buat fungsi untuk menampilkan image:
    btnView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            bmImage.setImageBitmap(image);
        }
    });
    

     

    Source code:
    download

  • Android

    Custom Color Listview Selected

    Pada res, buat file color_selector.xml

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_pressed="true" android:color="#04b3d3" />
        <item android:state_selected="true" android:color="#048563" />
        <item android:color="#04b3d3" />
    </selector>

    Pada textview property, tambahkan android:textColor=”@color/color_selector”.

    <TextView
        android:id="@+id/tv_list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/color_selector"/>

    Pada program java, tambahkan view.setSelected(true);.

    list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            view.setSelected(true);
        }
    });

     

  • Android

    Android TimerTask

    Pada kali ini akan dicontohkan penggunaan Timer dan TimerTask untuk sekali perhitungan timer maupun timer yang berulang-ulang (repeat) pada jeda waktu tertentu.

    Buat variabel yang diperlukan pada program java.

    private Timer timer;
    private TimerTask timerTask;

    Buat method startTimer(int time). Method ini digunakan untuk perhitungan timer yang bersifat sekali jalan.

    private void startTimer(int time) {
        stopTimer();
        timer = new Timer();
        initTimerTask();
        timer.schedule(timerTask,time);
    }

    Buat method startRepeatTimer(int time). Method ini digunakan untuk perhitungan timer yang berulang-ulang (repeat).

    private void startRepeatTimer(int time) {
        stopTimer();
        timer = new Timer();
        initTimerTask();
        timer.schedule(timerTask,time,time);
    }

    Buat method stopTimer();

    private void stopTimer() {
        if(timer != null) {
        timer.cancel();
        timer = null;
    }

    Buat method initTimerTask();

    private void initTimerTask() {
        timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("On Timer.");
            }
        };
    }

    Untuk menjalankan timer, tinggal panggil method startTimer(int timer) atau method startRepeatTImer(int timer).

     

    Gunakan Handler jika ingin menampilkan data pada TextView maupun sejenisnya.

    Buat object dari class Handler.

    Handler timerHandler;
    timerHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0:
                    textView.setText(msg.obj);
                    break;
                default:
                    break;
            }
        }
    };

    Gunakan sendMessage untuk menampilkan data.

    private void initTimerTask() {
        timerTask = new TimerTask() {
            @Override
            public void run() {
                Message msg = Message.obtain(null,0,"On Timer.");
                timerHandler.sendMessage(msg);
            }
        };
    }

     

    Source code:
    donwload