Vietnamese (Tiếng Việt) translation by Dai Phong (you can also view the original English article)
Khi nói đến dữ liệu cố định của ứng dụng tại cục bộ, thì các nhà phát triển Android chắc chắn tha hồ lựa chọn. Ngoài việc truy cập trực tiếp đến cả các khu vực lưu trữ bên trong và bên ngoài của một thiết bị Android, thì nền tảng Android còn cung cấp cơ sở dữ liệu SQLite để lưu trữ các dữ liệu quan hệ, và các tập tin đặc biệt để lưu trữ cặp khóa-giá trị. Hơn nữa, ứng dụng Android cũng có thể sử dụng các cơ sở dữ liệu bên thứ ba cung cấp hỗ trợ NoSQL.
Trong bài này, tôi sẽ hướng dẫn cho bạn cách làm thế nào để sử dụng tất cả những lựa chọn lưu trữ trong các ứng dụng Android của bạn. Tôi cũng sẽ giúp bạn tìm hiểu cách chọn tùy chọn lưu trữ thích hợp nhất cho dữ liệu của bạn.
Bạn có thấy dễ dàng hơn khi tìm hiểu bằng video? Tại sao không kiểm tra khóa học của chúng tôi:
1. Lưu trữ các cặp khóa-giá trị
Nếu bạn đang tìm kiếm một cách nhanh chóng để lưu trữ một số chuỗi hoặc các con số, thì bạn nên xem xét việc sử dụng một tập tin preferences. Các activity và service của Android có thể sử dụng phương thức getDefaultSharedPreferences()
của lớp PreferenceManager
để lấy một tham chiếu đến một đối tượng SharedPreferences
có thể được sử dụng cho cả đọc và ghi vào tập tin preferences mặc định.
SharedPreferences myPreferences = PreferenceManager.getDefaultSharedPreferences(MyActivity.this);
Để bắt đầu ghi vào tập tin preferences, bạn phải gọi phương thức edit()
của đối tượng SharedPreferences
, nó trả về một đối tượng SharedPreferences.Editor
.
SharedPreferences.Editor myEditor = myPreferences.edit();
Đối tượng SharedPreferences.Editor
có một số phương thức trực quan, bạn có thể sử dụng để lưu trữ cặp khóa-giá trị mới vào tập tin preferences. Ví dụ, bạn có thể sử dụng phương thức putString()
để đặt một cặp khóa-giá trị mà giá trị của chúng của chúng có kiểu String
. Tương tự, bạn có thể sử dụng phương thức putFloat()
để đặt một cặp khóa-giá trị mà giá trị của nó là kiểu float
. Đoạn code sau đây tạo ra ba cặp khóa-giá trị:
myEditor.putString("NAME", "Alice"); myEditor.putInt("AGE", 25); myEditor.putBoolean("SINGLE?", true);
Một khi bạn đã thêm tất cả các cặp, bạn phải gọi phương thức commit()
của đối tượng SharedPreferences.Editor
để làm cố định chúng.
myEditor.commit();
Đọc từ một đối tượng SharedPreferences
là dễ dàng hơn rất nhiều. Tất cả những gì bạn cần làm là gọi phương thức get*()
thích hợp. Ví dụ, để có được một cặp khóa-giá trị mà giá trị của nó là kiểu String
, bạn phải gọi phương thức getString()
. Dưới đây là một đoạn code truy vấn tất cả các giá trị mà chúng ta đã thêm vào trước đó:
String name = myPreferences.getString("NAME", "unknown"); int age = myPreferences.getInt("AGE", 0); boolean isSingle = myPreferences.getBoolean("SINGLE?", false);
Như bạn có thể thấy trong đoạn code ở trên, đối với tham số thứ hai, tất cả các phương thức get*()
kỳ vọng một giá trị mặc định mà phải là giá trị trả về nếu khoá không tồn tại trong tập tin preferences.
Lưu ý rằng các tập tin preferences giới hạn chỉ dữ liệu kiểu String và kiểu nguyên thủy. Nếu bạn muốn lưu trữ các loại dữ liệu phức tạp hoặc dữ liệu nhị phân, bạn phải chọn một tùy chọn lưu trữ khác.
2. Sử dụng một cơ sở dữ liệu SQLite
Mỗi ứng dụng Android có thể tạo và tận dụng cơ sở dữ liệu SQLite để lưu trữ một lượng lớn dữ liệu có cấu trúc. Như bạn có thể đã biết, SQLite là không chỉ nhẹ, mà còn rất nhanh. Nếu bạn có kinh nghiệm làm việc với hệ thống quản lý cơ sở dữ liệu quan hệ và rành về SQL, viết tắt của Structured Query Language, và JDBC, là viết tắt Java Database Connectivity, thì đây có thể là tùy chọn lưu trữ ưa thích của bạn.
Để tạo ra một cơ sở dữ liệu SQLite mới, hoặc để mở một cái đã có sẵn, bạn có thể sử dụng phương thức openOrCreateDatabase()
trong Activity hoặc Service của bạn. Đối với đối số của nó, bạn phải truyền vào tên của cơ sở dữ liệu của bạn và các chế độ mà bạn muốn mở nó. Chế độ sử dụng nhiều nhất là MODE_PRIVATE
, nó đảm bảo rằng cơ sở dữ liệu có thể truy cập chỉ đối với ứng dụng của bạn. Ví dụ, ở đây là cách bạn sẽ mở hoặc tạo một cơ sở dữ liệu được gọi là my.db:
SQLiteDatabase myDB = openOrCreateDatabase("my.db", MODE_PRIVATE, null);
Một khi cơ sở dữ liệu đã được tạo ra, bạn có thể sử dụng các phương thức execSQL()
để chạy các câu lệnh SQL trên đó. Các code sau đây cho bạn thấy cách làm thế nào để sử dụng câu lệnh SQL CREATE TABLE
để tạo ra một bảng gọi là user, trong đó có ba cột:
myDB.execSQL( "CREATE TABLE IF NOT EXISTS user (name VARCHAR(200), age INT, is_single INT)" );
Mặc dù có thể chèn các dòng mới vào bảng bằng cách sử dụng phương thức execSQL()
, nhưng tốt hơn là sử dụng phương thức insert()
để thay thế. Phương thức insert()
cần một đối tượng ContentValues
có chứa các giá trị cho mỗi cột của bảng. Một đối tượng ContentValues
là rất giống với một đối tượng Map
và chứa các cặp khóa-giá trị.
Dưới đây là hai đối tượng ContentValues
mà bạn có thể sử dụng với bảng user
:
ContentValues row1 = new ContentValues(); row1.put("name", "Alice"); row1.put("age", 25); row1.put("is_single", 1); ContentValues row2 = new ContentValues(); row2.put("name", "Bob"); row2.put("age", 20); row2.put("is_single", 0);
Như bạn có thể thấy, các khoá mà bạn truyền vào phương thức put()
phải khớp với tên của các cột trong bảng.
Một khi các đối tượng ContentValues
của bạn đã sẵn sàng, bạn có thể chuyển chúng cho phương thức insert()
cùng với tên bảng.
myDB.insert("user", null, row1); myDB.insert("user", null, row2);
Truy vấn cơ sở dữ liệu, bạn có thể sử dụng phương thức rawQuery()
, nó trả về một đối tượng Cursor
có chứa các kết quả của truy vấn.
Cursor myCursor = myDB.rawQuery("select name, age, is_single from user", null);
Một đối tượng Cursor
có thể chứa không hay nhiều dòng. Cách dễ nhất để lặp qua tất cả các dòng của nó là gọi phương thức moveToNext()
của nó bên trong một vòng lặp while
.
Để lấy giá trị của một cột riêng lẻ, bạn phải sử dụng các phương thức như getString()
và getInt()
, chúng yêu cầu các chỉ số của các cột. Ví dụ, ở đây là cách làm thế nào bạn truy vấn tất cả các giá trị mà bạn thêm vào trong bảng user
:
while(myCursor.moveToNext()) { String name = myCursor.getString(0); int age = myCursor.getInt(1); boolean isSingle = (myCursor.getInt(2)) == 1 ? true:false; }
Một khi bạn đã lấy tất cả các kết quả của truy vấn của bạn, hãy chắc chắn rằng bạn gọi phương thức close()
của các đối tượng Cursor
để đóng tất cả các tài nguyên mà nó nắm giữ.
myCursor.close();
Tương tự, khi bạn đã hoàn thành tất cả các hoạt động trên cơ sở dữ liệu của bạn, đừng quên gọi phương thức close()
của đối tượng SQLiteDatabase
.
myDB.close();
3. Sử dụng bộ nhớ lưu trữ bên trong
Mỗi ứng dụng Android có một thư mục lưu trữ riêng bên trong liên kết với nó, trong đó ứng dụng có thể lưu trữ văn bản và các tập tin nhị phân. Các tập tin nằm trong thư mục này không thể truy cập bởi người dùng hoặc các ứng dụng khác được cài đặt trên thiết bị của người dùng. Chúng cũng sẽ tự động được loại bỏ khi người dùng gỡ bỏ ứng dụng.
Trước khi bạn có thể sử dụng thư mục lưu trữ bên trong, bạn phải xác định vị trí của nó. Để làm như vậy, bạn có thể gọi phương thức getFilesDir()
, nó sẵn có trong cả các Activity và Service.
File internalStorageDir = getFilesDir();
Để có được một tham chiếu đến một tập tin bên trong thư mục, bạn có thể truyền vào tên của các tập tin cùng với vị trí mà bạn xác định. Ví dụ, ở đây là cách bạn có được một tham chiếu đến một tập tin gọi là alice.csv:
File alice = new File(internalStorageDir, "alice.csv");
Từ thời điểm này trở đi, bạn có thể sử dụng kiến thức về các lớp Java I/O và các phương thức đọc hoặc ghi vào tập tin. Đoạn code sau đây cho bạn thấy cách sử dụng một đối tượng FileOutputStream
và phương thức write()
để ghi vào tập tin:
// Create file output stream fos = new FileOutputStream(alice); // Write a line to the file fos.write("Alice,25,1".getBytes()); // Close the file output stream fos.close();
4. Sử dụng bộ nhớ lưu trữ bên ngoài
Vì khả năng lưu trữ bên trong của các thiết bị Android thường cố định, và thường là khá hạn chế, một số thiết bị Android hỗ trợ phương tiện lưu trữ rời bên ngoài như thẻ micro-SD. Tôi khuyên bạn nên sử dụng tùy chọn lưu trữ này cho các tập tin lớn, chẳng hạn như hình ảnh và video.
Không giống như bộ lưu trữ bên trong, bộ lưu trữ bên ngoài có thể không phải lúc nào cũng có sẵn. Vì vậy, bạn phải luôn luôn kiểm tra xem nó có được lắp vào hay chưa trước khi sử dụng nó. Để làm như vậy, sử dụng phương thức getExternalStorageState()
của lớp Environment
.
if(Environment.getExternalStorageState() .equals(Environment.MEDIA_MOUNTED)) { // External storage is usable } else { // External storage is not usable // Try again later }
Một khi bạn đã chắc chắn rằng lưu trữ bên ngoài có sẵn, bạn có thể lấy đường dẫn thư mục lưu trữ bên ngoài cho ứng dụng của bạn bằng cách gọi phương thức getExternalFilesDir()
và truyền vào null
như là đối số cho nó. Bạn có thể sử dụng đường dẫn để tham chiếu các tập tin bên trong thư mục. Ví dụ, ở đây là cách bạn tham chiếu một tập tin gọi là bob.jpg trong thư mục lưu trữ bên ngoài của ứng dụng:
File bob = new File(getExternalFilesDir(null), "bob.jpg");
Bằng cách yêu cầu người dùng chấp nhận quyền WRITE_EXTERNAL_STORAGE
, bạn có thể đọc/ghi vào toàn bộ hệ thống tập tin trên bộ lưu trữ bên ngoài. Sau đó bạn có thể sử dụng các thư mục công cộng thông dụng để lưu trữ hình ảnh, phim ảnh và tập tin đa phương tiện khác của bạn. Lớp Environment
cung cấp một phương thức gọi là getExternalStoragePublicDirectory()
để xác định đường dẫn của các thư mục công cộng đó.
Ví dụ, bằng cách truyền giá trị Environment.DIRECTORY_PICTURES
vào phương thức, bạn có thể xác định đường dẫn của thư mục công cộng trong đó bạn có thể lưu trữ hình ảnh. Tương tự, nếu bạn truyền giá trị Environment.DIRECTORY_MOVIES
vào phương thức, bạn nhận được đường dẫn của thư mục công cộng trong đó phim ảnh có thể được lưu trữ.
Dưới đây là cách bạn tham chiếu đến một tập tin gọi là bob.jpg trong thư mục hình ảnh công cộng:
File bobInPictures = new File( Environment.getExternalStoragePublicDirectory( Environment.DIRECTORY_PICTURES), "bob.jpg" );
Một khi bạn đã có đối tượng File
, bạn có thể sử dụng các lớp FileInputStream
và FileOutputStream
để đọc hoặc ghi vào nó.
Tổng kết
Bây giờ bạn đã biết cách sử dụng hầu hết các tùy chọn lưu trữ cục bộ được cung cấp bởi Android SDK. Bất kể tùy chọn lưu trữ mà bạn chọn, các hoạt động đọc/ghi có thể mất nhiều thời gian nếu một khối lượng lớn dữ liệu có liên quan. Vì vậy, để đảm bảo rằng tiến trình UI luôn được đáp ứng, thì bạn phải xem xét chạy các hoạt động trong một tiến trình khác.
Để tìm hiểu thêm về việc lưu dữ liệu ứng dụng cục bộ, hãy tham khảo tài liệu hướng dẫn data storage API chính thức.
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post