SQLite Trong Android
Phần 3: SQLite Với Image Và Cách Intent Camera Trong Android.
1. Giới thiệu.
Xin chào các bạn, Ở 2 phần trước mình đã giới thiệu đến các bạn cơ bản về SQLite trong Android, ở phần này mình sẽ hướng dẫn đến các bạn xử lý hình ảnh để lưu vào SQLite, đồng thời giới thiệu cho các bạn biết về Intent Camera trong Android để kết nối với camera của điện thoại, chụp một tấm ảnh và gửi chúng về lại phần mềm của chúng ta.
2. Cấu hình SQLite.
Đầu tiên các bạn tạo một project mới và đặt tên bất kỳ, sau đó tạo một class có tên SQL extends từ SQLiteOpenHelper để cấu hình và quản lý các thao tác trong SQLite của ứng dụng. Trong ứng dụng này, mình sẽ Demo một ứng dụng Quản lý Sản phẩm, cho phép người dùng chụp hình Sản phẩm của họ rồi thêm vào CSDL.
Bạn tạo một class SanPham để chứa các thông tin của sản phẩm nhé:
class SanPham { String tensp; private Integer gia; byte[] hinhanh; SanPham(String tensp, Integer gia, byte[] hinhanh) { this.tensp = tensp; this.gia = gia; this.hinhanh = hinhanh; } }
Giao diện ứng dụng đơn giản của chúng ta sẽ như sau:
Trong class SQL chúng ta cấu hình như sau:
class SQL extends SQLiteOpenHelper { SQL(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); } void TruyVanKhongTraVe(String sql) { SQLiteDatabase db=getWritableDatabase(); db.execSQL(sql); } Cursor TruyVanTraVe(String sql) { SQLiteDatabase db=getWritableDatabase(); return db.rawQuery(sql,null); } @Override public void onCreate(SQLiteDatabase db) { } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
Trong MainActivity, chúng ta sẽ tạo một CSDL và một bảng mới có tên SanPham gồm 4 trường: ID, TenSP, Gia, HinhMh:
public static SQL db; db=new SQL(this,"BanHang.sqlite",null,1); db.TruyVan("Create Table If not Exists SanPham(ID Integer Primary Key Autoincrement, TenSP Varchar, Gia Integer, HinhMh Blob)");
Trong câu lệnh phía trên, trường HinhMh chúng ta sẽ để kiểu dữ liệu là Blob, vì SQLite sẽ lưu file hình ảnh của chúng ta dưới dạng một mảng Byte[], do đó để lưu chúng ta sẽ cần một hàm để chuyển đổi hình ảnh bình thường thành mảng Byte[], hàm này mình sẽ giới thiệu phía dưới.
3. Intent Camera.
Sau khi đã tạo một bảng rồi, thì công việc tiếp theo chúng ta sẽ thiết kế lại giao diện và cho người dùng chụp ảnh từ điện thoại để có dữ liệu lưu vào SQLite nhé.
Trong activity_main.xml chúng ta sẽ sửa lại như sau:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp" android:orientation="vertical"> <ImageView android:id="@+id/imageView" android:layout_width="200dp" android:layout_height="200dp" android:contentDescription="HinhMH" /> <EditText android:id="@+id/edtTen" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Tên" android:lines="1" /> <EditText android:id="@+id/edtGiatien" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Giá tiền" android:lines="1" /> <Button android:id="@+id/btnThemSP" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="61dp" android:text="Thêm sản phẩm" /> <Button android:id="@+id/btnXemDS" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Xem danh sách" /> </LinearLayout>
Trong MainActivity, chúng ta khai báo và Ánh xạ các View này:
EditText edtten, edtgia; Button btnthem,btndanhsach; ImageView imganh;
edtten= (EditText) findViewById(R.id.edtTen); edtgia= (EditText) findViewById(R.id.edtGiatien); btnthem= (Button) findViewById(R.id.btnThemSP); btndanhsach= (Button) findViewById(R.id.btnXemDS); imganh= (ImageView) findViewById(R.id.imageView);
Để kết nối với Camera của điện thoại, chúng ta sử dụng Intent kết hợp với với câu lệnh MediaStore, bạn bắt sự kiện Click của ImageView như sau:
imganh.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent =new Intent(MediaStore.ACTION_IMAGE_CAPTURE); startActivityForResult(intent,REQUEST_CODE); } });
Trong đó, MediaStore.ACTION_IMAGE_CAPTURE sẽ giúp kết nối tới camera, startActivityForResult(); giúp trả về dữ liệu khi chụp ảnh xong, đi kèm với nó là một biến REQUEST_CODE kiểu Int để so sánh điều kiện khi trả về dữ liệu có đúng Activity đang cần hay không, giá trị REQUEST_CODE các bạn có thể khai báo giá trị bất kỳ.
Sau khi chụp ảnh và gửi về rồi, chúng ta cần một hàm để nhận dữ liệu này và hiển thị lên trên ImageView, để nhận giá trị gửi về từ startActivityForResult(), bạn gọi phương thức onActivityResult():
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode==REQUEST_CODE&&resultCode==RESULT_OK) { Bitmap bitmap = (Bitmap) data.getExtras().get("data"); imganh.setImageBitmap(bitmap); } super.onActivityResult(requestCode, resultCode, data); }
Trong phương thức này, đầu tiên bạn phải kiểm tra xem biến requestCode trả về có mang giá trị giống như biến REQUEST_CODE đã khai báo hay không, vì có thể nhiều Activity sẽ có nhiều REQUEST_CODE khác nhau.
4. Thêm một Sản phẩm mới với Hình ảnh vừa chụp.
Như đã nói ở Mục 2, hình ảnh trong SQLite được lưu với dạng mảng byte[], nhưng khi hình ảnh trả về từ camera lại có kiểu dữ liệu là Bitmap. Do đó, chúng ta phải có một hàm để chuyển đổi từ kiểu Bitmap sang kiểu byte[], trong MainActivity các bạn tạo một hàm mới có tên ConverttoArrayByte() như sau:
public byte[] ConverttoArrayByte(ImageView img) { BitmapDrawable bitmapDrawable = (BitmapDrawable) img.getDrawable(); Bitmap bitmap=bitmapDrawable.getBitmap(); ByteArrayOutputStream stream=new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream); return stream.toByteArray(); }
Sau khi chuyển đổi, hàm này sẽ trả về cho chúng ta một mảng byte[], chúng ta chỉ việc lấy mảng byte[] này thêm vào CSDL mà thôi, trong class SQL, các bạn tạo một hàm mới để Insert với kiểu byte[] này:
void Insertsanpham(String ten, Integer gia, byte[] hinh) { SQLiteDatabase db=getWritableDatabase(); String sql="Insert into SanPham values (null,?,?,?)"; SQLiteStatement statement=db.compileStatement(sql); statement.clearBindings(); statement.bindString(1,ten); statement.bindLong(2,gia); statement.bindBlob(3,hinh); statement.executeInsert(); }
Lúc này, class SQL đầy đủ của chúng ta:
class SQL extends SQLiteOpenHelper { SQL(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); } void TruyVan(String sql) { SQLiteDatabase db=getWritableDatabase(); db.execSQL(sql); } Cursor TruyVanTraVe(String sql) { SQLiteDatabase db=getWritableDatabase(); return db.rawQuery(sql,null); } void Insertsanpham(String ten, Integer gia, byte[] hinh) { SQLiteDatabase db=getWritableDatabase(); String sql="Insert into SanPham values (null,?,?,?)"; SQLiteStatement statement=db.compileStatement(sql); statement.clearBindings(); statement.bindString(1,ten); statement.bindLong(2,gia); statement.bindBlob(3,hinh); statement.executeInsert(); } @Override public void onCreate(SQLiteDatabase db) { } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
Quay về MainActivity, các bạn bắt sự kiện Click của btnthem để tiến hành gọi hàm Insert của lớp SQL:
btnthem.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { db.Insertsanpham(edtten.getText().toString(), Integer.parseInt(edtgia.getText().toString()),ConverttoArrayByte(imganh)); Toast.makeText(MainActivity.this,"Thêm thành công",Toast.LENGTH_SHORT).show(); edtgia.setText(""); edtten.setText(""); edtten.requestFocus(); } });
5. Đọc dữ liệu từ SQLite.
Đầu tiên, bạn tạo một Activity mới có tên DanhsachSP, Activity này sẽ chứa một ListView cho phép hiển thị các sản phẩm mà bạn đã thêm trong CSDL, file activity_danhsachsp.xml chúng ta code thêm một Listview vào:
<?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="com.assss.ass.sqliteimage.DanhsachSP"> <ListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/lvDanhsach" /> </RelativeLayout>
Tiếp theo, các bạn tạo một file .xml mới có tên row__listview.xml dùng để custom các dòng cho ListView, ở mỗi dòng của ListView, chúng ta sẽ có 1 ImageView hiển thị ảnh đại diện và 1 TextView hiển thị tên của Sản phẩm:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <ImageView android:id="@+id/imgAnhDaiDien" android:layout_width="100dp" android:layout_height="100dp" /> <TextView android:id="@+id/txtTen" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:ellipsize="end" android:lines="1" android:text="Tên Hàng" android:textSize="20sp" /> </LinearLayout>
Lúc chạy giao diện của chúng ta sẽ như thế này:
Tiếp theo, các bạn tạo một class có tên CustomAdapter, class này có nhiệm vụ sẽ hiển thị dữ liệu lên ListView theo định dạng trong file row_listview.xml:
class CustomAdapter extends ArrayAdapter<SanPham> { CustomAdapter(Context context, int resource, List<SanPham> item) { super(context, resource, item); } @NonNull @Override public View getView(int position, View convertView, @NonNull ViewGroup parent) { View view=convertView; if (view ==null) { LayoutInflater inflater=LayoutInflater.from(getContext()); view=inflater.inflate(R.layout.row_listview, null); } SanPham sanPham=getItem(position); if (sanPham!=null) { ImageView imgHinhDaidien= (ImageView) view.findViewById(R.id.imgAnhDaiDien); TextView txtTenSP= (TextView) view.findViewById(R.id.txtTen); Bitmap bitmap= BitmapFactory.decodeByteArray(sanPham.hinhanh, 0, sanPham.hinhanh.length); imgHinhDaidien.setImageBitmap(bitmap); txtTenSP.setText(sanPham.tensp); } return view; } }
Class này sẽ extends từ ArrayAdapter, trong phương thức getView(), bạn inflater file row_listview.xml lúc nãy đã tạo phía trên vào, sau đó tạo một biến từ Object SanPham để lấy các giá trị trong đó ra. Ngoài ra, để hiển thị một hình ảnh dưới dạng mảng byte[], các bạn code như sau:
Bitmap bitmap= BitmapFactory.decodeByteArray(sanPham.hinhanh, 0, sanPham.hinhanh.length); imgHinhDaidien.setImageBitmap(bitmap);
Sau khi đã code class CustomAdapter xong xuôi, bạn quay về file DanhsachSP để tiến hành lấy dữ liệu và hiển thị lên ListView:
public class DanhsachSP extends AppCompatActivity { ArrayList<SanPham> arraySanPham; ListView lvDanhsach; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_danhsach_sp); lvDanhsach = (ListView) findViewById(R.id.lvDanhsach); Cursor cursor = MainActivity.db.TruyVanTraVe("Select * from SanPham"); arraySanPham = new ArrayList<>(); while (cursor.moveToNext()) { arraySanPham.add(new SanPham(cursor.getString(1), cursor.getInt(2), cursor.getBlob(3))); } CustomAdapter adapter = new CustomAdapter(DanhsachSP.this, R.layout.row_listview, arraySanPham); lvDanhsach.setAdapter(adapter); } }
Như đã nói ở 2 Phần trước, để lấy dữ liệu từ CSDL SQLite, bạn cũng dùng một biến Cursor (Con trỏ) để lấy dữ liệu ra từ CSDL, tuy nhiên do kiểu dữ liệu của ảnh trong SQLite là Blob, nên khi lấy ra chúng ta sẽ dùng cursor.getBlob() nhé.
Để chuyển màn hình từ MainActivity sang DanhsachSP, trong MainActivity bạn bắt sự kiện onCLick() của btndanhsach:
btndanhsach.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(MainActivity.this,DanhsachSP.class); startActivity(intent); } });
6. Kết luận.
Sau khi chạy, giao diện chính của chúng ta sẽ như sau:
Danh sách các sản Phẩm đã thêm:
Như vậy là mình đã hướng dẫn xong cho các bạn phần SQLite với Image và kết nối đến Camera của điện thoại, các chức năng khác như Sửa, Xóa, Tìm Kiếm các bạn có thể tham khảo thêm ở 2 phần trước mình làm, nó cũng tương tự nhau cả thôi. Ở Phần 4, mình sẽ giới thiệu đến các bạn việc lưu 1 file Âm thanh vào SQLite và cách Ghi âm trong Android, nhớ đón theo dõi nhé!!!!!
Xin chào và Hẹn gặp lại các bạn ở Phần 4: SQLite với Âm thanh và Ghi âm trong Android.