Giới thiệu
Thư mục assets/ dùng để lưu trữ file tĩnh (JSON, text, font, HTML, CSV...) được đóng gói cùng APK. Không giống res/raw/, assets giữ nguyên cấu trúc thư mục và tên file, không bị compile thành resource ID. Bài viết hướng dẫn đọc file từ assets bằng AssetManager.
Các bước thực hiện
Bước 1: Tạo dự án mới
Android Studio → File → New Project → Empty View Activity.
Bước 2: Tạo thư mục assets và thêm file
- Chuột phải vào module
app→ New → Folder → Assets Folder. - Chuột phải vào thư mục
assetsvừa tạo → New → File → đặt tênquotes.txt. - Nhập nội dung:
"Darkness cannot drive out darkness: only light can do that.
Hate cannot drive out hate: only love can do that."
— Martin Luther King Jr.
Bước 3: Thiết kế giao diện (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="24dp"
android:gravity="center"
tools:context=".MainActivity">
<Button
android:id="@+id/btnReadFile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Đọc file từ assets" />
<TextView
android:id="@+id/tvContent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="16dp"
android:padding="12dp"
android:textSize="16sp"
android:gravity="center"
android:background="@android:color/darker_gray"
tools:text="Nội dung file sẽ hiển thị ở đây" />
</LinearLayout>
Bước 4: Code đọc file (MainActivity.java / MainActivity.kt)
Java (sử dụng try-with-resources):
package com.example.readassets;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class MainActivity extends AppCompatActivity {
private TextView tvContent;
private Button btnReadFile;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvContent = findViewById(R.id.tvContent);
btnReadFile = findViewById(R.id.btnReadFile);
btnReadFile.setOnClickListener(v -> readFileFromAssets());
}
private void readFileFromAssets() {
try (InputStream inputStream = getAssets().open("quotes.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
tvContent.setText(stringBuilder.toString().trim());
} catch (IOException e) {
e.printStackTrace();
tvContent.setText("Lỗi đọc file: " + e.getMessage());
}
}
}
Kotlin (sử dụng extension function):
package com.example.readassets
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.readassets.databinding.ActivityMainBinding
import java.io.BufferedReader
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.btnReadFile.setOnClickListener {
readFileFromAssets()
}
}
private fun readFileFromAssets() {
try {
val inputStream = assets.open("quotes.txt")
val content = inputStream.bufferedReader().use { it.readText() }
binding.tvContent.text = content.trim()
} catch (e: Exception) {
binding.tvContent.text = "Lỗi đọc file: ${e.message}"
}
}
}
Đọc file JSON từ assets (ứng dụng thực tế)
File: assets/config.json
{
"api_base_url": "https://api.example.com",
"timeout": 30000,
"features": ["dark_mode", "offline_sync", "push_notifications"]
}
Code parse JSON (cần dependency Gson/Moshi):
// Kotlin + Moshi
private fun loadConfig(): AppConfig? {
return try {
val json = assets.open("config.json").bufferedReader().use { it.readText() }
Moshi.Builder().build().adapter(AppConfig::class.java).fromJson(json)
} catch (e: Exception) {
null
}
}
data class AppConfig(
val api_base_url: String,
val timeout: Int,
val features: List<String>
)
Assets vs res/raw
| Đặc điểm | assets/ | res/raw/ |
|---|---|---|
| Cấu trúc thư mục | Giữ nguyên (subfolders OK) | Phẳng (không có subfolder) |
| Truy cập | AssetManager.open() | Resources.openRawResource(R.raw.xxx) |
| Tên file | Bất kỳ (có dấu cách, chữ hoa) | Chỉ [a-z0-9_] |
| Compile time | Không generate R.id | Generate R.raw.xxx |
| Kích thước file | Không giới hạn | Không giới hạn |
Lưu ý quan trọng
- File trong assets không được nén khi build APK (trừ khi dùng
aaptOptions { noCompress "txt", "json" }). - Đọc file lớn nên dùng background thread (coroutine/RxJava) để không block UI thread.
- Đóng
InputStreamsau khi dùng (try-with-resources hoặc.use { }Kotlin). - Không thể ghi file vào assets lúc runtime (read-only). Cần ghi vào internal storage (
context.filesDir).