Intent dan Content Provider

Hai kembali lagi di blog saya malasnugas.com . kali ini saya akan membahas tentang intent dan Content provider pada android studio. simak baik-baik ya

Intent
Apa itu intents? Android menggunakan intents untuk melakukan pekerjaan tertentu di dalam aplikasinya. Begitu kita menguasai penggunaan intents, maka semua pengembangan aplikasi baru yang ada akan terbuka. Subbab ii mengungkap apa intents itu dan bagaimana dia digunakan. Intents adalah sebuah metode android untuk me-relay informasi tertentu dari satu aktivitas ke aktivitas lainnya. Secara lebih sederhana, Intents mengekspresikan kepada android keinginan kita untuk melakukan sesuatu. Kita bisa menganggap intent sebagai sebuah pesan yang dilewatkan diantara banyak aktivitas. Misalnya, mempunyai aktivitas yang mengharuskan untuk membuka web browser dan menampilkan sebuah halaman di perangkat android kita. Aktivitas kita akan mengirimkan “keinginan (intent) untuk membuka halaman x di web browser” yang dikenal dengan Intent WEB-SEARCH_ACTION, ke Android IntentResolver. IntentResolver mengurai melalui sebuah daftar Aktivitas dan memilih salah satu yang paling cocok dengan Intent kita; dalam hal ini adalah Web Browser Activity. Lalu Intent Resolver mengirimkan halaman kita ke web browser dan memulai Web Browser Activity.
Intent dipecah ke dalam dua kategori utama:
 Activity Action Intents: Intent yang duigunakan untuk memanggil Activity di luar aplikasi kita. Hanya satu Activity yang bisa ditangani oleh Intent. Misalnya saja untuk sebuah web browser, kita harus membuka Web Browser Activity untuk menampilkan halaman.
 Broadcast Intents: Intents yang dikirimkan untuk menangani lebih dari satu Activity. Contohnya, Broadcast intent yang akan menjadi sebuah pesan yang dikirimkan oleh Android mengenai tingkat baterei saat itu. Banyak aktivitas bisa memproses Intent ini dan melakukan reaksi yang sesuai – misalnya, membatalkan sebuah Activity bila tingkat baterei berada di bawah titik tertentu.

Content Provider
Sebuah content provider memasok data dari satu aplikasi ke aplikasi lain sesuai permintaan. Premintaan semacam itu ditangani oleh method class ContentResolver. Sebuah content provider bisa menggunakan cara yang berbeda untuk menyimpan datanya dan data itu bisa disimpan di dalam sebuah database, file, ataupun jaringan

Kadang-kadang data harus dishare dengan aplikasi lain. Disinilah pentingnya content provider.
Content provider memungkinkan anda untuk memusatkan konten di dalam satu tempat dan mempunyai banyak aplikasi berbeda yang bisa mengaksesnya sesuai kebutuhan. Content provider bertindak sangat mirip dengan database dimana dia bisa di-kueri, diedit, serta ditambah atau bahkan dihapus dengan menggunakan method insert(), update(), delete(), dan query(). Di dalam sebagian besar kasus data ini disimpan di dalam database Sqlite.
Content provider diimplementasikan sebagai sebuah subclass dari class ContentProvider dan harus mengimplementasikan set standard API yang memungkinkan aplikasi lain untuk melakukan transaksi. public class My Application extends ContentProvider { }
Content URIs
Untuk meng-query content provider harus menentukan query string dalam bentuk URI yang mengikuti format berikut: <prefix>://<authority>/<data_type>/<id>
Di bawah ini adalah detail dari berbagai bagian dari URI-- Part Description
prefix
Selalu diset ke content://
authority
ini menentukan nama content provider, misalnya contacts, browser dll. Untuk content provider pihak ketiga, dia bisa berupa fully qualified name, seperti com.tutorialspoint.statusprovider
data_type
Menunjukkan tipa data yang disediakan oleh provider tertentu. Misalnya, bila mengambil semua kontak dari provider Contactscontent, maka jalur datanya mungkin berupa people dan URInya munngkin akan menjadi seperti konten ini ://contacts/people
id
Menentukan rekaman tertentu yang diminta.. Misalnya, bila mencari kontak nomer 5 di dalam konten provider Contact maka URInya akan terlihat seperti://contacts/people/5.

Membuat Content Provider
Melibatkan sejumlah langkah sederhana untuk membuat content provider sendiri
 Pertama semua yang diperlukan untuk membuat sebuah class Content Provider yang mencakup theContentProviderbaseclass.
 Kedua, harus menentukan alamat URI konten provider yang akan digunakan untuk mengakses konten itu.
 Kemudian harus membuat database sendiri untuk menyimpan konten. Biasanya Android menggunakan database Sqlite dan kerangka kerja ke method overrideonCreate() yang akan menggunakan method SQLite Open Helper untuk membuat atau membuka database provider. Ketika aplikasi diluncurkan handler onCreate() dari masing-masing Content Providers nya dipanggil ke aplikasi utama.
 Selanjutnya harus mengimplementasikan query Content Provider untuk melakukan operasi database yang berbeda.
 Terakhir, daftarkan Content Provider di dalam aktivitas pada AndroidManifest menggunakan tag <provider>.

Berikut ini adalah daftar method yang diperlukan agar Content Provider berjalan:

 onCreate() Method ini dipanggil pada saat provider dimulai.
 query() Method ini menerima permintaan dari klien. Hasilnya dikembalikan sebagai sebuah objek Cursor.
 insert()Method ini menyisipkan sebuah rekaman baru ke dalam content provider.
 delete() Method ini menghapus rekaman yang sudah ada dari konten provider.
 update() Method ini memperbaharui rekaman yang ada dari content provider.
 getType() Method ini mengembalikan MIME type data di dalam URI yang dibverikan.

Agar kalian lebih mengerti cara kerja dari intent dan content provider diatas alangkah baiknya kalian lakukan percobaan dengan menggunakan scribt di bawah ini :
Untuk membuat Aplikasi dengan widget Button Intent Back dan Exit pada Aplikasi kalian harus menyiapkan dua activity dan juga dua layout xml. Button Intent disini difungsikan untuk berpindah dari Activity satu ke Activity dua ,dan Button Back untuk kembali ke Activity Sebelumnya dan juga Button Exit untuk Keluar dari Aplikasi kita dan akan kembali Homescreen pada Launcher di Smartphone Android kita.
1. Buat file java dan file layout.xml
2. File layout kita buat dua buah.
activity_main.xml (content_main.xml)
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="com.example.lucianugraheni.tryintent.MainActivity" tools:showIn="@layout/activity_main"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button Intent " android:id="@+id/button1" android:layout_marginTop="111dp" android:layout_below="@+id/textView" android:layout_centerHorizontal="true" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button Exit" android:id="@+id/button2" android:layout_below="@+id/button1" android:layout_centerHorizontal="true" android:layout_marginTop="59dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Selamat Datang dia Activity 1" android:id="@+id/textView" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="48dp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Button Intent pindah ke Acitivity 2" android:id="@+id/textView2" android:layout_below="@+id/textView" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Button Exit Untuk Keluar Aplikasi" android:id="@+id/textView3" android:layout_below="@+id/textView2" android:layout_alignLeft="@+id/textView" android:layout_alignStart="@+id/textView" /> </RelativeLayout>
activity_dua.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent">
<Button android:layout_width="wrap_content" android:layout_height="35dp" android:text="Back/Kembali" android:id="@+id/button1" android:layout_gravity="center_horizontal" android:layout_centerVertical="true" android:layout_centerHorizontal="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="kalian di Activity 2 Pilih Back/Kembali untuk kembali ke ACTIVITY 1" android:id="@+id/textView4" android:layout_above="@+id/button1" android:layout_centerHorizontal="true" android:layout_marginBottom="48dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/textView4" android:id="@+id/gambar" android:src="@drawable/strawbery" android:layout_centerHorizontal="true" android:layout_marginBottom="48dp"/> </RelativeLayout>
3. File java juga dua buah.
MainActivity.java package com.example.lucianugraheni.tryintent; import android.content.Intent; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity { Button btn1, btn2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); }
}); btn1 =(Button)findViewById(R.id.button1); btn2 =(Button)findViewById(R.id.button2); btn1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { Intent keli = new Intent(MainActivity.this,ActivityDua.class); startActivity(keli); } }); btn2.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { moveTaskToBack(true); } }); } }
ActivityDua.java package com.example.lucianugraheni.tryintent; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; public class ActivityDua extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dua); Button btnback = (Button) findViewById(R.id.button1); btnback.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { startActivity(new Intent(ActivityDua.this, MainActivity.class)); finish(); } }); } }
4. Daftarkan activity kedua pada AndroidManifest.xml (activity pertama biasanya sudah didaftarkan pada awal create project. <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.lucianugraheni.tryintent"> <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" android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </activity> <activity android:name=".ActivityDua" > </activity> </application> </manifest>

5. Jalankan dan amati hasilnya.
6. Buat project kedua untuk membuat project dengan content provider.
7. Pada file layout nya
 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout 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" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context="com.example.lucianugraheni.trycontentprovider.MainActivity" tools:showIn="@layout/activity_main"> <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Content provider" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:textSize="30dp" /> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Daftar Nama" android:textColor="#ff87ff09" android:textSize="30dp" android:layout_below="@+id/textView1" android:layout_centerHorizontal="true" /> <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageButton" android:src="@drawable/images" android:layout_below="@+id/textView2" android:layout_centerHorizontal="true" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/button2" android:text="Tambah Nama" android:layout_below="@+id/editText3" android:layout_alignRight="@+id/textView2" android:layout_alignEnd="@+id/textView2" android:layout_alignLeft="@+id/textView2" android:layout_alignStart="@+id/textView2" android:onClick="onClickAddName"/> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content"
android:id="@+id/editText" android:layout_below="@+id/imageButton" android:layout_alignRight="@+id/imageButton" android:layout_alignEnd="@+id/imageButton" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/editText2" android:layout_alignTop="@+id/editText" android:layout_alignLeft="@+id/textView1" android:layout_alignStart="@+id/textView1" android:layout_alignRight="@+id/textView1" android:layout_alignEnd="@+id/textView1" android:hint="Nama" android:textColorHint="@android:color/holo_blue_light" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/editText3" android:layout_below="@+id/editText" android:layout_alignLeft="@+id/editText2" android:layout_alignStart="@+id/editText2" android:layout_alignRight="@+id/editText2" android:layout_alignEnd="@+id/editText2" android:hint="Nilai" android:textColorHint="@android:color/holo_blue_bright" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Ambil Data" android:id="@+id/button" android:layout_below="@+id/button2" android:layout_alignRight="@+id/editText3" android:layout_alignEnd="@+id/editText3" android:layout_alignLeft="@+id/button2" android:layout_alignStart="@+id/button2" android:onClick="onClickRetrieveStudents"/> </RelativeLayout>

8. Pada main activitynya
 package com.example.lucianugraheni.trycontentprovider;
import android.content.ContentValues;
 import android.database.Cursor; import android.net.Uri;
import android.os.Bundle;
 import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.EditText; import android.widget.Toast; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.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(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } public void onClickAddName(View view) { // Add a new student record ContentValues values = new ContentValues(); values.put(StudentsProvider.NAME, ((EditText)findViewById(R.id.editText2)).getText().toString()); values.put(StudentsProvider.GRADE, ((EditText)findViewById(R.id.editText3)).getText().toString()); Uri uri = getContentResolver().insert( StudentsProvider.CONTENT_URI, values); Toast.makeText(getBaseContext(), uri.toString(), Toast.LENGTH_LONG).show(); } public void onClickRetrieveStudents(View view) { // Retrieve student records String URL = "content://com.example.lucianugraheni.trycontentprovider/students"; Uri students = Uri.parse(URL); Cursor c = managedQuery(students, null, null, null, "name"); if (c.moveToFirst()) { do{ Toast.makeText(this, c.getString(c.getColumnIndex(StudentsProvider._ID)) + ", " + c.getString(c.getColumnIndex( StudentsProvider.NAME)) + ", " + c.getString(c.getColumnIndex( StudentsProvider.GRADE)), Toast.LENGTH_SHORT).show(); } while (c.moveToNext()); } } }

9. Tambahkan satu file java dengan nama StudentProvider
package com.example.lucianugraheni.trycontentprovider; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.content.UriMatcher; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; import android.text.TextUtils; import java.util.HashMap; public class StudentsProvider extends ContentProvider { static final String PROVIDER_NAME = "com.example.lucianugraheni.trycontentprovider"; static final String URL = "content://" + PROVIDER_NAME + "/students"; static final Uri CONTENT_URI = Uri.parse(URL); static final String _ID = "_id"; static final String NAME = "name"; static final String GRADE = "grade"; private static HashMap<String, String> STUDENTS_PROJECTION_MAP; static final int STUDENTS = 1; static final int STUDENT_ID = 2; static final UriMatcher uriMatcher; static{ uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(PROVIDER_NAME, "students", STUDENTS); uriMatcher.addURI(PROVIDER_NAME, "students/#", STUDENT_ID); } /** * Database specific constant declarations */ private SQLiteDatabase db; static final String DATABASE_NAME = "College"; static final String STUDENTS_TABLE_NAME = "students"; static final int DATABASE_VERSION = 1; static final String CREATE_DB_TABLE = " CREATE TABLE " + STUDENTS_TABLE_NAME + " (_id INTEGER PRIMARY KEY AUTOINCREMENT, " + " name TEXT NOT NULL, " + " grade TEXT NOT NULL);"; /** * Helper class that actually creates and manages * the provider's underlying data repository. */ private static class DatabaseHelper extends SQLiteOpenHelper { DatabaseHelper(Context context){ super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_DB_TABLE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("DROP TABLE IF EXISTS " + STUDENTS_TABLE_NAME); onCreate(db);
} } @Override public boolean onCreate() { Context context = getContext(); DatabaseHelper dbHelper = new DatabaseHelper(context); /** * Create a write able database which will trigger its * creation if it doesn't already exist. */ db = dbHelper.getWritableDatabase(); return (db == null)? false:true; } @Override public Uri insert(Uri uri, ContentValues values) { /** * Add a new student record */ long rowID = db.insert( STUDENTS_TABLE_NAME, "", values); /** * If record is added successfully */ if (rowID > 0) { Uri _uri = ContentUris.withAppendedId(CONTENT_URI, rowID); getContext().getContentResolver().notifyChange(_uri, null); return _uri; } throw new SQLException("Failed to add a record into " + uri); } @Override public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables(STUDENTS_TABLE_NAME); switch (uriMatcher.match(uri)) { case STUDENTS: qb.setProjectionMap(STUDENTS_PROJECTION_MAP); break; case STUDENT_ID: qb.appendWhere( _ID + "=" + uri.getPathSegments().get(1)); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } if (sortOrder == null || sortOrder == ""){ /** * By default sort on student names */ sortOrder = NAME; } Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, sortOrder); /** * register to watch a content URI for changes */ c.setNotificationUri(getContext().getContentResolver(), uri); return c; } @Override
public int delete(Uri uri, String selection, String[] selectionArgs) { int count = 0; switch (uriMatcher.match(uri)){ case STUDENTS: count = db.delete(STUDENTS_TABLE_NAME, selection, selectionArgs); break; case STUDENT_ID: String id = uri.getPathSegments().get(1); count = db.delete( STUDENTS_TABLE_NAME, _ID + " = " + id + (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""), selectionArgs); break; default: throw new IllegalArgumentException("Unknown URI " + uri); } getContext().getContentResolver().notifyChange(uri, null); return count; } @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int count = 0; switch (uriMatcher.match(uri)){ case STUDENTS: count = db.update(STUDENTS_TABLE_NAME, values, selection, selectionArgs); break; case STUDENT_ID: count = db.update(STUDENTS_TABLE_NAME, values, _ID + " = " + uri.getPathSegments().get(1) + (!TextUtils.isEmpty(selection) ? " AND (" +selection + ')' : ""), selectionArgs); break; default: throw new IllegalArgumentException("Unknown URI " + uri ); } getContext().getContentResolver().notifyChange(uri, null); return count; } @Override public String getType(Uri uri) { switch (uriMatcher.match(uri)){ /** * Get all student records */ case STUDENTS: return "vnd.android.cursor.dir/vnd.example.students"; /** * Get a particular student */ case STUDENT_ID: return "vnd.android.cursor.item/vnd.example.students"; default: throw new IllegalArgumentException("Unsupported URI: " + uri); } } }

10. Daftarkan provider pada Android Manifest
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.lucianugraheni.trycontentprovider"> <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" android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:authorities="com.example.lucianugraheni.trycontentprovider" android:name=".StudentsProvider"> </provider> </application> </manifest>
11. Jalankan dan amati hasilnya

0 Response to "Intent dan Content Provider"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel