ch23-part-1-Android-Database-sqlite-cover

آموزش اندروید-فصل ۲۳: پایگاه داده در اندروید (قسمت اول)

همه برنامه‌های کامپیوتری و موبایلی با هدف کار کردن بر روی داده‌ها یا اطلاعات توسعه می‌یابند. این اطلاعات معمولاً از منابع خارجی مانند اینترنت وارد برنامه می‌شود و پردازش می‌شود یا توسط خود برنامه تولید می‌شود. یکی از اصلی‌ترین کارهایی که بر روی داده‌ها انجام می‌شود ذخیره آن‌ها برای استفاده‌های بعدی است. داده‌ها را به روش‌های متنوعی می‌توان ذخیره کرد. مثلاً در فایل، ولی اصلی‌ترین شیوه ذخیره اطلاعات که دسترسی به داده‌ها و اطلاعات را در آینده بسیار ساده‌تر می‌کند، پایگاه داده (یا دیتابیس database) است.

اندروید هم مثل همه سیستم‌عامل‌های موجود در بازار دارای برنامه‌های متعددی است که کار اصلی آن‌ها ذخیره و بازیابی اطلاعات است. معروف‌ترین آن‌ها که به صورت پیش‌فرض در همه دستگاه‌های اندروید نصب شده است، پایگاه‌داده‌ای است به نام SQLite. این پایگاه داده کدباز (اوپن سورس open source) است و با حجم بسیار کم امکانات متنوعی را در اختیار برنامه‌ها قرار می‌دهد.

در این مطلب یک برنامه اندروید ساده می‌نویسیم که اطلاعات را در پایگاه داده ذخیره و بازیابی کند.

۱- شروع کار:

برای شروع کار یک پروژه جدید اندروید می‌سازیم. توصیه من این است که از اندروید استودیو استفاده کنید ولی خب در این پروژه خاص فرقی بین اکلیپس و اندروید استودیو نیست!

می‌خواهیم برنامه‌ای بنویسیم که نام و نام خانوادگی افراد را گرفته و آن‌ها را در پایگاه داده یا دیتابیس ذخیره کند. برای شروع فرمی شبیه فرم زیر بسازید:

ch23-01-database-data-entry-form

حتماً می‌دانید چطور باید این فرم را بسازید ولی با این حال برای کامل بودن آموزش کد طراحی برنامه را هم اینجا می‌آورم:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
        android:id="@+id/nameEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/hint_name" />

    <EditText
        android:id="@+id/familyEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/hint_family" />

    <Button
        android:id="@+id/saveButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/save"
        android:layout_gravity="center_horizontal"/>

</LinearLayout>

حالا به سراغ کد می‌رویم. باید بتوانیم متنی را که کاربر در این فرم وارد کرده است استخراج کنیم:

public class MainActivity extends AppCompatActivity {

    private EditText nameEditText;
    private EditText familyEditText;
    private Button saveButton;

    private String name;
    private String family;

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

        nameEditText = (EditText) findViewById(R.id.nameEditText);
        familyEditText = (EditText) findViewById(R.id.familyEditText);
        saveButton = (Button) findViewById(R.id.saveButton);

        saveButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                name = nameEditText.getText().toString();
                family = familyEditText.getText().toString();

            }
        });
    }
}

همانطور که می‌بینید همه چیز آماده است تا در پایگاه داده یا دیتابیس ذخیره شود!

۲- ایجاد دیتابیس:

برای شروع یک کلاس درست می‌کنیم که نشان‌دهنده اطلاعات باشد. معمولاً این کلاس‌ها را مدل می‌نامند. اشیای ساخته شده از روی این کلاس هر کدام نشان‌دهنده یک رکورد اطلاعاتی در دیتابیس و کوچک‌ترین واحد اطلاعاتی برنامه‌اند. برای شروع یک پکیج به نام مدل می‌سازیم و در آن کلاسی به نام Person با دو ویژگی name و family از نوع String:

public class Person {

    private long id;
    private String name;
    private String family;

    public Person() {
    }

    public Person(String name, String family) {
        this.name = name;
        this.family = family;
    }

    public Person(long id, String name, String family) {
        this.id = id;
        this.name = name;
        this.family = family;
    }

    public long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getFamily() {
        return family;
    }

    public void setFamily(String family) {
        this.family = family;
    }
}

برای انجام چهار عمل اصلی پایگاه داده که اصطلاحاً CRUD یا کراد گفته می‌شود و مخفف این چهار عمل است:

Create: ایجاد پایگاه داده، جدول‌ها و ذخیره کردن اطلاعات در پایگاه داده

Retrieve یا Read: هر نوع عملی که برای استخراج یا بازیابی اطلاعات از پایگاه داده

Update: هر نوع عملی که باعث تغییر در اطلاعات ذخیره شده در پایگاه داده

Delete: هر عملی که ماحصل آن حذف اطلاعات از پایگاه داده است

یک کلاس دیگر می‌سازیم و نام آن را PersonDatabaseAdapter می‌گذاریم:

public class PersonDatabaseAdapter {

    private Context context;

    public PersonDatabaseAdapter(Context context) {
        this.context = context;
    }

    public long savePerson(Person person) {
    }

    public Person readPerson(long id) {
    }

    public int updatePerson(Person person) {
    }

    public int deletePerson(long id) {
    }
}

به زودی از کاربرد ویژگی context در این کلاس مطلع خواهید شد.

از این جا به بعد یکی یکی این چهار متد را پر می‌کنیم.

برای شروع باید این کلاس PersonDatabaseAdapter را به پایگاه داده SQLite در اندروید وصل کنیم. برای این کار نیاز به یک شی از کلاس SQLiteOpenHelper داریم که همانطور از که نامش پیدا است یک کلاس کمکی است برای ایجاد دیتابیس٫

بنابرای یک ویژگی به کلاس اضافه می‌کنیم از نوع SQLiteOpenHelper و در سازنده کلاس آن را مقداردهی می‌کنیم:

public class PersonDatabaseAdapter {

    private Context context;
    private SQLiteOpenHelper sqLiteOpenHelper;

    public PersonDatabaseAdapter(Context context) {
        this.context = context;
        sqLiteOpenHelper = new SQLiteOpenHelper(context, "database.db", null, 1) {

            @Override
            public void onCreate(SQLiteDatabase db) {
            }

            @Override
            public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            }
        };
    }

    public long savePerson(Person person) {
    }

    public Person readPerson(long id) {
    }

    public int updatePerson(Person person) {
    }

    public int deletePerson(long id) {
    }
}

همانطور که می‌بینید برای ساختن یک شی از کلاس SQLiteOpenHelper باید تعدادی پارامتر را به سازنده این کلاس انتقال داد و دو متد onCreate و onUpgrade را Override یا بازنویسی کرد. متد onCreate فقط یک بار و آن هم اولین باری که دیتابیس ساخته می‌شود صدا زده می‌شود. در این متد باید کد SQL مربوط به ایجاد جداول‌ها را بنویسیم. متد onUpgrade فقط یک بار و آن هم زمانی که برنامه بروزرسانی می‌شود صدا زده می‌شود. در حال حاضر این متد را خالی می‌گذاریم.

حالا توضیح این که پارامترهای متد سازنده کلاس SQLiteOpenHelper چه چیزهایی‌اند:

context یک شی از کلاس Context است و همانطور که می‌دانید در اندروید هر زمان که سیستم قرار است برای برنامه کاری را انجام دهد، به یک شی از این کلاس نیاز دارد.

پارامتر دوم یک String با مقدار “database.db” است. این رشته نام دیتابیس را مشخص می‌کند.

توضیح پارامتر بعدی فراتر از نیاز فعلی ما است و می‌وانیم آن را null بفرستیم.

پارامتر آخر شماره ورژن پایگاه داده است که کاربرد در زمان ارتقا یا upgrade است. برای شروع ورژن دیتابیس را ۱ می‌گذاریم.

حالا برمی‌گردیم به متد onCreate. همانطور که گفتم این متد در زمان ایجاد دیتابیس و فقط یک بار صدا زده می‌شود. کد‌های ایجاد جداول اطلاعاتی در این تابع قرار می‌گیرند. برای شروع فرض کنید می‌خواهیم یک در پایگاه داده “database.db” یک جدول با نام tbl_person ایجاد کنیم که هر سطر اطلاعاتی یا رکورد آن اطلاعات یک Person باشد:

@Override
public void onCreate(SQLiteDatabase db) {
        String sql = "create table tbl_persons (id integer primary key, name text, family text)";
    db.execSQL(sql);
}

در بازنویسی متد onCreate دو خط کد اضافه کردیم. خط اول کد sql ای است که یک جدول با سه ستون در SQLite می‌سازد و خط دوم اجرا کردن آن sql‌ است.

برای اطمینان از صحت sql فوق می‌توانید از برنامه‌هایی مثل SQLite Browser یا SQLite Administrator استفاده کنید:

ch23-02-database-sqlite-administrator

متد onUpgrade را همین طور خالی رها می‌کنیم! حالا همه چیز آماده است تا یک Person را در پایگاه داده یا دیتابیس ذخیره کنیم!

ذخیره کردن اطلاعات:

برای ذخیره کردن یک Person‌ در دیتابیس متد savePerson می‌رویم. دقت کنید که این متد مقداری از نوع long برمی‌گرداند که به زودی می‌فهمید چیست و کاربردش کجا است!

این متد مقداری از نوع Person می‌گیرد و ما می‌توانیم از طریق این شی به مقادیر name و family دسترسی داشته باشیم:

public long savePerson(Person person) {
    String name = person.getName();
    String family = person.getFamily();
}

حالا یک بلوک try/catch به متد اضافه می‌کنیم. از آنجایی که ممکن است انواع خطاها و استثناها در کار با دیتابیس رخ بدهد، بهتر است کل فرایند را در یک بلوک try/catch قرار دهیم تا برنامه با force close روبرو نشود:

public long savePerson(Person person) {
    String name = person.getName();
    String family = person.getFamily();

    try {

    } catch (Exception ex) {
        Log.d("Database", "Exception:" + ex.getMessage());
    }
}

کاری که حالا باید بکنیم این است که ارتباط بین مقادیر name و family و ستون‌های جدول tbl_persons را مشخصی کنیم. یعنی باید بدانیم که هر کدام از این مقادیر قرار است در کدام ستون دیتابیس قرار بگیرند. برای این کار یک شی از روی کلاس ContentValues می‌سازیم:

public long savePerson(Person person) {
    String name = person.getName();
    String family = person.getFamily();

    try {
        ContentValues values = new ContentValues();
        values.put("name", name);
        values.put("family", family);
    } catch (Exception ex) {
        Log.d("Database", "Exception:" + ex.getMessage());
    }
}

این کار به دیتابیس می‌گوید که مقدار name در ستون name و مقدار family در ستون family قرار خواهد گرفت (دقت کنید همیشه اسم متغیرها و اسم ستون‌های دیتابیس الزاماً شبیه به هم نیستند).

بالاخره نوبت رسید به اصل کار: ذخیره اطلاعات در دیتابیس! ولی ما اینجا هیچ چیزی از دیتابیس نداریم! چطور باید به SQLite بگوییم این اطلاعات را ذخیره کند؟ خیلی ساده است: باید یک شی از کلاس SQLiteDatabase داشته باشیم. ولی چطور؟ با کمک شی sqLiteOpenHelper که پیش از این و متد سازنده کلاس آن را ساختیم:

public long savePerson(Person person) {
    String name = person.getName();
    String family = person.getFamily();

    try {
        ContentValues values = new ContentValues();
        values.put("name", name);
        values.put("family", family);

        SQLiteDatabase database = sqLiteOpenHelper.getWritableDatabase();
    } catch (Exception ex) {
        Log.d("Database", "Exception:" + ex.getMessage());
    }
}

حالا هم داده‌ها را داریم و هم مشخص کرده‌ایم هر کدام در چه ستونی قرار می‌گیرند و هم یک شی از کلاس SQLiteDatabase. حالا همه چیز آماده است تا اطلاعات را در پایگاه داده ذخیره کنیم. برای این کار از متد insert کلاس SQLiteDatabase استفاده می‌کنیم:

public long savePerson(Person person) {
    String name = person.getName();
    String family = person.getFamily();
    long id = -1;

    try {
        ContentValues values = new ContentValues();
        values.put("name", name);
        values.put("family", family);

        SQLiteDatabase database = sqLiteOpenHelper.getWritableDatabase();
        id = database.insert("tbl_persons", null, values);
    } catch (Exception ex) {
        Log.d("Database", "Exception:" + ex.getMessage());
    }

    return id;
}

همین طور که می‌بینید متد insert سه مقدار ورودی دارد. اولی نام جدولی است که می‌خواهیم اطلاعات را در آن ذخیره کنیم. دومی متغیری است که می‌گوید اگر ستونی در جدول هست که ما اینجا مقداری برای آن مشخص نکرده‌ایم، چه مقداری را در آن قرار دهد که با null فرستادن عملاً به دیتابیس می‌گوییم آن‌ها را Null قرار دهد. سومین ورودی هم که مقادیر ما است. اما این تابع مقداری را هم برمی‌گرداند. این مقدار چیست؟ معمولاً در دیتابیس هر جدولی یک ستون دارد که شناسه یا ID رکوردهای ذخیره شده را نگه می‌دارد. این شناسه یکتا است و هرگز تکراری نمی‌شود. روش‌های زیادی برای ایجاد شناسه وجود دارد که ساده‌ترین آن مقادیر عددی است. اگر دقت کرده باشید در زمان تعریف SQL ساخت جدول یک ستون به نام id از نوع integer primary key تعریف کردیم. این ستون یک ستون کلید یا شناسه است و از آنجایی که نوع آن integer تعریف شده است، هر بار که یک رکورد به دیتابیس اضافه می‌شود، به طور خودکار id آخرین رکورد قبلی با یک جمع شده و در این ستون قرار می‌گیرد و مقدار آن را تابع insert برمی‌گرداند. حالا می‌دانید که آن long که در تعریف تابع savePerson آوردیم چیست.

اگر فکر می‌کنید کار ما تمام شده است اشتباه می‌کنید. حتماً می‌گویید حالا که اطلاعات را در دیتابیس ذخیره کردیم و id را هم گرفته‌ایم دیگر چه کاری باید بکنیم؟ باید شی SQLiteDatabase ساخته شده را ببندیم. این‌ها اشیایی سنگین هستند و باز گذاشتن آن‌ها اصلاً کار صحیحی نیست. بنابراین به بلوک try/catch یک بلوک finally اضافه می‌کنیم و database را آنجا می‌بندیم:

بعد از اعمال تغییرات فوق متد savePerson به شکل زیر در می‌آید:

public long savePerson(Person person) {
	String name = person.getName();
	String family = person.getFamily();
	long id = -1;

	SQLiteDatabase database = null;

	try {
		ContentValues values = new ContentValues();
		values.put("name", name);
		values.put("family", family);

		database = sqLiteOpenHelper.getWritableDatabase();
		id = database.insert("tbl_persons", null, values);
	} catch (Exception ex) {
		Log.d("Database", "Exception:" + ex.getMessage());
	} finally {
		if( database != null && database.isOpen()) {
			database.close();
		}
	}

	return id;
}

در قسمت بعدی به سراغ سایر توابع PersonDatabaseAdapter خواهیم رفت! نظرات ارزشمند خودتان را از من دریغ نکنید!

facebooktwittergoogle_plusredditpinterestlinkedinmailfacebooktwittergoogle_plusredditpinterestlinkedinmail

25 فکر می‌کنند “آموزش اندروید-فصل ۲۳: پایگاه داده در اندروید (قسمت اول)

  1. امین

    مثل همیشه خلی خوب بود
    منتظر قسمت های بعدی و مخصوصا شیوه ها و متد های جدید برنامه نویسی آندریود از شما استاد گرانقدر هستم
    با تشکر

    پاسخ
  2. رضا

    سلام خیلی خوبه استاد… واقعا معرکه اس فن بیان و تدریستون… ای کاش میدونستیم کجا هستین تا تو کلاساتون شرکت میکردیم و استفاده میکردیم… اگر در تهران هستین و کلاس دارین حتما به بنده لطف کنید ایمیل بدین. بازم ممنون

    پاسخ
  3. ehsan

    با سلام و خسته نباشید
    میخواستم بدونم انتخاب دیتا بیس شما کجا انجام شده و ایا در کلاس savePerson تون نام دیتا بیستون رو انتخاب نکردید و چرا در کدهاتون از PersonDatabaseAdapter
    استفاده نکردید
    با تشکر از مطالب خوبتون

    پاسخ
    1. علی بهزادیان نژاد نویسنده

      سلام
      کد رو اصلاح کردم.
      از کلاس PersonDatabaseAdapter در ادامه مطلب به کرات استفاده می‌کنیم. ادامه مطلب را بخوانید.
      سپاسگزارم

      پاسخ
  4. فرهاد

    سلام
    دوست عزیز ، من میخوام توی برنامم از یه پایگاه داده اماده استفاده کنم و اونو داخل یه لیست مثل Auto complete list view
    بریزم و نمایش بدم
    ینی نمیخوام چیزی داخل دیتا بیسم ذخیره بشه بلکه فقط میخوام اطلاعات داخلشو ببینم و جستجو کنم
    مثل فال حافظ
    میشه لطفا بگید چجوری این کارو بکنم؟
    ممنون

    پاسخ
  5. yasiiii

    سلام .. من پیاده سازی رو طبق مطالب پیش رفتم ولی در دو قسمت ارور دارم : ۱- در قسمت تعریف

    public long savePerson(Person person) {

    String unitnumber = unitnumber.getUnitnumber();
    String owner = owner.getOwner();
    String phone = phone.getPhone();
    String mobile = mobile.getMobile();
    …..

    که از توابع getunitnumber و getowner و … ارور میگیره و پیغامش هم the method is undifine for type string هست … ذر صورتی که من تعاریفم رو چک کردم و جایی مغایرتی تو تعریف ها ندیدم !!
    و دومین ارور :

    finally{
    if(database != null && database.isOpen()){
    database.close();
    }

    در این قسمت هست و از هر سه متغیر database ارور میگیره و پیغامش database cannot be resolved هستش !!!

    من این قسمت اول آموزش رو طبق گفته های شما پیش رفتم .. نمیدونم پرا این ارورهارو داره !!!

    پاسخ
  6. میثم

    سلا
    از آموزشهای بسیار خوب و قدم به قدمتون و توضیحات روان و شیوای شما بسیار ممنونم
    استفاده میبر من تازه کار

    سپاس

    فقط یک چیزی روی دلم مونده اونم اینکه خداییش فکر کنم بد عذابی هست برای منِ دات نت کار؛
    کار با این جاوا! :)

    یعنی یک setter getter اتوماتیک نداره ؟ که مجبور به تعریف دستی نباشیم؟

    با تشکر

    پاسخ
    1. علی بهزادیان نژاد نویسنده

      :)
      منم که از محیط جاوا به دات نت رفته بودم مشکلات مشابهی داشتم! سعی کنید یه بار شورت‌کات‌ها و ابزارهای IDE رو مطالعه کنید. برای ساخت متدهای get و set دو راه ساده وجود داره:

      ۱- بعد از تعریف فیلدهای کلاس، کلید ترکیبی Shift+Insert رو بزنید و از منوی باز شده ایجاد متدهای get و set رو انتخاب کنید و بینگو! همه متدها رو با صورت استاندارد براتون می‌سازه!

      ۲- استفاده از کتابخانه Lombok که امسال جزو محبوبترین و پرکاربردترین کتابخانه‌های جاوا بود. این کتابخانه با استفاده از Annotation (همون Attribute در محیط دات نت) خیلی چیزها رو برای شما می سازه: https://projectlombok.org

      پاسخ
  7. Yecim

    سلام.
    ممنونم از توضیحات بسیار خوبتون واقعا عالی آموزش میدید.
    در مورد این آموزش یه سوال دارم.
    مسیر این دیتا بیس کجا هست تا بتونم اونو در sqlite admin باز کنم و تغییرات رو ببینم؟
    ممنون میشم جواب بدید

    پاسخ
    1. علی بهزادیان نژاد نویسنده

      تعداد سازنده‌ها هیچ محدودیتی نداره و هر تعداد که لازم داشتید می‌تونید اضافه کنید.

      پاسخ
  8. Ali

    سلام
    دیتا بیس واسه من ایجاد نشد
    چه جوری کد های کلاس ها اجرا میشن
    مثلا وقتی منغییر ها تغییر می کنند دیتا بیس افزوده میشه یا چه جوری ؟
    لطفا زود جواب بدین

    پاسخ
    1. علی بهزادیان نژاد نویسنده

      سلام
      چطور مطمئن شدید که دیتابیس ایجاد نشده است؟
      با تغییر دادن مقدار متغیرها و اشیا دیتابیس به طور خودکار آپدیت نمی‌شود و شما خودتون باید کوئری آپدیت به دیتابیس بزنید.
      فصل‌های ۲۴، ۲۵ و ۲۶ ادامه این مطلب هستند. آنها را هم مطالعه کنید. جواب سؤال شما آنجا است.

      پاسخ
  9. مهدی

    سلام
    من همین دیتابیس رو نوشتم اما برای متد اضافه کردن و حذف از دیتابیس از متغیری از جنس boolean استفاده کردم

    به نظر شما کدوم راه بهتره؟

    پاسخ

پاسخ دهید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

شما می‌توانید از این دستورات HTML استفاده کنید: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>