บทเรียนเบื้องต้นสำหรับสร้าง Comic Book Shelf ด้วย Firebase และ Android Studio เพื่อสร้างแอปพลิเคชันอ่านหนังสือ PDF อย่างง่ายและจัดการด้วย Firebase
ศึกษาบทเรียนก่อนหน้านี้เกี่ยวกับการสร้าง Adapter, Model และ Picasso ไปจนถึงการเชื่อมต่อ Firebase ที่บทความ:
- เขียนแอพฯ ควบคุม Arduino ด้วย Android ผ่าน Firebase RealTime Database
- เขียนแอพ Android ดึง JSON มาเล่นกับ RecyclerView และ Picasso
คราวนี้ให้เราเตรียมไฟล์ PDF ที่เป็น Ebook อัพขึ้นผ่าน Storage ของ Firebase (ปล. ระบบนี้ไม่ได้ทำระบบ DRM:Data Right Management นะแค่ทำแอปพลิเคชันอ่าน Pdf ง่ายๆ ที่เป็นรูปแบบ Book Shelf หรือตู้หนังสือแค่นั้น)
เมื่ออัพโหลด PDF ไปบน Firebase Storage แล้วให้จัดการสร้าง Sample Real-Time Database ขึ้นมาให้ได้โครงสร้างตามภาพนี้:
หรือดู Preview แบบ JSON ให้เป็นแบบ Link นี้: https://enet5-7f9f6.firebaseio.com/bookshelf.json
บทเรียนนี้ให้ปรับ Rule แบบมักง่ายไปก่อนเพื่อให้ใครก็แก้ไข เขียนได้ให้เป็น
{ "rules": { ".read": true, ".write": true } }
ต่อมาให้ทำการสร้างแอพพลิเคชันขึ้นมาใหม่เป็น Empty Activity ทำการเชื่อมต่อ Firebase โดยไปที่ เมนู: Tools-> Firebase
หลังจากนั้นเลือก Realtime Database
ทำตามขั้นตอนที่ 1 และ ขั้นตอนที่ 2 โดยมันจะมีการบังคับให้เราเข้าระบบ Google บัญชีที่เราใช้ในการทำ Firebase อยู่อีกทั้งขั้นตอนนี้จะมีการ Sync ตัว Gradle ให้ด้วยเรียบร้อย:
เมื่อเสร็จแล้วซ่อนหน้าต่าง Assistance นี้ออกไป
ขั้นตอนต่อมาให้เราเตรียมพร้อมการสร้างโปรเจ็คของเราให้ประกาศตัวแปรต่อไปนี้ที่คลาส MainActivity.java
private static final String TAG = "FireComic"; private List<DataModel> response_data; private DataAdapter dataAdapter; private RecyclerView mRecyclerView; private FirebaseDatabase firebaseDatabase; private DatabaseReference databaseReference;
มันจะขึ้นตัก Error สีแดงที่ DataAdapter นำเมาส์ไปวางไว้แล้วกด Alt+Enter เพื่อเพิ่มคลาส DataAdapter.java ขึ้นมา เช่นกันมันจะขึ้นที่ DataModel ให้ทำขั้นตอนเดียวกันเพื่อสร้าง Class ใหม่ชื่อ DataModel.java ด้วย ดังนั้นโปรเจ็คนี้เราจะได้ ไฟล์ Class ทั้งหมด:
ไปที่ Layout ให้เราสร้าง RecycleView ขึ้นมาที่ไฟล์ activity_main.xml ดังนี้:
<?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:gravity="top" android:orientation="vertical" tools:context=".MainActivity"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintVertical_bias="1.0"> </android.support.v7.widget.RecyclerView> </LinearLayout>
เปิด Class ที่ชื่อ DataAdapter.java ขึ้นมาเขียนคำสั่งต่อไปนี้:
import android.support.annotation.NonNull; 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.squareup.picasso.Picasso; import java.util.List; public class DataAdapter extends RecyclerView.Adapter<DataAdapter.DataViewHolder> { private List<DataModel> dataModelList; public DataAdapter(List<DataModel> result) { this.dataModelList = result; } @Override public DataAdapter.DataViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { return new DataViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.content_read,viewGroup,false)); } @Override public void onBindViewHolder(final DataViewHolder dataViewHolder, final int i) { DataModel dataModel = dataModelList.get(i); dataViewHolder.textTitle.setText(dataModel.title); Picasso.get().load(dataModel.photos) .error(R.mipmap.ic_launcher) .placeholder(R.mipmap.ic_launcher) .into(dataViewHolder.imageView); } @Override public int getItemCount() { return dataModelList.size(); } public class DataViewHolder extends RecyclerView.ViewHolder { TextView textTitle; ImageView imageView; public DataViewHolder(View itemView) { super(itemView); textTitle = itemView.findViewById(R.id.title); imageView = itemView.findViewById(R.id.thumbnail); } } }
โดยมันจะบังคับให้เราสร้าง Layout ใหม่ขึ้นมาชื่อว่า content_read.xml ให้เราสร้างขึ้นมาหลังจากนั้นให้แก้ไข XML ของ content_read.xml เป็นดังนี้:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="170dp" android:layout_height="300dp" android:layout_marginLeft="20dp" android:layout_marginTop="10dp" android:orientation="horizontal" android:padding="5dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ImageView android:id="@+id/thumbnail" android:layout_width="match_parent" android:layout_height="240dp" android:scaleType="centerCrop" /> <TextView android:id="@+id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:textAlignment="center" android:textColor="@color/cardview_dark_background" android:textSize="16sp" /> </LinearLayout> </LinearLayout>
ถ้าหากไม่เกิดข้อผิดพลาดใดๆ ให้ไปที่ DataModel.java แก้ไขไฟล์นี้เป็น:
import java.util.HashMap; import java.util.Map; public class DataModel { String title,desc,photos,key; public DataModel(){ } public DataModel(String title, String desc, String photos, String key) { this.title = title; this.desc = desc; this.photos = photos; this.key = key; } public Map<String, Object> toMap(){ HashMap<String, Object> result = new HashMap<>(); result.put("title",title); result.put("content",desc); result.put("photos",photos); result.put("key",key); return result; } }
เพื่อทำการ Map ตัว Key ที่เราใช้ใน Firebase ให้ตรงกับหน้าจอที่จะปรากฏขึ้นในระบบ เมื่อเสร็จขั้นตอนนี้แล้วให้เราไปที่ MainActivity.java เพิ่มคำสั่งต่อไปนี้ในOnCreate() เมธอด:
firebaseDatabase = FirebaseDatabase.getInstance(); databaseReference = firebaseDatabase.getReference("bookshelf/data"); response_data = new ArrayList<>(); mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView); int numberOfColumns = 2; mRecyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns)); dataAdapter = new DataAdapter(response_data); mRecyclerView.setAdapter(dataAdapter); bindingData();
พิจารณาว่า
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView); int numberOfColumns = 2; mRecyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns));
คือการแสดงผลของ RecyclerView ปกติของเราให้เป็น Vertical แนวดิ่งแต่แบ่ง คอลัมน์ของแถวเป็น 2 คอลัมน์นั่นเอง
เพิ่มเมธอด bindingData() ใหม่ใน MainActivity.java
private void bindingData() { databaseReference.addChildEventListener(new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String s) { response_data.add(dataSnapshot.getValue(DataModel.class)); dataAdapter.notifyDataSetChanged(); } @Override public void onChildChanged(DataSnapshot dataSnapshot, String s) { } @Override public void onChildRemoved(DataSnapshot dataSnapshot) { } @Override public void onChildMoved(DataSnapshot dataSnapshot, String s) { } @Override public void onCancelled(DatabaseError databaseError) { } }); }
ทำฟังกืชันการนับจำนวน Item ของ Firebase เพิ่มเข้าไป ต่อท้ายก่อนปิดคลาส:
private int getIemIndex(DataModel dataModel){ int index = -1; for(int i =0; i < response_data.size(); i++){ if(response_data.get(i).key.equals(dataModel.key)){ index = i; break; } } return index; }
ทดสอบการทำงานโดย run ตัว Android Studio ขึ้นมาถ้าไม่มีข้อผิดพลาดจะเป็นดังนี้:
บทเรียนต่อไปเราจะทำหน้าอ่านไฟล์ PDF เมื่อกด ที่หน้าปกของ PDF แต่ละตัว โดยเราต้องแก้ไข PDF URL เข้าไปใน Firebase ด้วยเช่นกัน
บทเรียนตอนที่ 2: Android Studio กับการทำระบบ Bookshelf ร่วมกับ Firebase เบื้องต้น ตอนที่ 2
สำหรับคนที่ไม่อยากโหลด PDF แต่มีภาพ Image หลายๆ ภาพให้ไปที่บทเรียนที่ 3 เลยข้ามบทที่ 2 ไป
บทเรียนตอนที่ 3: Android Studio กับการทำระบบ Bookshelf ร่วมกับ Firebase เบื้องต้น ตอนที่ 3
3 Comments