Pilih Laman

sumber : https://medium.com/@rizal_hilman/aplikasi-portal-berita-android-dengan-php-mysqli-belajarapi-ccde39565403

Persiapan Server API

Database

Setting Koneksi.php

<?php
// mengkoneksikan ke database
$server = “localhost”;
$server_username = “root”;
$server_password = “”;
$database_name = “db_portal_berita”;$conn = new Mysqli($server, $server_username, $server_password, $database_name);

tampil_berita.php

<?php
// include file koneksi
require ‘koneksi.php’;
// buat QUery perintah untuk menampilkan semua data
// Secara Descending berdasarkan ID
$sql_get_berita = “SELECT * FROM tb_berita ORDER BY id DESC”;
$query = $conn->query($sql_get_berita);// Variable penampung array sementara
$response_data = null;while ($data = $query->fetch_assoc()) {
 // tambahkan data yg di seleksi ke dalam array
 $response_data[] = $data;
}// Cek apakah datanya null ?
if (is_null($response_data)) {
 // jika ya, buat status untuk response jadi false
 $status = false;
} else {
 // jika tidak, buat status untuk response jadi true
 $status = true;
}
// Set type header response ke Json
header(‘Content-Type: application/json’);
// Bungkus data dalam array
$response = [‘status’ => $status, ‘berita’ => $response_data];
// tampilkan dan convert ke format json
echo json_encode($response);

Testing Web server

Screenshot from tampil_berita.php
Json Viewer

Persiapan Project Android

Persiapan Library

  1. Retrofit & Gson-Converter (untuk API manager)
  2. Piccasso (menampilkan gambar dari internet)
  3. Recycler View (untuk list)
{
   ...
   compile 'com.squareup.retrofit2:retrofit:2.3.0'
   compile 'com.squareup.retrofit2:converter-gson:2.3.0'
   compile 'com.squareup.picasso:picasso:2.5.2'
   implementation 'com.android.support:recyclerview-v7:26.1.0'
   ...
}

Persiapan Retrofit

Project Structure
package com.khilman.www.aplikasiportalberita.network;

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Created by Rizal Hilman on 12/02/18.
 * www.khilman.com
 */

public class InitRetrofit {
    // URL Server API
    public static String API_URL = "http://192.168.95.2/portal_berita/";

    public static Retrofit setInit() {
        return new Retrofit.Builder().baseUrl(API_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

    public static ApiServices getInstance() {
        return setInit().create(ApiServices.class);
    }
}
package com.khilman.www.aplikasiportalberita.network;

import retrofit2.Call;
import retrofit2.http.GET;

/**
 * Created by Rizal Hilman on 12/02/18.
 * www.khilman.com
 */

public interface ApiServices {

    //@TIPEMETHOD("API_END_POINT")
    @GET("tampil_berita.php")
    Call<ResponseBerita> request_show_all_berita();
    // <ModelData> nama_method()
    
}
  • Kamu akan mendapati error dibagian ResponseBerita, itu dikarenakan kita belum membuat Model Pojo tersebut. Kita akan membuatnya ditahap berikutnya
  • Ketika memanggil class Call pastikan mengimport class milik retrofit2. seperti di screenshot berikut :

Model Pojo

Project Structure after Pojo Generated
package com.khilman.www.aplikasiportalberita.response;

import java.util.List;
import com.google.gson.annotations.SerializedName;

public class ResponseBerita{

   @SerializedName("berita")
   private List<BeritaItem> berita;

   @SerializedName("status")
   private boolean status;

   public void setBerita(List<BeritaItem> berita){
      this.berita = berita;
   }

   public List<BeritaItem> getBerita(){
      return berita;
   }

   public void setStatus(boolean status){
      this.status = status;
   }

   public boolean isStatus(){
      return status;
   }

   @Override
   public String toString(){
      return 
         "ResponseBerita{" + 
         "berita = '" + berita + '\'' + 
         ",status = '" + status + '\'' + 
         "}";
      }
}
package com.khilman.www.aplikasiportalberita.response;

import com.google.gson.annotations.SerializedName;

public class BeritaItem{

   @SerializedName("penulis")
   private String penulis;

   @SerializedName("foto")
   private String foto;

   @SerializedName("id")
   private String id;

   @SerializedName("judul_berita")
   private String judulBerita;

   @SerializedName("tanggal_posting")
   private String tanggalPosting;

   @SerializedName("isi_berita")
   private String isiBerita;

   public void setPenulis(String penulis){
      this.penulis = penulis;
   }

   public String getPenulis(){
      return penulis;
   }

   public void setFoto(String foto){
      this.foto = foto;
   }

   public String getFoto(){
      return foto;
   }

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

   public String getId(){
      return id;
   }

   public void setJudulBerita(String judulBerita){
      this.judulBerita = judulBerita;
   }

   public String getJudulBerita(){
      return judulBerita;
   }

   public void setTanggalPosting(String tanggalPosting){
      this.tanggalPosting = tanggalPosting;
   }

   public String getTanggalPosting(){
      return tanggalPosting;
   }

   public void setIsiBerita(String isiBerita){
      this.isiBerita = isiBerita;
   }

   public String getIsiBerita(){
      return isiBerita;
   }

   @Override
   public String toString(){
      return 
         "BeritaItem{" + 
         "penulis = '" + penulis + '\'' + 
         ",foto = '" + foto + '\'' + 
         ",id = '" + id + '\'' + 
         ",judul_berita = '" + judulBerita + '\'' + 
         ",tanggal_posting = '" + tanggalPosting + '\'' + 
         ",isi_berita = '" + isiBerita + '\'' + 
         "}";
      }
}

Layouting

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingVertical="5dp">
    <ImageView
        android:id="@+id/ivPosterBerita"
        android:layout_width="match_parent"
        android:layout_height="130dp"
        android:layout_marginHorizontal="10dp"
        android:scaleType="fitXY"
        android:src="@mipmap/ic_launcher"/>
    <TextView
        android:id="@+id/tvJudulBerita"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:layout_marginVertical="10dp"
        android:layout_marginHorizontal="10dp"
        android:textColor="@android:color/black"
        android:text="Judul Artikel Berita"/>
    <LinearLayout
        android:layout_marginHorizontal="10dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:id="@+id/tvTglTerbit"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Sabtu, 12 Maret 2018."/>
        <TextView
            android:id="@+id/tvPenulis"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginHorizontal="10dp"
            android:text="Oleh : Rizal Hilman"/>
    </LinearLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
    tools:context=".MainActivity">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/rvListBerita"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

Activity Logic

package com.khilman.www.aplikasiportalberita;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.widget.Toast;

import com.khilman.www.aplikasiportalberita.network.ApiServices;
import com.khilman.www.aplikasiportalberita.network.InitRetrofit;
import com.khilman.www.aplikasiportalberita.response.BeritaItem;
import com.khilman.www.aplikasiportalberita.response.ResponseBerita;

import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class MainActivity extends AppCompatActivity {

    // Deklarasi Widget
    private RecyclerView recyclerView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Inisialisasi Widget
        recyclerView = (RecyclerView) findViewById(R.id.rvListBerita);
        // RecyclerView harus pakai Layout manager
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        // Eksekusi method
        tampilBerita();
    }

    private void tampilBerita() {
        ApiServices api = InitRetrofit.getInstance();
        // Siapkan request
        Call<ResponseBerita> beritaCall = api.request_show_all_berita();
        // Kirim request
        beritaCall.enqueue(new Callback<ResponseBerita>() {
            @Override
            public void onResponse(Call<ResponseBerita> call, Response<ResponseBerita> response) {
                // Pasikan response Sukses
                if (response.isSuccessful()){
                    Log.d("response api", response.body().toString());
                    // tampung data response body ke variable
                    List<BeritaItem> data_berita = response.body().getBerita();
                    boolean status = response.body().isStatus();
                    // Kalau response status nya = true
                    if (status){
                        // Buat Adapter untuk recycler view
                        AdapterBerita adapter = new AdapterBerita(MainActivity.this, data_berita);
                        recyclerView.setAdapter(adapter);
                    } else {
                        // kalau tidak true
                        Toast.makeText(MainActivity.this, "Tidak ada berita untuk saat ini", Toast.LENGTH_SHORT).show();
                    }
                }
            }

            @Override
            public void onFailure(Call<ResponseBerita> call, Throwable t) {
                // print ke log jika Error
                t.printStackTrace();
            }
        });
    }
}
package com.khilman.www.aplikasiportalberita;

import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.khilman.www.aplikasiportalberita.response.BeritaItem;
import com.squareup.picasso.Picasso;

import java.util.List;

/**
 * Created by Rizal Hilman on 12/02/18.
 * www.khilman.com
 */

class AdapterBerita extends RecyclerView.Adapter<AdapterBerita.MyViewHolder> {
    // Buat Global variable untuk manampung context
    Context context;
    List<BeritaItem> berita;
    public AdapterBerita(Context context, List<BeritaItem> data_berita) {
        // Inisialisasi
        this.context = context;
        this.berita = data_berita;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // Layout inflater
        View view = LayoutInflater.from(context).inflate(R.layout.berita_item, parent, false);

        // Hubungkan dengan MyViewHolder
        MyViewHolder holder = new MyViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, final int position) {
        // Set widget
        holder.tvJudul.setText(berita.get(position).getJudulBerita());
        holder.tvTglTerbit.setText(berita.get(position).getTanggalPosting());

        // Dapatkan url gambar
        final String urlGambarBerita = "http://192.168.20.92/portal_berita/images/" + berita.get(position).getFoto();
        // Set image ke widget dengna menggunakan Library Piccasso
        // krena imagenya dari internet
        Picasso.with(context).load(urlGambarBerita).into(holder.ivGambarBerita);

        // Event klik ketika item list nya di klik
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Mulai activity Detail
                Intent varIntent = new Intent(context, DetailActivity.class);
                // sisipkan data ke intent
                varIntent.putExtra("JDL_BERITA", berita.get(position).getJudulBerita());
                varIntent.putExtra("TGL_BERITA", berita.get(position).getTanggalPosting());
                varIntent.putExtra("PNS_BERITA", berita.get(position).getPenulis());
                varIntent.putExtra("FTO_BERITA", urlGambarBerita);
                varIntent.putExtra("ISI_BERITA", berita.get(position).getIsiBerita());

                // method startActivity cma bisa di pake di activity/fragment
                // jadi harus masuk ke context dulu
                context.startActivity(varIntent);
            }
        });
    }
    // Menentukan Jumlah item yang tampil
    @Override
    public int getItemCount() {
        return berita.size();
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        // Deklarasi widget
        ImageView ivGambarBerita;
        TextView tvJudul, tvTglTerbit, tvPenulis;
        public MyViewHolder(View itemView) {
            super(itemView);
            // inisialisasi widget
            ivGambarBerita = (ImageView) itemView.findViewById(R.id.ivPosterBerita);
            tvJudul = (TextView) itemView.findViewById(R.id.tvJudulBerita);
            tvTglTerbit = (TextView) itemView.findViewById(R.id.tvTglTerbit);
            tvPenulis = (TextView) itemView.findViewById(R.id.tvPenulis);
        }
    }
}

Detail Berita Activity

Layouting

<?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"
    android:fitsSystemWindows="true"
    tools:context=".DetailActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="@dimen/app_bar_height"
        android:fitsSystemWindows="true"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            app:toolbarId="@+id/toolbar">
            <!--TAMPILKAN GAMBAR-->
            <ImageView
                android:id="@+id/ivGambarBerita"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:src="@mipmap/ic_launcher"
                android:scaleType="fitXY"/>

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/AppTheme.PopupOverlay" />

        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_detail" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/fab_margin"
        app:layout_anchor="@id/app_bar"
        app:layout_anchorGravity="bottom|end"
        app:srcCompat="@android:drawable/ic_dialog_email" />

</android.support.design.widget.CoordinatorLayout>
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.NestedScrollView 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"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context=".DetailActivity"
    tools:showIn="@layout/activity_detail">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="10dp"
        android:orientation="vertical">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="15dp"
            android:orientation="horizontal">
            <TextView
                android:id="@+id/tvTglTerbit"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Senin, 12 Maret 2018"/>
            <TextView
                android:id="@+id/tvPenulis"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="10dp"
                android:text="Oleh : Rizal Hilman"/>
        </LinearLayout>
        <WebView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/wvKontenBerita"></WebView>
    </LinearLayout>
</android.support.v4.widget.NestedScrollView>

DetailActivity.java

package com.khilman.www.aplikasiportalberita;

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.View;
import android.webkit.WebView;
import android.widget.ImageView;
import android.widget.TextView;

import com.squareup.picasso.Picasso;

public class DetailActivity extends AppCompatActivity {

    // Deklarasi
    ImageView ivGambarBerita;
    TextView tvTglTerbit, tvPenulis;
    WebView wvKontenBerita;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);
        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();
            }
        });

        // Inisialisasi
        ivGambarBerita = (ImageView) findViewById(R.id.ivGambarBerita);
        tvTglTerbit = (TextView) findViewById(R.id.tvTglTerbit);
        tvPenulis = (TextView) findViewById(R.id.tvPenulis);
        wvKontenBerita = (WebView) findViewById(R.id.wvKontenBerita);

        // Jalankan method tampil detail berita
        showDetailBerita();

    }

    private void showDetailBerita() {
        // Tangkap data dari intent
        String judul_berita = getIntent().getStringExtra("JDL_BERITA");
        String tanggal_berita = getIntent().getStringExtra("TGL_BERITA");
        String penulis_berita = getIntent().getStringExtra("PNS_BERITA");
        String isi_berita = getIntent().getStringExtra("ISI_BERITA");
        String foto_berita = getIntent().getStringExtra("FTO_BERITA");

        // Set judul actionbar / toolbar
        getSupportActionBar().setTitle(judul_berita);

        // Set ke widget
        tvPenulis.setText("Oleh : " + penulis_berita);
        tvTglTerbit.setText(tanggal_berita);
        // Untuk gambar berita
        Picasso.with(this).load(foto_berita).into(ivGambarBerita);
        // Set isi berita sebagai html ke WebView
        wvKontenBerita.getSettings().setJavaScriptEnabled(true);
        wvKontenBerita.loadData(isi_berita, "text/html; charset=utf-8", "UTF-8");
    }
}

Android Manifest

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

Running Project

Sentuhan Akhir

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#ff9100</color>
    <color name="colorPrimaryDark">#c56200</color>
    <color name="colorAccent">#ffc246</color>
</resources>