Trong phần này chúng ta sẽ xây dựng một ứng dụng file explorer (duyệt file) đơn giản.
Chúng ta tạo project với tên FileExplorer,
file Activity
là MainActivity.java,
file layout cho Activity này là main.xml.
Main Layout
Trong file main.xml
chúng ta thiết kế như sau:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" androd:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:id="@+id/txtPath" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Path:" /> <Button android:id="@+id/btnBrowse" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Browse" android:onClick="onClicked"/> </LinearLayout>
Chúng ta thiết kế một TextView
và một Button, TextView
sẽ hiển thị đường dẫn tuyệt đối đến file mà người dùng chọn, Button
được dùng để mở một Activity
khác để duyệt file, phương thức xử lý sự kiện của Button
là onClicked().
MainActivity
Tiếp theo là file MainActivity.java:
package com.phocode; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.content.Intent; import android.widget.TextView; public class MainActivity extends Activity { private static final int FILE_CHOOSER_CODE = 1; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } public void onClicked(View view) { Intent fileChooserIntent = new Intent(this, FileChooserActivity.class); startActivityForResult(fileChooserIntent, FILE_CHOOSER_CODE); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode == FILE_CHOOSER_CODE) if(resultCode == RESULT_OK) { String fullPath = data.getStringExtra("FullPath"); TextView path = (TextView) findViewById(R.id.txtPath); path.setText(fullPath); } } }
Lớp MainActivity
sẽ hiển thị màn hình của file layout main.xml
và chịu trách nhiệm mở lớp FileChooserActivity
để duyệt file.
private static final int FILE_CHOOSER_CODE = 1;
Chúng ta định nghĩa code để mở Activity
mới.
public void onClicked(View view) { Intent fileChooserIntent = new Intent(this, FileChooserActivity.class); startActivityForResult(fileChooserIntent, FILE_CHOOSER_CODE); }
Trong phương thức onClicked(),
chúng ta tạo một đối tượng Intent
mới và gọi phương thức startActivityForResult()
để mở lớp FileChooserActivity
mà chúng ta sẽ viết ở dưới.
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if(requestCode == FILE_CHOOSER_CODE) if(resultCode == RESULT_OK) { String fullPath = data.getStringExtra("FullPath"); TextView path = (TextView) findViewById(R.id.txtPath); path.setText(fullPath); } }
Phương thức onActivityResult()
sẽ nhận kết quả trả về của lớp FileChooserActivity
là đường dẫn tuyệt đối của file mà người dùng chọn khi duyệt file, chúng ta lấy đường dẫn đó gán vào TextView.
ListView Layout
Không giống như các bài trước, chúng ta sử dụng ListView
chỉ để hiển thị những chuỗi string đơn lẻ, ở đây mỗi item của ListView
sẽ hiển thị tên file hoặc tên thư mục đi kèm với kích thước file nếu có. Nên chúng chúng ta thiết kế các item này giống như thiết kế một giao diện cho Activity
vậy.
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="5dp"> <TextView android:id="@+id/name" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="20sp" android:padding="10dp"/> <TextView android:id="@+id/size" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="10sp"/> </LinearLayout>
Chúng ta sẽ dùng 2 TextView,
một dùng để hiển thị tên file hoặc thư mục, một dùng để hiển thị kích thước file nếu có.
FileChooserActivity
Tiếp theo là lớp FileChooserActivity.
package com.phocode; import android.app.ListActivity; import android.os.Bundle; import android.content.Intent; import android.view.View; import android.widget.ArrayAdapter; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import java.io.File; import java.util.Arrays; import java.util.ArrayList; import java.util.List; import java.util.Collections; public class FileChooserActivity extends ListActivity { private ItemArrayAdapter la; private List<Item> itemArr; private String currentDirectory; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); currentDirectory = "/"; generateContent(currentDirectory); } @Override public void onListItemClick(ListView listView, View view, int position, long id) { Item selectedItem = (Item)getListAdapter().getItem(position); String newPath = ""; if(selectedItem.getName().equals("..")) newPath = new File(currentDirectory).getParent(); else { newPath = currentDirectory; if(currentDirectory.equals("/") == false) newPath += "/"; newPath += selectedItem.getName(); } File newFile = new File(newPath); if(newFile.isDirectory()) { currentDirectory = newPath; generateContent(currentDirectory); } else { Intent intent = new Intent(); intent.putExtra("FullPath", newPath); setResult(RESULT_OK, intent); finish(); } } private void generateContent(String path) { File f = new File(path); ArrayList<File> files = new ArrayList<File>(Arrays.asList(f.listFiles())); int fileSize = files.size(); itemArr = new ArrayList(); if(path.equals("/") == false) itemArr.add(new Item("..", 0)); for(int i = 0 ; i < fileSize ; i++) { String name = files.get(i).getName(); int size; if(files.get(i).isDirectory()) size = 0; else size = (int)files.get(i).length(); itemArr.add(new Item(name, size)); } la = new ItemArrayAdapter(this, itemArr); setListAdapter(la); } }
Lớp FileChooserActivity
sẽ có giao diện để người dùng chọn file hoặc thư mục.
currentDirectory = "/";
Chúng ta định nghĩa biến currentDirectory
dùng để lưu đường dẫn đến file hoặc thư mục được chọn. Mặc định khi chạy ứng dụng thì thư đây là đường dẫn đến thư mục gốc, thư mục gốc trong các hệ điều hành linux và Android là dấu "/"
.
private void generateContent(String path) { ... }
Khi Activity
này được khởi động, phương thức generateContent()
sẽ tìm danh sách các thư mục và file trong tham số path và đưa chúng lên màn hình.
File f = new File(path); ArrayList<File> files = new ArrayList<File>(Arrays.asList(f.listFiles()));
Đầu tiên chúng ta lấy danh sách các thư mục và file và lưu trong một đối tượng ArrayList<File>.
Phương thức File.listFiles()
sẽ trả về danh sách các thư mục và file hiện có dưới dạng mảng, phương thức Arrays.asList()
sẽ chuyển mảng thành kiểu List.
itemArr = new ArrayList(); if(path.equals("/") == false) itemArr.add(new Item("..", 0));
Chúng ta sẽ thực hiện lưu các đối tượng file/thư mục trong danh sách itemArr,
đây là một đối tượng List<Item>,
chúng ta sẽ viết lớp Item
ở dưới. Ngoài ra ở đây chúng ta còn kiểm tra xem thư mục hiện tại mà người dùng đang duyệt có phải là thư mục gốc hay không, nếu không thì chúng ta chèn thêm một đối tượng ".."
nữa, dấu ".."
nghĩa là lùi thư mục hiện tại về một cấp, chẳng hạn như chúng ta đang ở /sdcard/musics thì lùi một cấp sẽ thành /sdcard.
for(int i = 0 ; i < fileSize ; i++) { ... }
Trong vòng lặp for
chúng ta tiến hành kiểm tra xem các đối tượng File
là thư mục hay là file để tạo đối tượng Item
tương ứng. Phương thức length()
sẽ trả về kích thước của file, nếu đối tượng hiện tại là thư mục thì chúng ta gán kích thước là 0.
la = new ItemArrayAdapter(this, itemArr); setListAdapter(la);
Cuối cùng chúng ta thiết lập ArrayAdapter
để ListView
có thể nhận dữ liệu. Ở đây vì ListView
của chúng ta không chỉ hiển thị một phần tử đơn lẻ mà hiển thị nhiều phần tử cùng một lúc nên chúng ta phải tùy chỉnh lại lớp ArrayAdapter.
@Override public void onListItemClick(ListView listView, View view, int position, long id) { ... }
Phương thức onListItemClick()
sẽ tự động được gọi mỗi khi chúng ta click vào một item nào đó trên ListView.
Trong phương thức này chúng ta kiểm tra xem nếu người dùng click vào một thư mục thì chúng ta khởi tạo lại một đối tượng ArrayAdapter
mới, nếu người dùng click vào một file thì chúng ta tắt Activity
tại đây và gửi trả về đường dẫn đến file mà đó, nếu người dùng click vào nút ".."
thì chúng ta cho lùi thư mục về một cấp.
ItemArrayAdapter
package com.phocode; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; import java.util.List; public class ItemArrayAdapter extends ArrayAdapter<Item> { private Context context; private List<Item> values; public ItemArrayAdapter(Context context, List<Item> values) { super(context, R.layout.row, values); this.context = context; this.values = values; } @Override public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View row = inflater.inflate(R.layout.row, parent, false); TextView name = (TextView) row.findViewById(R.id.name); TextView size = (TextView) row.findViewById(R.id.size); Item currentItem = values.get(position); name.setText(currentItem.getName()); if(currentItem.getSize() > 0) size.setText(String.valueOf(currentItem.getSize()) + " bytes"); else size.setText(""); return row; } }
Lớp ItemArrayAdapter
sẽ kế thừa từ lớp ArrayAdapter.
@Override public View getView(int position, View convertView, ViewGroup parent) { ... }
Chúng ta tùy chỉnh cách mà các item sẽ được hiển thị trong phương thức getView().
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View row = inflater.inflate(R.layout.row, parent, false); TextView name = (TextView) row.findViewById(R.id.name); TextView size = (TextView) row.findViewById(R.id.size);
Chúng ta lấy 2 phần tử TextView
trong file layout.
name.setText(currentItem.getName()); if(currentItem.getSize() > 0) size.setText(String.valueOf(currentItem.getSize()) + " bytes"); else size.setText("");
Với mỗi item trên ListView,
nếu item đó là file thì chúng ta hiển thị tên file và kích thước file, còn nếu là thư mục thì chúng ta không cho hiển thị kích thước.
Item
Cuối cùng là lớp Item.
package com.phocode; public class Item { private String name; private int size; public Item() { this.name = ""; this.size = 0; } public Item(String name, int size) { this.name = name; this.size = size; } public String getName() { return this.name; } public int getSize() { return this.size; } public void setName(String name) { this.name = name; } public void setSize(int size) { this.size = size; } }
Lớp Item
là lớp dùng để lưu thông tin về từng Item trên ListView,
bao gồm tên file/thư mục và kích thước file đó.