شرح استخدام Rxjava مع Room في Android Studio
في الدروس السابقة شرحنا لكم room و rx java وفي هذا المقال سوف نقوم بعمل مشروع بسيط بهم وهو مفكرة لحفظ البيانات اولا سوف نستغني عن NoteDetails.class و RoomConverter لان عملنا لن يحتاج الى وضع بيانات داخل array وتحويلهم لjson لذلك سوف نذهب الى NoteEntity.class وبعدها سنقوم بحذف NoteDetails.class منها لاننا لن نستخدمها وايضا سوف نحذف priority لاننا لن نحتاجها فقط نحتاج الى name و content يمكنك تغيير الاسم الى العنوان .
من اكثر المهارات التي تطلب بكثره في سوق العمل في الاونه الحاليه و هي مطور تطبيقات وخصوصا مطور تطبيقات ios والاندرويد , حاول الدخول الى احد المواقع الخاصه بالعمل الحر سوف تجد ان اكثر الاعمال التي تطلب لمطور التطبيقات ومصمم المواقع والى الديزاينر. حاول دائما تعلم احد هذه المهارات سواءا مطور مواقع او مطور تطبيقات او حتى مصمم ولكن انصحك تعلم اي مهاره تتعلق في البرمجه وذلك لعده اسباب اولا يكون المبلغ المقبوض منها اكثر من راتب المصمم ايضا يساعدك موقعنا في تصميم وانشاء تطبيقات التي تريدها وايضا سوف تجد ان اغلب الشركات تبحث عن مطورين. ناجحين ذو سابقه اعمال قويه للعمل معه.
ويعد برنامج اندرويد استوديو واحد من اقوى البرامج التي يمكنك استعمالها في انشاء وتطوير التطبيقات سواء باستخدام لغه الجافا وكوتلن او حتى لغة درات المخصصه لflutter وسوف نقوم في الايام المقبله بشرح لكم الفلاتر وكيف تحميله وتثبيته و كيفيه انشاء تطبيقات عليه ولكن كل هذا في الايام المقبله باذن الله تعالى حاول دائما نتعلم على احد اللغات , في الفترة الحاليه نقوم بشرح لكم java لذلك حاول تعلمها بشكل جيد الفتره نفسها تقريبا من اغلب اللغات اذا فهمت الاساسيات سوف تستطيع التعامل مع اي لغه برمجه اخرى العمليه تختلف فقط في طريقة الكتابه , فقط هي التي تختلف ولكن طريقه التفكير واحده نفس الخوارزميات تقريبا ولكن كما اخبرتكم فان طريقة للكتابه فقط التي تختلف برنامج android studio برنامج قوي جدا تستطيع التعامل معه في انشاء وتطوير تطبيقاتك.
NoteEntity.class
@Entity(tableName = "NoteTable")
public class NoteEntity {
@ColumnInfo (name = "name")
private String name;
@ColumnInfo (name = "content")
private String content;
@PrimaryKey (autoGenerate = true)
private int id;
public NoteEntity(String name, String content) {
this.name = name;
this.content = content;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
الخطوة التالية سوف ننتقل الى NoteDatabase ونقوم بعمل بعض الاشياء البسيطة هنا وهو اولا سنقوم باضافة synchronized الى الاسم NoteDatabase لكي نستطيع تمرير البيانات بسهوله من مكان لاخر , سنقوم بإضافة fallbackToDestructiveMigration الى الكود instance وهذا لكي لا يحدث مشاكل في الكود وتخزين البيانات واحذف الامر allowMainThreadQueries لاننا سنعمل على room وفقط هذة هي التعديلات البسيطة في هذا الكلاس
NoteDatabase.class
@Database(entities = NoteEntity.class, version = 2)
@TypeConverters(RoomConverter.class)
public abstract class NoteDatabase extends RoomDatabase {
private static NoteDatabase instance;
public abstract NoteDAO noteDAO();
public static synchronized NoteDatabase getInstance(Context context) {
if (instance == null) {
instance = Room.databaseBuilder(context.getApplicationContext(), NoteDatabase.class, "NoteDatabase")
.fallbackToDestructiveMigration()
.build();
}
return instance;
}
}
الان انتقل الى ملف NoteDAO وهنا سوف تشاهد ظهور rx java في الروم حيث ان كل عنصر تريدة قم بعمل له Completable او Single للInsert و Query وDelete حيث ان Single ان العنصر يظهر عندما يبدء التطبيق و Completable عندما تكتمل البيانات وفي طبيعة الحال لن تشاهد اي فرق استخدم ما تريد منهم وهنا سوف نستخدمهم ال2 لكي اوريكم كيف يعملون فقط .
interface NoteDAO
public interface NoteDAO {
@Insert
Completable insertNote (NoteEntity note);
@Query("Select * from NoteTable")
Single <List<NoteEntity>> getnote ();
@Delete
Completable deletenote(NoteEntity note);
@Query("Delete from NoteTable")
Completable deleteallnote ();
}
الان تعالوا نقوم بعمل ui بسيط للتطبيق الخاص بنا وبكل بساطة نريد عمل مكان لكتابة عنوان الملاحظة واخر لمحتويات الملاحظه واسفلها 3 ازرار او 2 كما تريد واحد لاضافة البيانات واخر لجلب البيانات والاخير لحذف البيانات واسفلهم recyclerview تقوم باضافة الملاحظات فيها .
activity_main
<LinearLayout
android:orientation="vertical"
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">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editTexttitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:ems="10"
android:hint="title" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editTextBody"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:inputType="textPersonName"
android:hint="body" />
<LinearLayout
android:layout_gravity="center"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="@+id/insertButton"
android:layout_margin="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="insert"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/editTextBody" />
<Button
android:id="@+id/getButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:text="get" />
<Button
android:id="@+id/delButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="delete"
android:layout_margin="20dp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/posts_recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
الان سوف نقوم بعمل activity جديد باسم note وهي تحتوي على نص باللون البنفسجي وستايل bold والاخر نص عادي للمحتوى وهذا ما سوف نقوم بتشغيله على Recyclerview .
note_activity
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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="wrap_content">
<TextView
android:id="@+id/item_title_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:textColor="#7A2DE6"
android:textSize="18dp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.045"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="MissingConstraints" />
<TextView
android:id="@+id/item_body_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="TextView"
android:textSize="18dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.045"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/item_title_textView" />
</androidx.constraintlayout.widget.ConstraintLayout>
الان قم بعمل كلاس جديد باسم RecyclerAdapter لنقوم بعمل Recycler له اولا عرف List<NoteEntity> وهو الكلاس الذي يحمل البيانات وsetPostsList لكي تقوم بارسال المعطيات من خلال المستخدم وليس من طرفك واكمل باقي التعريف كما تعلمنا سابقا في درس كيفية عملل recyclerview للاندرويد ستوديو .
RecyclerAdapter.class
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.PostsViewHolder> {
private List<NoteEntity> postsList = new ArrayList<>();
@NonNull
@Override
public PostsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new PostsViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.note,parent,false));
}
@Override
public void onBindViewHolder(@NonNull PostsViewHolder holder, int position) {
holder.titleTV.setText(postsList.get(position).getName());
holder.bodyTV.setText(postsList.get(position).getContent());
}
public void setPostsList(List<NoteEntity> postsList) {
this.postsList = postsList;
notifyDataSetChanged();
}
public class PostsViewHolder extends RecyclerView.ViewHolder {
private TextView titleTV, bodyTV;
public PostsViewHolder(@NonNull View itemView) {
super(itemView);
titleTV = itemView.findViewById(R.id.item_title_textView);
bodyTV = itemView.findViewById(R.id.item_body_textView);
}
}
@Override
public int getItemCount() {
return postsList.size();
}
}
الان ارجع الى MainActivity وقم بكتابة التعاريف وهي RecyclerView و Button و EditText قم بتعريف المتغيرات عن طريق findViewById وبعدها قم بتعريف RecyclerAdapter و setLayoutManager وكل هذا تحدثنا عليه سابقا والان قم بعمل setOnClickListener لكل زر من الازرار , قم بكتابة noteDatabase.noteDAO() واختر بعدها الوظيفة التي تريدها سواء insertNote او getnote اذا كان اختيارك insertNote سوف تحتاج الى بعدها قم بعمل new NoteEntity وبعدها اكتب المتغيرات التي تريدها وهنا نريد استلام البيانات من المستخدم لذلك سوف يكون النص noteTitle.getEditableText().toString() والنص الاخر نفس الوضع وبعدها قم بعمل اشتراك subscribeOn داخل Schedulers.computation وبعدها observeOn وبعدها subscribe مثل ما تعملنا في java rx تماما سوف تخرج لنا مجموعة الاحتمالات onSubscribe و onComplete و onError في insert اتركها لا تضع بهم شيئ ولكن في getnote سوف تخبر الadapter انه هناك تغييرات و notifyDataSetChanged لكي يحدث البيانات عندما يوجد تغيير .
#7
private void room_with_rx
private void room_with_rx() {
// لعمل الروم يجب ان تتوفر المتطلبات التالية
// Entity ( Table class ).
// DAO Data access ( interface ).
// Database ( Abstract Class ).
insertBtn = findViewById(R.id.insertButton);
getBtn = findViewById(R.id.getButton);
deldata =findViewById(R.id.delButton);
noteTitle = findViewById(R.id.editTexttitle);
bodyEt = findViewById(R.id.editTextBody);
postsRecyclerView = findViewById(R.id.posts_recyclerView);
RecyclerAdapter adapter = new RecyclerAdapter();
postsRecyclerView.setLayoutManager(new LinearLayoutManager(this));
postsRecyclerView.setAdapter(adapter);
NoteDatabase noteDatabase = NoteDatabase.getInstance(this);
// NoteEntity noteEntity =new NoteEntity(noteTitle.getEditableText().toString(),bodyEt.getEditableText().toString());
insertBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
noteDatabase.noteDAO().insertNote(new NoteEntity(noteTitle.getEditableText().toString(),bodyEt.getEditableText().toString()))
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onComplete() {
}
@Override
public void onError(Throwable e) {
}
});
}
});
getBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
noteDatabase.noteDAO().getnote()
.subscribeOn(Schedulers.computation())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new SingleObserver<List<NoteEntity>>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onSuccess(List<NoteEntity> posts) {
adapter.setPostsList(posts);
adapter.notifyDataSetChanged();
Log.i(TAG, "onSuccess: "+posts);
}
@Override
public void onError(Throwable e) {
}
});
}
});
}
انا اعلم الموضوع من اول مره يكون صعب ومعقد ولكن يجب ان تفهمه جيد وسوف اضع لكم لينك github به جميع الاكواد التي استخدمناها في بناء الroom و الshared لانها مهمه وسوف تستخدمها بكثرة , الموضوع ليس بالسهل كما اخبرتكم وانا شخصيا اعاني منه حاليا واحاول ان اتدرب على امثلة اكثر لكي ترسخ الفكرة معي وايضا اقوم بتدوين لكم كل الافكار تقريبا التي استخدمها في هذا الموقع بشكل مجاني لكم , من اجل ان يستفاد الجميع .
لمزيد من الاكواد والدروس في Room يمكنك متابعة باقي السلسلة من خلال احد المواضيع التالية