অ্যান্ড্রয়েডে ডেটা পারসিস্টেন্সির জন্য আমরা সাধারণত SharedPreferences ব্যবহার করি। কিন্তু বেশি ডেটা বা কমপ্লেক্স ডেটা হলে পারসিস্টেন্সির জন্য SharedPreferences ভালো একটা অপশন নয়। তখন আমরা ফাইল স্টোরেজ বা ডেটাবেজ ব্যবহার করতে হয়। SQLite হচ্ছে ওপেন সোর্স ডেটাবেজ সিস্টেম, যেটা অ্যান্ড্রয়েডে বিল্টইন থাকে। এটি অফলাইন ডেটাবেজ। আর এটি ডিভাইসে একটা ফাইল হিসেবে স্টোর থাকে।
ডেটাবেজের প্রধান চারটি অপারেশন হচ্ছে Create, Read, Update, Delete সংক্ষেপে CRUD। আমরা সিম্পল একটা অ্যাপ তৈরি করব যেটার মাধ্যমে এই চারটি অপারেশন শিখব। সব গুলো অপারেশনের জন্য কোড লিখার পর আমাদের অ্যাপটি নিচের মত হবেঃ
আমরা একটি ক্লাস তৈরি করে নিব। যেটা আমাদের সব গুলো SQLite অপারেশন ম্যানেজ করবে। যেমন নাম দিলাম DatabaseHelper. এরপর আমাদেরকে SQLiteHelper ক্লাসটিকে এক্সটেন্ড করতে হবে। SQLiteHelper এক্সটেন্ড করলে আমাদের দুইটা মেথড অবশয়ই ইমপ্লিমেন্ট করতে হবে, একটি হচ্ছে onCreate এবং onUpgrade মেথড।
একটি ডেটাবেজ তৈরি করতে আমাদের দুইটা জিনিস লাগবে, ডেটাবেজ এর নাম এবং ভার্সন। এতটুকু করলেই আমাদের জন্য ডেটাবেজ তৈরি হবে।
public class DatabaseHelper extends SQLiteOpenHelper { public static final String DATABASE_NAME = "friends.db"; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null , 1); SQLiteDatabase db = this.getWritableDatabase(); } @Override public void onCreate(SQLiteDatabase db) { } @Override public void onUpgrade(SQLiteDatabase db, int i, int i1) { } }
MainActiviy.java ফাইলে DatabaseHelper এর একটা ইন্সট্যান্স তৈরি করলেই এখন আমাদের জন্য একটা ডেটাবেজ তৈরি হবে।
public class MainActivity extends AppCompatActivity { DatabaseHelper myDB; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myDB = new DatabaseHelper(this); } }
ডেটাবেজ যে তৈরি হয়েছে, তা দেখতে চাইলে আমরা অ্যান্ড্রয়েড স্টুডিও থেকে Tools > Android > Android Device Monitor এ ক্লিক করব। এখানে আমাদের যে ডিভাইস বা ভার্চুয়াল ডিভাইসটি কানেক্টেড থাকবে, তার তথ্য দেখাবে। এখান থেকে Data > Data > app id তে ন্যাভিগেট করলে Database নামে ফোল্ডার পাবো। এই ফোল্ডারে ডেটাবেজ দেখাবে। আমরা চাইলে এই ডেটাবেজ কম্পিউটারে এক্সপোর্ট করে দেখতেও পারব। তার জন্য ডেটাবেজ এ ক্লিক করে pull to device আইকনে ক্লিক করে লোকেশন দেখিয়ে দিলে তা কম্পিউটারে দেখতে পারব।
ডেটাবেজ এর ভেতরে কি আছে, তা আমরা দেখতে চাইলে SQLite Database Browser নামে যে কোন সফটওয়ার ব্যবহার করতে পারি। ক্রোম ব্রাউজার বা ফায়ারফক্সের এক্সটেনশন ও রয়েছে অনেক।
ডেটাবেজ তো ক্রিয়েট হয়েছে, এবার আমরা ডেটাবেজে ডেটা রাখব। ডেটাবেজে ডেটা রাখার জন্য আমাদের টেবিল তৈরি করে নিতে হবে। আর প্রতি টেবিলে একটি প্রাইমারি কী রাখতে হবে। যেটা হবে ইউনিক। যেমন আমরা friends নামে একটা ডেটাবেজ তৈরি করব। যেখানে friends_table নামে একটা টেবিল থাকবে। ঐ টেবিলে তিনটা রো থাকবে। ID, Friends Name & Friends Email. আর তার জন্য আমাদের নিচের মত SQL কোয়েরি লিখতে হবে।
db.execSQL("create table " + TABLE_NAME + " (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, EMAIL TEXT)");
এটিকে ডাইন্যামিক ভাবে লিখলেঃ
db.execSQL("create table " + TABLE_NAME + " (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, MARKS TEXT)");
SQL Query সম্পর্কে আইডিয়া না থাকলে W3school থেকে গিয়ে ধারণা নিতে পারেন। গুগলে সার্চ করলেও অনেক টিউটোরিয়াল পাওয়া যাবে।
এতটুকু করে রান করলে আমাদের ডেটাবেজে আমাদের জন্য টেবিল তৈরি হবে। টেবিল তৈরি হয়েছে কিনা, তা আমরা Device Monitor থেকে ডেটাবেজটি এক্সপোর্ট করে তারপর দেখতে পারি। সব কিছু এ পর্যন্ত ঠিক থাকলে এবার আমরা ডেটাবেজে ডেটা রাখতে পারি। তার জন্য আমাদের activity_main.xml ফাইলে কয়েকটা ফিল্ড যুক্ত করব। Friend Name এর জন্য একটা টেক্সট ফিল্ড, Friend Email এর জন্য একটা টেক্সট ফিল্ড এবং একটা বাটন। নিজের ইচ্ছে মত যুক্ত করতে পারেন। এরপর MainActivity.java এ রেফারেন্স যুক্ত করব।
ডেটাবেজে ডেটা ইন্সার্ট করার জন্য আমাদের দুইটা তথ্য দরকার হবে। কোন টেবিলে ডেটা ইনসার্ট করব, তা এবং কি ডেটা ইনসার্ট করব তা। আর তা আমাদের একটা নির্দিষ্ট নিয়ম মেনে প্রোভাইড করতে হয়। Content Values এর মাধ্যমে। এতে ডেটা গুলো জোড়া জোড়া ভাবে রাখা যায়।
ডেটাবেজে ডেটা ইনসার্ট করার জন্য আমরা DatabaseHelper ক্লাসে insertData নামে একটা নতুন মেথড যুক্ত করব। যা এ কাজ গুলো করবে। নিচের মত করেঃ
public boolean insertData(String name, String email){ SQLiteDatabase db = this.getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put(COL_2, name); contentValues.put(COL_3, email); long result = db.insert(TABLE_NAME, null, contentValues); if (result== -1) return false; else return true; }
এরপর আমরা MainActiviy.java ফাইলে এডিট টেক্সট থেকে ডেটা গুলো নিয়ে DatabaseHelper ক্লাসের insertData মেথডে পাস করব। তাহলে ডেটাবেজে ডেটা ইনসার্ট হবে। MainActivity.java:
public class MainActivity extends AppCompatActivity { DatabaseHelper myDB; EditText editName, editEmail; Button btnAdd; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myDB = new DatabaseHelper(this); editName = (EditText) findViewById(R.id.textName); editEmail = (EditText) findViewById(R.id.textEmail); btnAdd = (Button) findViewById(R.id.btnAdd); addData(); } public void addData(){ btnAdd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { boolean isInserted = myDB.insertData(editName.getText().toString(), editEmail.getText().toString()); if(isInserted == true) Toast.makeText(MainActivity.this, "Data Inserted", Toast.LENGTH_LONG).show(); else Toast.makeText(MainActivity.this, "Data Insert failed", Toast.LENGTH_LONG).show(); } }); } }
ডেটা ঠিক মত ইনসার্ট হল একেটা টোস্ট দেখাবে। এখন সত্যিই ডেটা ইনসার্ট হয়েছে কিনা, তা দেখতে হলে ডিভাইস মনিটর এ গিয়ে ফাইল এক্সপ্লোরার এর মাধ্যমে ডেটাবেজ ব্রাউজ করে তা কম্পিউটারে নিয়ে আমরা দেখতে পারি। SQLite Database Browser ব্যবহার করলে নিচের মত করে ডেটা ব্রাউজ করে দেখা যাবে।
অ্যাপে ডেটা গুলো যদি দেখতে চাই, তার জন্য আমাদের ডেটাবেজ থেকে কোয়েরি করে ডেটা গুলো নিতে হবে। এবং পরে ডেটা গুলো দেখাতে হবে। ডেটা দেখানোর জন্য একটা টেক্সট ভিউ যুক্ত করি। ডেটাবেজ থেকে ডেটা কোয়েরি করার জন্য Cursor ব্যবহার করা হয়। ডেটাবে থেকে ডেটা কোয়েরি করার জন্য আমরা DatabaseHelper ক্লাসে getAll নামে একটা নতুন মেথড যুক্ত করব। যা এ কাজ গুলো করবে। নিচের মত করেঃ
public Cursor getAllData(){ SQLiteDatabase db = this.getWritableDatabase(); Cursor res = db.rawQuery("select * from " +TABLE_NAME, null); return res; }
কোয়েরি করার পর ডেটা গুলো টেক্সট ভিউতে দেখানোর জন্য নিচের মত করে লিখতে পারিঃ
public void viewAll(){ btnView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Cursor res = myDB.getAllData(); if(res.getCount() == 0){ Toast.makeText(MainActivity.this, "No data found", Toast.LENGTH_LONG).show(); return; }else { StringBuffer buffer = new StringBuffer(); while (res.moveToNext()){ buffer.append("Id: " + res.getString(0) + "\n"); buffer.append("Name: " + res.getString(1) + "\n"); buffer.append("Email: " + res.getString(2) + "\n \n"); } tvData.setText(buffer.toString()); } } }); }
এখন যদি অ্যাপটি রান করে View Data তে ক্লিক করলে আমরা আমাদের ডেটাবেজে থাকা ডেটা গুলো দেখতে পাবো।
আমরা ডেটাবেজে কোন ডেটা যুক্ত করেছি। এখন যদি ভুল ডেটা ইনপুট দেই, তাহলে তো ভুল ডেটা ইনপুট হবে। আমরা এখন ভুল লিখলেও যেন ডেটা ঠিক করতে পারি, তা দেখব। আর তা করা হয় আপডেট এর মাধ্যমে।
ডেটা আপডেট করার জন্য আমাদের ডেটা পাস করার পাশা পাশি কোন আইডিটির ডেটা আপডেট করতে চাই, তাও পাস করতে হবে। তাই আমরা আমাদের activity_main.xml ফাইলে নতুন আরেকটা ফিল্ড যুক্ত করব।
ডেটা ইনসার্ট এবং আপডেট প্রায় একই রকম। ডেটাবেজে ডেটা আপডেট করার জন্য আমরা DatabaseHelper ক্লাসে updateData নামে একটা নতুন মেথড যুক্ত করব। যা এ কাজ গুলো করবে। নিচের মত করেঃ
public boolean updateData(String id, String name, String email){ SQLiteDatabase db = this.getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put(COL_1, id); contentValues.put(COL_2, name); contentValues.put(COL_3, email); db.update(TABLE_NAME, contentValues, "ID = ?", new String[] {id}); return true; }
এরপর আমরা MainActiviy.java ফাইলে এডিট টেক্সট থেকে ডেটা গুলো নিয়ে DatabaseHelper ক্লাসের updateData মেথডে পাস করব। তাহলে যে আইডিটির ডেটা আমরা আপডেট করত চাই, তা আপডেট হবে।
public void updateData(){ btnUpdate.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { boolean isUpdated = myDB.updateData( editID.getText().toString(), editName.getText().toString(), editEmail.getText().toString()); if (isUpdated == true) Toast.makeText(MainActivity.this, "Updated", Toast.LENGTH_LONG).show(); else Toast.makeText(MainActivity.this, "Not updated", Toast.LENGTH_LONG).show(); } }); }
ডিলেট করা অনেক সহজ। শুধু মাত্র কোন আইডিটির ডেটা ডিলেট করব, তা পাস করে দিলেই ডেটা ডিলেট হয়ে যাবে। হেল্পার ক্লাসে deleteData নামক একটি মেথড যুক্ত করি এবং নিচের কোড গুলো যুক্ত করিঃ
public Integer deleteData (String id){ SQLiteDatabase db = this.getWritableDatabase(); return db.delete(TABLE_NAME, "ID = ?", new String[] {id}); }
এখন কোন আইডিটির ডেটা আমরা ডিলেট করতে চাই, তা পাস করলেই ডেটা ডিলেট হবেঃ
public void deleteData(){ btnDelete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Integer isDeleted = myDB.deleteData(editID.getText().toString()); if (isDeleted > 0) Toast.makeText(MainActivity.this, "Deleted", Toast.LENGTH_LONG).show(); else Toast.makeText(MainActivity.this, "Not deleted", Toast.LENGTH_LONG).show(); } }); }
উপরের সব গুলো অপারেশন নিয়ে আমাদের সম্পুর্ণ MainActivity.java:
package me.jakir.sqlitedemo; import android.database.Cursor; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import org.w3c.dom.Text; public class MainActivity extends AppCompatActivity { DatabaseHelper myDB; EditText editName, editEmail, editID; TextView tvData; Button btnAdd, btnView, btnUpdate, btnDelete; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myDB = new DatabaseHelper(this); editName = (EditText) findViewById(R.id.textName); editEmail = (EditText) findViewById(R.id.textEmail); editID = (EditText) findViewById(R.id.textID); tvData = (TextView) findViewById(R.id.tvData); btnAdd = (Button) findViewById(R.id.btnAdd); btnView = (Button) findViewById(R.id.btnView); btnUpdate = (Button) findViewById(R.id.btnUpdate); btnDelete = (Button) findViewById(R.id.btnDelete); addData(); viewAll(); updateData(); deleteData(); } public void addData(){ btnAdd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { boolean isInserted = myDB.insertData(editName.getText().toString(), editEmail.getText().toString()); if(isInserted == true) Toast.makeText(MainActivity.this, "Data Inserted", Toast.LENGTH_LONG).show(); else Toast.makeText(MainActivity.this, "Data Insert failed", Toast.LENGTH_LONG).show(); } }); } public void viewAll(){ btnView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Cursor res = myDB.getAllData(); if(res.getCount() == 0){ Toast.makeText(MainActivity.this, "No data found", Toast.LENGTH_LONG).show(); return; }else { StringBuffer buffer = new StringBuffer(); while (res.moveToNext()){ buffer.append("Id: " + res.getString(0) + "\n"); buffer.append("Name: " + res.getString(1) + "\n"); buffer.append("Email: " + res.getString(2) + "\n \n"); } tvData.setText(buffer.toString()); } } }); } public void updateData(){ btnUpdate.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { boolean isUpdated = myDB.updateData( editID.getText().toString(), editName.getText().toString(), editEmail.getText().toString()); if (isUpdated == true) Toast.makeText(MainActivity.this, "Updated", Toast.LENGTH_LONG).show(); else Toast.makeText(MainActivity.this, "Not updated", Toast.LENGTH_LONG).show(); } }); } public void deleteData(){ btnDelete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Integer isDeleted = myDB.deleteData(editID.getText().toString()); if (isDeleted > 0) Toast.makeText(MainActivity.this, "Deleted", Toast.LENGTH_LONG).show(); else Toast.makeText(MainActivity.this, "Not deleted", Toast.LENGTH_LONG).show(); } }); } }
সম্পূর্ণ DatabaseHelper.java:
package me.jakir.sqlitedemo; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; /** * Created by Jakir Hossain on 7/23/16. * Email: [email protected] */ public class DatabaseHelper extends SQLiteOpenHelper { public static final String DATABASE_NAME = "friends.db"; public static final String TABLE_NAME = "friends_table"; public static final String COL_1 = "ID"; public static final String COL_2 = "NAME"; public static final String COL_3 = "EMAIL"; public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null , 1); SQLiteDatabase db = this.getWritableDatabase(); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL("create table " + TABLE_NAME + " ( " + COL_1 + " INTEGER PRIMARY KEY AUTOINCREMENT, " + COL_2 + " TEXT, " + COL_3 + " TEXT)"); } @Override public void onUpgrade(SQLiteDatabase db, int i, int i1) { db.execSQL("DROP TABLE IF EXIST" + TABLE_NAME); onCreate(db); } public boolean insertData(String name, String email){ SQLiteDatabase db = this.getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put(COL_2, name); contentValues.put(COL_3, email); long result = db.insert(TABLE_NAME, null, contentValues); if (result== -1) return false; else return true; } public Cursor getAllData(){ SQLiteDatabase db = this.getWritableDatabase(); Cursor res = db.rawQuery("select * from " +TABLE_NAME, null); return res; } public boolean updateData(String id, String name, String email){ SQLiteDatabase db = this.getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put(COL_1, id); contentValues.put(COL_2, name); contentValues.put(COL_3, email); db.update(TABLE_NAME, contentValues, "ID = ?", new String[] {id}); return true; } public Integer deleteData (String id){ SQLiteDatabase db = this.getWritableDatabase(); return db.delete(TABLE_NAME, "ID = ?", new String[] {id}); } }
এবং সম্পূর্ণ activity_main.java:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="me.jakir.sqlitedemo.MainActivity"> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/textName" android:hint="Friend Name" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/textEmail" android:hint="Friend Email" android:layout_below="@+id/textName" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_alignRight="@+id/textName" android:layout_alignEnd="@+id/textName" /> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/textID" android:hint="ID" android:layout_below="@+id/textEmail" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_alignRight="@+id/textEmail" android:layout_alignEnd="@+id/textEmail" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Add Data" android:id="@+id/btnAdd" android:layout_below="@+id/btnView" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="View Data" android:id="@+id/btnView" android:layout_below="@+id/textID" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Update" android:id="@+id/btnUpdate" android:layout_below="@+id/btnAdd" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Delete" android:id="@+id/btnDelete" android:layout_below="@+id/btnUpdate" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_alignRight="@+id/btnUpdate" android:layout_alignEnd="@+id/btnUpdate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tvData" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:layout_marginBottom="105dp" android:layout_below="@+id/btnDelete" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> </RelativeLayout>
Thanks a lot
আপনাকে অনেক অনেক ধন্যবাদ , ভীষণ উপকারিত হলাম। আসাকরি সময় পেলে database আর উপর আর tutorial করবেন।
Thank you bro
একটা টিউটরিয়াল কৃতজ্ঞ থাকিব। অগ্রিম ধন্যবাদ। টিউটরিয়ালটি হল… sqliteopenhelper দিয়ে extend করে,…Table create করে, সেই table এ তৈরি করা asset এ রাখা existing database file টা upload দেওয়া ।
I will try 🙂
SQLiteDatabase.CursorFactory এর ব্যাপারটা ইন্টারনেট ঘাটাঘাটি করেও ভাল ভাবে বুঝতে পারিনি।হাল্কা একটু ধারনা দিবেন ভাইয়া?
Excellent Boss.