سورس کد نمایش لیست در کاتلین – آموزش برنامه نویسی kotlin ، در این پست از تجاری اپ میخوایم کمی پروژه محور تر به کاتلین نگاه کنیم و نمایش لیست با recyclerview در کاتلین (پروژه نمایش لیست کتابها در کاتلین) را آموزش بدیم .بهتون پیشنهاد میکنم که اگر پست های قبلی آموزش کاتلین تجاری اپ رو مطالعه نکردید حتما مطالعه کنید و بعد این پست رو مطالعه و تمرین کنید.
در این پروژه میخوایم دیتا یک سری کتاب که درون دیتابیس sqlite درون اپلیکیشن ذخیره شده رو واکشی و درون یک recyclerView ( نمایش لیست با recyclerview در کاتلین ) نمایش بدیم.
پس قبل از هرچیز یک پروژه کاتلین ایجاد میکنیم ، با کلیک برروی
start a new Android studio project
یک پروژه جدید ایجاد میکنیم.مرحله بعد گزینه Empty Activity رو انتخاب میکنیم و در مرحله آخر مطابق تصویر زیر گزینه language رو حتما kotlin انتخاب میکنیم
حالا خواهیم دید که درون فایل Gradle پروژه وابستگی های مربوط به کاتلین ایجاد شده و میتونیم خیلی راحت کدهای کاتلین رو بزنیم.
پس شروع میکنیم به کدنویسی 🙂
اولین دستوری که باید بنویسیم اضافه کردن وابستگی های sqlite هستش برای اینکه بتونیم از دیتابیس sqlite درون اپلیکیشن استفاده کنیم پس دستورات زیر رو به گردل برنامه اضافه میکنیم
implementation 'com.readystatesoftware.sqliteasset:sqliteassethelper:2.0.1'
خب حالا باید با استفاده از نرم افزار DB Browser for SQLite یک دیتابیس ایجاد کنیم و بعد فایل دیتابیس sqlite ایجاد شده رو درون پروژه اندروید ایمپورت کنیم
همچنین بخوانید: آموزش نرم افزار DB Browser Sqlite
من یک دیتابیس با نام BooksDB و درون آن یک جدول با نام tbl_books ایجاد کردم و جدول رو بدین صورت طراحی کردم
حالا میتونیم فایل دیتابیس sqlite رو به پروژه ایمپورت کنیم
خب الان فایل دیتابیس sqlite که حاوی اطلاعات یک سری کتاب هست رو درون پروژه اندروید خود داریم و میتونیم از دیتاهای داخلش استفاده کنیم
پس قبل از هرکار باید کلاس های مورد نیاز برای دسترسی به دیتابیس رو ایجاد کنیم
پس بریم سراغ کدنویسی 🙂 !
درون دایرکتوری جاوا یک پکیج با عنوان db ایجاد میکنیم و کلاس های مربوط به دیتابیس رو درون این پکیج ایجاد میکنیم ، پکیج رو با کلیک راست برروی فولدر اصلی کلاس های جاوا یعنی:
java / com.tejaripp.kotlinprac
و سپس New / package ایجاد میکنیم
حالا درون پکیج db یک کلاس جاوا با عنوان DataBaseOpenHelper برای ایجاد بستر دسترسی به دیتابیس ایجاد میکنیم و درون آن دستورات زیر را مینویسیم
package com.tejariapp.kotlinprac.db
import android.content.Context
import com.readystatesoftware.sqliteasset.SQLiteAssetHelper
class DataBaseOpenHelper(context: Context) : SQLiteAssetHelper(context, DATABASE_NAME, null, DATABASE_VERSION) {
companion object {
private val DATABASE_NAME = "BooksDB.db"
private val DATABASE_VERSION = 1
}
}
کلاس ایجاد شده از کلاس SQLiteAssetHelper مربوط به کتابخانه sqliteassethelper ارث بری میکند و همونطور که مشخصه دو متغیر companion داریم نام فایل دیتابیس و ورژن دیتابیس رو مشخص کردیم (توجه کنید که نام دیتابیس دقیقا نام همان فایلی که درون مسیر زیر قرار دادیم باشد)
src / main / assets / databases /
و یک ورژن برای دیتابیس که درواقع بیشتر زمانی کاربرد دارد که میخواهیم آپدیت هایی برروی دیتابیس بزنیم و ورژن بندی کنیم
و در ادامه هم مقادیر مورد نیاز سازنده کلاس پدر را برایش ارسال کردیم
همچنین بخوانید: کلاس و شی در کاتلین
حالا یک کلاس کاتلین درون پکیج db بصورت زیر ایجاد میکنیم
New / Kotlin FileClass
و یک کلاس با عنوان Books ایجاد میکنیم سپس دستورات زیر را درون کلاس کاتلین Books قرار میدهیم:
package com.tejariapp.kotlinprac.db
data class Books(val id:Int,val name: String , val img: String , val date:String , val writer: String)
کلاس Books درواقع برای گرفتن دیتاها از دیتابیس کاربرد دارد که درادامه از آن استفاده خواهیم کرد.همونطور که میبینید ما از data class استفاده کردیم چون میخواهیم یک سری دیتا به این کلاس بدهیم و از آن استفاده کنیم به علاوه فیلدهایی که برای این کلاس کاتلین مشخص کردیم دقیقا همان فیلدهای جدولی ست که درون دیتابیس ایجاد کردیم و همه بصورت val تعریف شدند چرا که مقادیری که از دیتابیس درون این فیلدها قرار گرفت هیچوقت نیاز به تغییر نخواهند داشت و فقط قرار است درون اپلیکیشن نمایش داده شود
خب حالا یک کلاس دیگر درون پکیج db با عنوان DatabaseAccess ایجاد میکنیم برای گرفتن داده ها از دیتابیس
package com.tejariapp.kotlinprac.db
import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import java.util.*
class DatabaseAccess private constructor(context: Context) {
private val openHelper: SQLiteOpenHelper
private lateinit var db: SQLiteDatabase
lateinit var c: Cursor
init {
this.openHelper = DataBaseOpenHelper(context)
}
// open database connection
private fun open() {
this.db = openHelper.writableDatabase
}
// close database connection
private fun close() {
this.db.close()
}
companion object {
private var instance: DatabaseAccess? = null
fun getInstance(context: Context): DatabaseAccess {
if (instance == null)
instance = DatabaseAccess(context)
return instance as DatabaseAccess
}
}
fun getBooks(): ArrayList<Books> {
open()
val data = ArrayList<Books>()
c = db.query("tbl_books", arrayOf("id", "name", "img", "date", "writer"), null, null, null, null, null)
while (c.moveToNext()) {
data.add(Books(c.getInt(0), c.getString(1), c.getString(2)
, c.getString(3), c.getString(4)))
}
close()
return data
}
}
کلاس DatabaseAccess همانطور که مشخصه یک سازنده اصلی و البته private دارد که تنها یک پارامتر context میگیرد که از این کانستراکتور یا سازنده در متد getInstance که بصورت comopanion تعریف شده استفاده میشود.
در بدنه کلاس هم نمونه هایی از کلاس های SqliteOpenHelper ، SqliteDatabase و Cursor ایجاد شده که درادامه کدهای کلاس از تمامی آنها استفاده شده.
در بلاک init که اولین بلاک پس از ساخت یک نمونه از کلاس اجرا میشه فیلد db مقداردهی شده برای استفاده از آن به عنوان باز و بسته کردن دریچه ی دسترسی به دیتابیس در متدهای open و close وهمچنین اجرای کوئری های دریافت اطلاعات از دیتابیس.
یک متد getBooks هم داریم که خروجی آن از نوع ArrayList است و با اجرای کوئری select از جدول tbl_books که درون فایل دیتابیس ایجاد کردیم تمامی رکوردها با تمامی فیلدها را انتخاب و دریافت میکند سپس با استفاده از فیلد cursor یکی یکی رکورد هارو به یک شی از کلاس Books که در بالا ایجاد کردیم تبدیل میکنیم و در نهایت همه را درون یک لیست به عنوان خروجی متد برمیگردانیم.
خب حالا باید یک recyclerView درون MainActivity پیاده و اداپتر آن را کانفیگ کنیم پس درون لایه activity_main یک recyclerView بصورت زیر پیاده میکنیم
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
به علاوه یک لایه دیگر برای آیتم های درون لیست با نام view_book_item ایجاد میکنیم با محتویات زیر:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
app:cardCornerRadius="5dp"
app:cardElevation="5dp">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/iv_profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@mipmap/ic_launcher" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="نام کتاب :"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/tv_name"
app:layout_constraintTop_toBottomOf="@+id/iv_profile" />
<TextView
android:id="@+id/tv_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:gravity="right"
android:text="TextView"
app:layout_constraintEnd_toStartOf="@+id/textView"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/textView" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="نام نویسنده کتاب :"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/tv_writer"
app:layout_constraintTop_toBottomOf="@+id/tv_name" />
<TextView
android:id="@+id/tv_writer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:gravity="right"
android:text="TextView"
app:layout_constraintEnd_toStartOf="@+id/textView3"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/textView3" />
<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:text="سال انتشار کتاب :"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/tv_date"
app:layout_constraintTop_toBottomOf="@+id/tv_writer" />
<TextView
android:id="@+id/tv_date"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:gravity="right"
android:text="TextView"
app:layout_constraintEnd_toStartOf="@+id/textView5"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/textView5" />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
حالا یک کلاس کاتلین BooksAdapter درون پکیج اصلی کلاس ها کنار MainActivity ایجاد میکنیم
درون این کلاس دستورات اداپتر RecyclerView رو مطابق زیر مینویسیم
package com.tejariapp.kotlinprac
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.bumptech.glide.Glide
import com.tejariapp.kotlinprac.db.Books
import kotlinx.android.synthetic.main.view_book_item.view.*
class BooksAdapter(private val mContext: Context, private val mList: ArrayList<Books>) : RecyclerView.Adapter<BooksAdapter.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, pos: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.view_book_item, parent, false)
return MyViewHolder(view)
}
override fun getItemCount(): Int = mList.size
override fun onBindViewHolder(holder: MyViewHolder, pos: Int) {
val book = mList[pos]
holder.setItems(mContext,book)
}
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun setItems(mContext: Context,book: Books) {
itemView.tv_name.text = book.name
itemView.tv_date.text = book.date
itemView.tv_writer.text = book.writer
Glide
.with(mContext)
.load(book.img)
.centerCrop()
.placeholder(R.mipmap.ic_launcher)
.into(itemView.iv_profile)
}
}
}
ما از کتابخونه Glide برای لود کردن تصاویر استفاده کردیم پس وابستگی یا dependency زیر رو به گردل پروژه اضافه میکنیم
https://github.com/bumptech/glide
build.gradle (app)
implementation 'com.github.bumptech.glide:glide:4.9.0'
build.gradle (project)
repositories {
mavenCentral()
google()
}
اداپتر ریسایکلر ویو مانند اداپتر های جاواست اما با کمی تفاوت سینتکسی.درابتدا ما در سازنده اصلی کلاس اداپتر دو مقدار context و mlist گرفتیم که درواقع mlist همان لیست کتاب هایی ست که از دیتابیس دریافت کردیم و باید درون recyclerView نمایش دهیم.
در متد onBindViewHolder برای هر آیتم لیست متدی که درون ViewHolder اداپتر تعریف شده رو برای مقدار دهی به ویو های درون لایه آیتم لیست فراخوانی میکنیم.
یک نکته جالب درباره کاتلین کوتاه کننده متدهای بازگشتی ست . همانطور که متد getItemCount رو میبینید چون یک مقدار int رو برمیگردونه و بدنه این متدهم تک خطی ست و همان خط هم مقدار مورد نظر رو برمیگردونه میتونیم بجای نوشتن این متد بصورت زیر
override fun getItemCount(): Int {
return mList.size
}
از کوتاه کننده های کاتلین استفاده کنیم و بصورت زیر این متد رو پیاده کنیم
override fun getItemCount(): Int = mList.size
حالا دستورات نهایی رو درون کلاس MainActivity بدین صورت مینویسیم
package com.tejariapp.kotlinprac
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.tejariapp.kotlinprac.db.Books
import com.tejariapp.kotlinprac.db.DatabaseAccess
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recycler.layoutManager = LinearLayoutManager(this)
getData()
}
private fun getData(){
var list: ArrayList<Books>
val access = DatabaseAccess.getInstance(this)
list = access.getBooks()
recycler.adapter = BooksAdapter(this,list)
}
}
در نهایت پروژه رو اجرا کنید و نتیجه رو بدین صورت ببینید
2 Comments
سلام وقت بخیر
لطفا برای این اموزش
https://www.tejariapp.com/source-code-display-list-in-kotlin/
یک جستجو هم قرار بدید
هزینشم درخدمتم
با سلام
سورس آماده ست ، هزینه ۶۰ تومن
سرچ هم براساس نام کتاب و نام نویسنده براتون میذاریم.
با احترام