قسمت های دیگر این مطلب:

در این قسمت قصد داریم برنامه اندرویدی خود را به پایگاه داده SQLite مجهز کنیم.برخی برنامه‌هایی که برای گوشی‌های همراه ایجاد می‌شوند دارای اطلاعات گسترده‌ای هستند که باید با نظم خاصی به نمایش در بیایند، به همین دلیل ناگزیر به استفاده از پایگاه داده هستیم.

اگر با پایگاه داده آشنا نیستید مطلب پایگاه داده چیست را از دست ندهید.

سیستم دیتابیس پیشفرض اندروید SQLite است، هر چند سیستم‌های دیگری نیز وجود دارند ولی استفاده از SQLite از سوی گوگل توصیه شده است.

مطلب آشنایی با پایگاه داده SQLite

دیتابیس را به دو روش در اندروید استفاده می‌کنند:

  1. ایجاد دیتابیس هنگام اولین اجرای نرم افزار، و دریافت اطلاعات از سمت سرور و یا کاربر و ذخیره آن‌ها درون دیتابیس تازه ایجاد شده.
  2. استفاده از دیتابیس پیش ساخته و انتقال آن به پوشه نرم افزار و استفاده از اطلاعات آن.

روش اول: در روش اول دیتابیس در اولین اجرای نرم افزار ایجاد می‌شود و اطلاعات به تدریج در آن قرار می‌گیرد. فرض کنید یک اپلیکیشن شعر دارید، وقتی کاربر به اینترنت متصل باشد اطلاعات شعرها دریافت می‌گردد و در اتصال‌های بعدی به اینترنت بررسی می‌شود که شعر جدیدی وجود دارد یا خیر. در صورت موجود بودن شعر‌های جدید نیز به پایگاه داده افزوده می‌شوند.

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

ایجاد یک دیتابیس هنگام اجرای نرم افزار

در ادامه قصد داریم با توجه به آموزش‌های قسمت‌های قبل اطلاعات را از اینترنت دریافت و با استفاده از دیتا مدل Posts دیتابیس را مقدار دهی کنیم.

دیتا مدل Posts را در پکیج ir.hitos.models به شرح زیر ایجاد می‌کنیم:

package ir.hitos.models;

public class Posts {
    private int id;
    private String title;
    private String intro;
    private String fullPost;
    private String date;
    private String image;

    public int getId() {
        return id;
    }

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

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getIntro() {
        return intro;
    }

    public void setIntro(String intro) {
        this.intro = intro;
    }

    public String getFullPost() {
        return fullPost;
    }

    public void setFullPost(String fullPost) {
        this.fullPost = fullPost;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }
}

روی نام پکیج اصلی نرم افزار یعنی ir.hitos.hitos  راست کلیک کرده و روی New و از آن Java Class کلیک کنید. یک کلاس با نام HitosSQLiteOpenHelper ایجاد می‌کنیم، و درون آن اطلاعات زیر را قرار می‌دهیم:

package ir.hitos.hitos;
import android.database.sqlite.SQLiteOpenHelper;
public class HitosSQLiteOpenHelper extends SQLiteOpenHelper{
}

همانطور که در بالا می‌بینید HitosSQLiteOpenHelper در واقع extends شده از SQLiteOpenHelper است.

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

اگر مثال فوق را در اندروید استودیو ببینید زیر نام کلاس یک خط قرمز کشیده می‌شود، روی نام کلاس کلیک کرده و Alt + Enter را فشار دهید. از لیست نمایش داده شده Implement methods را انتخاب کنید تا متدهای ضروری کلاس SQLiteOpenHelper به کلاس شما افزوده شوند.

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

متد onCreate: این متد زمانی اجرا می‌شود که پایگاه داده برای اولین بار در حال ایجاد شدن است. این متد به صورت خودکار فراخوانی خواهد شد.

متد onUpgrade: وقتی یک نرم افزار را برای اولین بار در گوشی نصب می‌کنید طبیعتا دیتابیس نیازی به بروز شدن و استفاده از متد onUpgrade ندارد. حال فرض کنید نرم افزار در گوشی شما موجود است و شما قصد دارید نرم افزار خود را بروز رسانی کنید، و نرم افزار بروز رسانی شده شامل تغییراتی در پایگاه داده باشد. در این حالت متد onUpgrade با توجه به ورژن پایگاه داده (در ادامه معرفی می‌شود) پایگاه داده قبلی را متناسب با بروز رسانی نرم افزار برای شما ویرایش می‌کند.

اگر دقت کرده باشید هنوز زیر نام کلاس خط قرمز موجود است که دوباره Alt + Enter را کلیک کرده و Creat Constructors matching super را انتخاب و پنجره باز شده را تایید کنید. یک متد سازنده همنام با نام کلاس شما ایجاد می‌شود. سورس پیشفرض این سازنده به شرح زیر است: سازنده این کلاس چهار ورودی دارد که در زیر آن‌ها را شرح می‌دهیم:

    public HitosSQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

context: با استفاده از context‌ها امکان استفاده از Resource‌ها را پیدا می‌کنیم.

name: نام پایگاه داده را باید اینجا وارد کنیم، بنابراین می‌توانید نام پایگاه داده را برای این ورودی از نوع String وارد کنید.

factory: از این ورودی برای انجام عملیات پیش فرض هنگام هر بار فراخوانی پایگاه داده استفاده می‌کنند که ما آن را به null تبدیل می‌کنیم.

version: ورژن فعلی پایگاه داده نرم افزار را در این بخش وارد می‌کنیم، تا در آینده بروز رسانی پایگاه داده را بوسیله آن بتوانیم انجام دهیم. ورودی این ورودی به صورت int است.

در نهایت پس از ویرایش مقادیر ورودی‌های سازنده، آن را به صورت زیر ویرایش می‌کنیم:

    Context context;
    public HitosSQLiteOpenHelper(Context context) {
        super(context, "Hitos_DB.sqlite", null, 1);
        this.context= context;
    }

در اولین سطر متغیر context را از نوع Context می‌سازیم تا بتوانیم در همه جای کلاس از آن استفاده کنیم. با استفاده از سازنده و وردی آن و دستور this.context قصد داریم به هنگام صدا زدن کلاس HitosSQLiteOpenHelper مقدار context را از Activity برنامه به کلاس HitosSQLiteOpenHelper نسبت دهیم.

متد onCreate را برای ایجاد پایگاه داده در نرم افزار به شکل زیر ویرایش می‌کنیم:

    @Override
    public void onCreate(SQLiteDatabase db) {
        try{
            db.execSQL("CREATE TABLE IF NOT EXISTS POSTS (ID INTEGER PRIMARY KEY AUTOINCREMENT, TITLE TEXT, CONTENT TEXT);");
        }catch (SQLException e){
            Log.e("SQLite Exception", "onCreate" + e.toString() );
        }
    }

در سطر سه تا هفت یک try catch برای عملیات ایجاد جدول پایگاه داده ایجاد می‌کنیم. همانطور که می‌دانید try catch برای جلوگیری کردن از کرش نرم افزار در صورت ایجاد مشکل استفاده می‌شود.

در سطر چهار متد db.execSQL دستورات SQL را اجرا می‌کند. در این دستور قصد داریم یک جدول با نام POSTS به پایگاه داده خود اضافه کنیم. اگر با ساختار دستورات SQL آشنا نیستید می‌توانید به آموزش‌های SQL مراجعه کنید. به صورت خلاصه این دستور را تشریح می‌کنیم:

  • CREATE TABLE IF NOT EXISTS POSTS: این بخش بررسی می‌کند اگر در پایگاه داده ما جدول با نام POSTS موجود نبود آن را ایجاد کند.
  • ID INTEGER PRIMARY KEY AUTOINCREMENT: یک شناسه با نام ID و از نوع INTEGER و به صورت کاملا یکتا (PRIMARY KEY) و به صورت افزایشی خودکار  (AUTOINCREMENT) ایجاد می‌شود. این شناسه در واقع یک ستون از جدول را تشکیل می‌دهد.
  • TITLE TEXT: یک ستون از نوع TEXT یا نوشته و با نام TITLE
  • CONTENT TEXT: یک ستون از نوع TEXT یا نوشته و با نام CONTENT

در سطر شش e.toString() منجر به چاپ خطا در Log‌های نرم افزار می‌شود.

از آن جایی که کلاس HitosSQLiteOpenHelper باید شامل تمام متدهایی ذخیره سازی اطلاعات باشد، یک متد جدید به نام savePosts ایجاد می‌کنیم، که سورس آن به شرح زیر است:

    public Boolean savePosts(List<Posts> posts){
        SQLiteDatabase sqLiteDatabase=this.getWritableDatabase();
        for (int i = 0; i < posts.size(); i++){
            ContentValues cv=new ContentValues();
            cv.put("title",posts.get(i).getTitle());
            cv.put("intro",posts.get(i).getIntro());
            cv.put("fullPost",posts.get(i).getFullPost());
            cv.put("date",posts.get(i).getDate());
            cv.put("image",posts.get(i).getImage());

            long isInserted=sqLiteDatabase.insert("POSTS" , null, cv);

            if(isInserted > 0){
                Log.i("Insert_DB", "Post Id: "+isInserted);
            }else{
                Log.i("Insert_DB", "Error!");
            }
        }
        return true;
    }

سطر 1: این متد خروجی Boolean دارد و ورودی‌هایی از جنس لیستی از Posts‌ها دریافت می‌کند.

 سطر 10: یک شی به نام sqLiteDatabase از روی کلاس SQLiteDatabase ایجاد می‌کنیم. getWritableDatabase() مجوز نوشتن روی دیتابیس را برای ما صادر می‌کند، اگر در جایی قصد خواندن اطلاعات از دیتابیس را داشتیم باید از getReadableDatabase() استفاده کنیم.

سطر 3: حلقه‌ای برای پردازش کل Posts‌ها ایجاد می‌کنیم.

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

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

سطر 11: با دستور sqLiteDatabase.insert اطلاعات پایگاه داده را ذخیره می‌کنیم. متد insert سه ورودی دارد، که اولی نام جدول پایگاه داده، دوم مشخص می‌کند که اگر به هر دلیل ContentValues خالی بود متد insert چه چیزی را ذخیره کند و ورودی سوم مقادیر درون ContentValues است.

همانطور که می‌بینید نتیجه اجرای دستور sqLiteDatabase.insert درون یک متغیر از نوع long با نام isInserted ذخیره می‌شود. خروجی این دستور که در isInserted ذخیره می‌شود شماره id آیتم ذخیره شده در پایگاه داده است.

سطر 13 تا 17: این سطرها بررسی می‌کنند که اگر isInserted بزرگتر از صفر بود یعنی یک آیتم در پایگاه داده با موفقیت ثبت شده است و یک Log با نام Insert_DB برای شما ذخیره می‌کند. اگر نتیجه isInserted بزرگتر از صفر نبود یعنی خطایی پیش آمده و یک Log خطا برای شما ثبت می‌شود.

کلاس APIGettingPosts را که در قسمت‌های قبلی ایجاد کردیم این جا نیز ایجاد می‌کنیم:

public class APIGettingPosts {

    private Context context;

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

    public void getPost(final OnPostsReceived onPostsReceived) {
        JsonArrayRequest request = new JsonArrayRequest(
                Request.Method.GET,
                "http://192.168.1.2/getposts.php",
                null,
                new Response.Listener<JSONArray>() {
                    @Override
                    public void onResponse(JSONArray response) {
                        onPostsReceived.onReceived(ParsingPostJSON(response));
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.i("Get_Error: ", error.toString());
                onPostsReceived.onReceived(null);
            }
        });
        request.setRetryPolicy(new DefaultRetryPolicy(8000, 1, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));

        RequestQueue requestQueue = Volley.newRequestQueue(context);
        requestQueue.add(request);
    }

    private List<Posts> ParsingPostJSON(JSONArray response) {
        try {
            List<Posts> posts = new ArrayList<>();
            for (int i = 0; i < response.length(); i++) {
                JSONArray postArray = response.getJSONArray(i);
                Posts post = new Posts();
                post.setTitle(postArray.getString(0));
                post.setIntro(postArray.getString(1));
                post.setDate(postArray.getString(2));
                post.setImage(postArray.getString(3));
                posts.add(post);
            }
            return posts;

        } catch (JSONException e) {
            e.printStackTrace();
            return null;
        }
    }

    public interface OnPostsReceived {
        void onReceived(List<Posts> posts);
    }
}

سطر 12: آی پی سیستم شما قرار گرفته است.

توضیحات دیگر این کلاس در قسمت‌های قبل موجود است.

کلاس MainActivity را به شرح زیر ویرایش می‌کنیم:

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

        APIGettingPosts apiGettingPosts = new APIGettingPosts(this);
        apiGettingPosts.getPost(new APIGettingPosts.OnPostsReceived() {
            @Override
            public void onReceived(List<Posts> posts) {
                if (posts == null || posts.isEmpty()){
                    Toast.makeText(MainActivity.this, "خطا در دریافت اطلاعات", Toast.LENGTH_SHORT).show();
                } else {
                    HitosSQLiteOpenHelper openHelper = new HitosSQLiteOpenHelper(MainActivity.this);
                    openHelper.savePosts(posts);
                    Toast.makeText(MainActivity.this, "اطلاعات با موفقیت دریافت و درون پایگاه داده ذخیره شدند", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

 این کدها نیز در قسمت‌های قبل کاملا تفسیر شده اند.

در سطر 12 شی openHelper را از کلاس HitosSQLiteOpenHelper ایجاد کرده و در سطر 13 متد savePosts را با ورودی posts دریافت شده از سرور صدا زدیم.

اگر به برگه Android Monitor مراجعه کنید خواهید دید در صورت درست بودن سورس‌ها و ارتباط صحیح با سرور شناسه کل اطلاعات ذخیره شده برای شما نمایان خواهد شد.

استخراج پایگاه داده SQlite و مشاهده در کامپیوتر

گاهی نیاز است پایگاه داده اندروید را استخراج و در سیستم خود مشاهده و ویرایش کنید. برای این کار پس از اجرا کردن ماشین مجازی خود از منو Tools اندروید استودیو گزینه Android و از آن Android Device Monitor را انتخاب کنید.

 از منو سمت چپ روی نام ماشین مجازی خود کلیک کرده و از برگه File Explorer سمت راست مسیر data و سپس دوباره data را باز کنید.

در مسیر جاری نام پکیج برنامه خود را یافته و از پوشه databases نام پوشه پایگاه داده خود را ببینید.

روی پایگاه داده خود کلیک کرده و از برگه بالای این بخش روی آیکون کوچکی که در تصویر زیر می‌بینید کلیک کنید تا دیتابیس در دستگاه شما save شود:

اندروید device monitor

حال می‌توان این پایگاه داده را در نرم افزاری به نام DB Browser for SQLite باز کرده و محتویات درون آن را دید.

sqlite نرم افزار

لینک دانلود این نرم افزار:

دانلود نسخه ویندوزی 62 بیت

دانلود نسخه ویندوزی 32 بیت

دانلود نسخه مخصوص لینوکس

دانلود نسخه مخصوص سیستم مکینتاش

به سادگی این نرم افزار را می‌توان نصب و اجرا کرد. به محض باز کردن این نرم افزار از منو File گزینه Open Detabase را کلیک و دیتابیس را وارد نرم افزار کنید.

تگ ها: android / اندرویددیتابیس و پایگاه دادهandroid studio