ahmdsat
ahmdsat
عضو شرف
المساهمات :
42
النقاط :
82
التقيم :
1
الاوسمة :
إختبر قواعد البيانات داخل الأندرويد Crown_gold
بسم الله الرحمن الرحيم
 
منذ ظهور مكتبة Room كمكتبة تسهل على مطوري الأندرويد التعامل مع قواعد البيانات الداخلية من ناحية الإنشاء والحذف والإضافة، بدأ الكثير من المطورين العمل على إضافة بعد المميزات على هذه المكتبة. واحدة من أهم المشاكل التي كان يعاني منها المطورين هي مشكلة إختبار قواعد البيانات والقدرة على معرفة محتوياتها ورؤيتها بشكل فعلي كجداول وعلاقات. الكثير من المواقع أو الـ plugins كانت توفر هذه الميزة ولكن يجب عليك أولاً رفع ملف قاعدة البيانات على الموقع واستخراجه من الهاتف ومن ثم العمل عليه. هذه الطريقة عانت من التعقيد ولم تستخدم بشكل كبير بين المطورين. ( منها مكتبة Stetho المطورة من قبل Facebook )
الكثير من المكتبات الأخرى التي تستخدم طريقة Object-Databases مثل مكتبة Realm أو حتى ObjectBox تمتلك Browser خاص بها يمكنك من معرفة محتويات قاعدة البيانات بسهولة. ولكن ماذا عن Room؟ سنتحدث اليوم عن واحدة من أفضل المكتبات التي تميزت بهذا المجال. كانت تستخدم من قبل ظهور مكتبة Room حتى، أي مع الـ Pure SQLite ولكن بعد ظهور Room تحسنت المكتبة بشكل كبير. تمكنك المكتبة من إضافة وحذف أو التعديل على الـ Records داخل قاعدة البيانات. تمكنك أيضاً من تتبع المعلومات المحفوظة داخل الـ SharedPreferences والتأكد ما إذا كانت المعلومات موجودة أو لا. 
 
المكتبة من تطوير Amit Shekhar واحد من أفضل مطوري المكتبات في مجال الأندرويد. بإمكانك مراجعة حسابه في Github من هنا
ملاحظة : لن نتكلم بشكل كبير عن مكتبة Room وطريقة إنشاء قواعد البيانات من خلالها. لمعرفة طريقة عمل المكتبة يمكنك زيارة موضوعي السابق من هنا
بإمكانك أيضاً مراجعة دورة الأستاذ محمد على عالم البرمجة من هنا
 
لنبدأ .. 
المشروع سيكون عبارة عن RecyclerView ستقوم بعرض محتويات قاعدة البيانات التي سنقوم بإنشائها.
 
بعد إنشاء بروجكت جديد سنقوم بإضافة كل الـ Dependencies اللازمة
الكود:
   // recyclerview
    implementation 'com.android.support:recyclerview-v7:+'

    //room db
    implementation "android.arch.persistence.room:runtime:1.1.1"
    annotationProcessor "android.arch.persistence.room:compiler:1.1.1"
    
    // android debug database library
    debugImplementation 'com.amitshekhar.android:debug-db:1.0.4'

 
نقوم الآن بعمل Setup لقاعدة البيانات.
أولاً سنقوم بإنشاء الـ Model Class. سيقوم بتخزين الـ ID, Name, and Major للطلاب.
الكود:
import android.arch.persistence.room.Entity;
import android.arch.persistence.room.PrimaryKey;

@Entity
public class Student {

    @PrimaryKey(autoGenerate = true)
    private int id;
    private String name;
    private String major;

    public Student() {

    }

    public Student(int id, String name, String major) {
        this.id = id;
        this.name = name;
        this.major = major;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMajor() {
        return major;
    }

    public void setMajor(String major) {
        this.major = major;
    }
}

 
ثانياً نقوم بإنشاء Data access object interface DAO بالإضافة إلى كلاس الـ Database.
الكود:
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Delete;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.OnConflictStrategy;
import android.arch.persistence.room.Query;

import com.example.asus.databasedebug.pojo.Student;

import java.util.List;


@Dao
public interface StudentDAO {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insert (Student student);

    @Delete
    void delete (Student student);

    @Query("SELECT * FROM Student")
    List<Student> getAllStudents();

}

 
الكود:
import android.arch.persistence.room.Database;
import android.arch.persistence.room.RoomDatabase;

import com.example.asus.databasedebug.pojo.Student;

@Database(entities = Student.class, version = 1)
public abstract class StudentDB extends RoomDatabase {

    public abstract StudentDAO studentDAO();

}

 
نقوم بإنشاء كلاس الـ Repository أو الـ Source of truth والمسؤول عن إنشاء قاعدة البيانات بالإضافة إلى إجراء كل العمليات المعرفة مسبقاً داخل الـDAO.
الكود:
import android.arch.persistence.room.Room;
import android.os.AsyncTask;

import com.example.asus.databasedebug.application.DatabaseDebugApplication;
import com.example.asus.databasedebug.pojo.Student;

import java.util.List;


// Singleton
public class StudentRepository {

    // singleton object
    private static StudentRepository repository = new StudentRepository();

    // database object
    private static StudentDB studentDB;

    // constructor
    private StudentRepository(){
        initDB();
    }

    public static StudentRepository getInstance(){
        return repository;
    }

    private void initDB() {
        studentDB = Room.databaseBuilder(DatabaseDebugApplication.getContext(),
                StudentDB.class, "StudentDatabase").build();
    }

    public List<Student> getStudents(){
        try {
            return new DataBaseOperation().execute().get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // Async
    class DataBaseOperation extends AsyncTask<Void,Void,List<Student>> {

        @Override
        protected List<Student> doInBackground(Void... voids) {
            return studentDB.studentDAO().getAllStudents();
        }
    }
}

 
لا تنسى توفير الـ Application Context لكلاس الـ Repository حتى يتمكن من إنشاء قاعدة البيانات. ( لا تنسى إضافته للـ Manifest )
الكود:
import android.app.Application;
import android.content.Context;

public class DatabaseDebugApplication extends Application {

    private static Context context;

    @Override
    public void onCreate() {
        super.onCreate();
        context = getApplicationContext();
    }

    public static Context getContext(){
        return context;
    }
}

 
ننتقل الآن إلى الـ View. ( لن نقوم بإنشاء ViewModel كحلقة وصل بين الـ View وبين الـ Repository إختصاراً للوقت .. ولكن لا يعتبر Good practice )
الـ MainActivity.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"
    tools:context=".ui.MainActivity">

    <android.support.v4.widget.SwipeRefreshLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/swipe_to_refresh">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="5dp" />

    </android.support.v4.widget.SwipeRefreshLayout>

</RelativeLayout>

 
الشكل النهائي
[ندعوك للتسجيل في المنتدى أو التعريف بنفسك لمعاينة هذه الصورة]
 
 
بالنسبة لتصميم الـ RecyclerView cell.
الكود:
<?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="wrap_content">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/name"
        android:layout_margin="10dp"
        android:textColor="#000"
        android:text="Student Name"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/major"
        android:layout_margin="10dp"
        android:layout_alignParentEnd="true"
        android:text="Student Major"/>

</RelativeLayout>

 
الشكل النهائي
[ندعوك للتسجيل في المنتدى أو التعريف بنفسك لمعاينة هذه الصورة]
 
 
أخيراً كلاس الـ MainActivity and RecyclerView adapter
الكود:
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import com.example.asus.databasedebug.R;
import com.example.asus.databasedebug.database.StudentRepository;

public class MainActivity extends AppCompatActivity {

    private RecyclerView mRecyclerView;
    private StudentAdapter adapter;
    private SwipeRefreshLayout swipeRefreshLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Initialize views
        mRecyclerView = findViewById(R.id.recyclerview);
        swipeRefreshLayout = findViewById(R.id.swipe_to_refresh);

        // Initialize adapter
        adapter = new StudentAdapter(StudentRepository.getInstance().getStudents());


        // Configure recyclerview
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
        mRecyclerView.setAdapter(adapter);

        // Swipe listener
        swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                adapter.setList(StudentRepository.getInstance().getStudents());
                adapter.notifyDataSetChanged();

                swipeRefreshLayout.setRefreshing(false);
            }
        });

    }
}

 
الكود:
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.TextView;

import com.example.asus.databasedebug.R;
import com.example.asus.databasedebug.pojo.Student;

import java.util.List;

public class StudentAdapter extends RecyclerView.Adapter<StudentAdapter.ViewHolder> {

    private List<Student> studentList;

    public StudentAdapter(List<Student> list){
        studentList = list ;
    }

    public void setList(List<Student> list){
        studentList = list;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        return new ViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_student, null));
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder viewHolder, int index) {
        viewHolder.name.setText(studentList.get(index).getName());
        viewHolder.major.setText(studentList.get(index).getMajor());
    }

    @Override
    public int getItemCount() {
        return ( studentList == null ) ? 0 : studentList.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder{

        TextView name, major;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            name = itemView.findViewById(R.id.name);
            major = itemView.findViewById(R.id.major);
        }
    }
}

 
إنتهينا بشكل كبير من الجانب النظري. ننتقل للجزء الرئيسي. إذا كنت تريد تشغيل التطبيق على الـ Emulator ستضطر إلى تشغيل هذا الأمر داخل مجلد التطبيق من نافذة الـ Terminal بالأسفل. ( تأكد من إضافة الـ platform-tools كـ PATH حتى يعمل الأمر بشكل صحيح )
adb forward tcp:8080 tcp:8080
 
إذا كنت تريد تشغيل التطبيق على جوالك الخاص، تأكد بأنك متصل على نفس الشبكة المتصل بها الكمبيوتر. 
بعد تشغيل التطبيق قم بالبحث داخل الـ Logcat عن D/DebugDB .. ستلاحظ وجود رابط قم بالدخول عليه.
[ندعوك للتسجيل في المنتدى أو التعريف بنفسك لمعاينة هذه الصورة]
 
بمجرد الدخول للرابط سنلاحظ ظهور هذه الصفحة
[ندعوك للتسجيل في المنتدى أو التعريف بنفسك لمعاينة هذه الصورة]
 
سنلاحظ وجود عدة خيارات. بإمكانك تصفح قواعد البيانات الموجودة داخل الجهاز والمنشأة من قبل التطبيق تحت خانة الـ Databases على اليسار. (StudentDatabase ) بالإضافة إلى الـ SharedPreference.
بالضغط على جدول الـ Student سنستطيع رؤية كل البيانات المخزنة داخل هذا الجدول. ( نلاحظ وجود عدة جداول لم نقم بإنشائها ولكن مكتبة Roomقامت بإنشائها بشكل تلقائي )
[ندعوك للتسجيل في المنتدى أو التعريف بنفسك لمعاينة هذه الصورة]
نستطيع الآن إضافة البيانات لتعبئة الجداول ( تعتبر طريقة ممتازة لعمل Populate لقاعدة البيانات بشكل سريع وبدون كتابة سطر برمجي واحد.
 
[ندعوك للتسجيل في المنتدى أو التعريف بنفسك لمعاينة هذه الصورة]
 
نقوم الآن بتحديث التطبيق بعمل Swipe للأسفل وسنلاحظ بأن البيانات أصبحت تعرض بشكل صحيح داخل التطبيق.
[ندعوك للتسجيل في المنتدى أو التعريف بنفسك لمعاينة هذه الصورة]
 
بإمكانك أيضاً تشغيل Query معينة للتأكد بأنها تعمل بشكل صحيح إذا طبقت داخل التطبيق.
[ندعوك للتسجيل في المنتدى أو التعريف بنفسك لمعاينة هذه الصورة]
 
بإمكانك أيضاً التعديل وحذف البيانات بكل سهولة بالتحديد على الـ Row ومن ثم الضغط على Edit أو Delete.
 
لمعرفة المزيد عن هذه المكتبة بإمكانك زيارة الـ Repository الخاصة بها على Github من هنا
 
بالتوفيق Smile
صلاحيات هذا المنتدى:
لاتستطيع الرد على المواضيع في هذا المنتدى