Sunday, April 27, 2014

Simple file manager for Android

Đây là chương trình đơn giản giúp bạn quản lý các file có trong sdcard của thiết bị Android

Các chức năng chính của chương trình gồm có:
  • Hiển thị các file có trong sdcard theo dạng danh sách.
  • Cho phép người dùng thực hiện các thao tác như cut, copy, delete trên một hoặc nhiều file
Bạn có thể tải source code chương trình tại đây.

Một số điểm đáng chú ý trong chương trình:

  • Các bạn cần phải khai báo permission trong file Manifest để có thể tương tác được với sdcard

  • Thuật toán đệ quy:
public void copyFolder(File src, File dest) throws IOException {
  if (src.isDirectory()) {
   if (!dest.exists()) {
    dest.mkdir();
   }
   String[] files = src.list();
   for (String file : files) {
    File srcFile = new File(src, file);
    File destFile = new File(dest, file);
    copyFolder(srcFile, destFile);
   }
  } else {
   InputStream in = new FileInputStream(src);
   OutputStream out = new FileOutputStream(dest);
   byte[] buffer = new byte[1024];
   int length;
   while ((length = in.read(buffer)) > 0) {
    out.write(buffer, 0, length);
   }
   in.close();
   out.close();
  }
 }
Để copy 1 folder ta phải copy toàn bộ file của nó, đối với các subfolder ta cũng tiến hành làm tương tự, vì vậy để giải quyết bài toán này ta sử dụng thuật toán đệ quy như trên.

Chúng ta cũng sử dụng thuật toán đệ quy để delete 1 folder.

  • Toàn bộ các function của chương trình đều chạy trên UIThread, điều này khiến chương trình không được mượt mà, nhất là khi các bạn copy, cut, delete các file có kích thước lớn, vì vậy các bạn hãy sũy nghĩ cách sử dụng Multithreading để cải tiến chương trình.


Tuesday, April 15, 2014

ActionBar và ListView

Bài viết này sẽ hướng dẫn các bạn sử dụng ActionBar kết hợp với ListView trong Android. Các bạn có thể xem bài viết về ListView tại đây.

Chương trình hoàn thiện sẽ có giao diện như hình bên dưới, phần ListView sẽ hiển thị danh sách các thư mục có trong sdcard, cho phép chọn nhiều item trong ListView, lọc các file bằng search box trên ActionBar.

ActionBar xuất hiện trong Android từ phiên bản 3.0(API level 11), nhưng bạn có thể sử dụng ActionBar thông qua Support Library cho các phiên bản từ 2.1(API level 7) trở lên. Trong bài viết này mình sẽ sử dụng Support Library, các bạn có thể tìm hiểu các thức setup Support Library tại đây.

Đầu tiên các bạn tiến hành tạo project mới như hình bên dưới 
Các thư mục chính trong project:
  • scr gồm có 2 class:
    • CustomListViewAdapter.java: sử dụng cho ListView
    • MainActivity.java: chứa các thành phần chính của chương trình.
  • drawable:
    • Hai file hình ảnh là icon của file và folder
    • background_selected.xml, background_deselected.xml, list_item_background_selector.xml được dùng cho các trạng thái khác nhau của ListView item.
  • layout, menu:
    • activity_main.xml: định nghĩa giao diện chính của chương trình
    • list_item.xml: giao diện của một item trong ListView
    • action_mode.xml: định nghĩa menu trong action mode.
    • main.xml: menu chính của chương trình.
  • AndroidManifest.xml:



    

    
    

    
        
            
                

                
            
        
    

  • activity_main.xml:



    
    




  • list_item.xml:



    

    

        

        

        
    




  • list_item_background_selector.xml:



    
    
    




  • background_selected.xml:





  • background_deselected.xml:






  • action_mode.xml:



    
    
    




  • main.xml:



  • CustomListViewAdapter.java:

public class CustomListViewAdapter extends BaseAdapter {
 
 private LayoutInflater inflater;
 private File[] listFile;
 private Context context;
 
 public CustomListViewAdapter(Context context, File[] files){
  this.context = context;
  inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  listFile = files;
 }
 

 @Override
 public int getCount() {
  return listFile.length;
 }

 @Override
 public Object getItem(int position) {
  return listFile[position];
 }

 @Override
 public long getItemId(int position) {
  return position;
 }

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  if(convertView == null)
   convertView = inflater.inflate(R.layout.list_item, null);
  ImageView iv = (ImageView) convertView.findViewById(R.id.iv_icon);
  TextView tvFileName = (TextView) convertView.findViewById(R.id.tv_file_name);
  TextView tvFileSize = (TextView) convertView.findViewById(R.id.tv_file_size);
  TextView tvDateModify = (TextView) convertView.findViewById(R.id.tv_date_modify);
  File file = listFile[position];
  long size = 0;
  if(file.isDirectory()){
   size = folderSize(file);
   iv.setImageDrawable(context.getResources().getDrawable(R.drawable.folder_icon));
  }
  else{
   iv.setImageDrawable(context.getResources().getDrawable(R.drawable.file_icon));
   size = file.length();
  }
  tvFileName.setText(file.getName());
  tvFileSize.setText(readableFileSize(size));
  tvDateModify.setText(convertTime(file.lastModified()));
  return convertView;
 }
 
 public static String readableFileSize(long size) {
     if(size <= 0) return "0 B";
     final String[] units = new String[] { "B", "KB", "MB", "GB", "TB" };
     int digitGroups = (int) (Math.log10(size)/Math.log10(1024));
     return new DecimalFormat("#,##0.#").format(size/Math.pow(1024, digitGroups)) + " " + units[digitGroups];
 }
 
 public String convertTime(long time){
     Date date = new Date(time);
     Format format = DateFormat.getDateInstance();
     return format.format(date).toString();
 }
 
 public static long folderSize(File directory) {
     long length = 0;
     for (File file : directory.listFiles()) {
         if (file.isFile())
             length += file.length();
         else
             length += folderSize(file);
     }
     return length;
 }

}

  • MainActivity.java:

Các bạn có thể tải source code project tại đây

Thursday, April 10, 2014

Custom ListView

Chào các bạn bài viết này mình sẽ hướng dẫn các bạn tạo ra một custom ListView trong Android.

Sau khi hoàn thành chương trình sẽ trông như hình bên dưới:

Đây là một chương trình đơn giản, sử dụng ListView để hiển thị toàn bộ file và folder trong sdcard của thiết bị Android.

Đầu tiên các bạn tạo một android project như hình bên dưới:
Đây là cấu trúc thư mục của project sau khi tạo xong:
  • CustomListViewAdapter.java: lớp này là Adapter, đóng vai trò trung gian giữa giữ liệu(data) và ListView.
  • MainActivity.java: lớp này chịu trách nhiệm hiển thị giao diện chính của chương trình.
  • activity_main.xml: là file định nghĩa layout chính của chương trình.
  • list_item.xml: là file định nghĩa layout của một  item trong ListView.

Để có thể thao tác được với sdcard chúng ta phải thêm permission vào trong file AndroidManifest.xml
activity_main.xml:




    
    


list_item.xml:




    

    

    

        

        

        
    


CustomListViewAdapter.java:


public class CustomListViewAdapter extends BaseAdapter {
 
 private LayoutInflater inflater;
 private File[] listFile;
 private Context context;
 
 public CustomListViewAdapter(Context context, File file){
  this.context = context;
  inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  listFile = file.listFiles();
 }
 

 @Override
 public int getCount() {
  return listFile.length;
 }

 @Override
 public Object getItem(int position) {
  return listFile[position];
 }

 @Override
 public long getItemId(int position) {
  return position;
 }

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  if(convertView == null)
   convertView = inflater.inflate(R.layout.list_item, null);
  ImageView iv = (ImageView) convertView.findViewById(R.id.iv_icon);
  TextView tvFileName = (TextView) convertView.findViewById(R.id.tv_file_name);
  TextView tvFileSize = (TextView) convertView.findViewById(R.id.tv_file_size);
  TextView tvDateModify = (TextView) convertView.findViewById(R.id.tv_date_modify);
  File file = listFile[position];
  long size = 0;
  if(file.isDirectory()){
   size = folderSize(file);
   iv.setImageDrawable(context.getResources().getDrawable(R.drawable.folder_icon));
  }
  else{
   iv.setImageDrawable(context.getResources().getDrawable(R.drawable.file_icon));
   size = file.length();
  }
  tvFileName.setText(file.getName());
  tvFileSize.setText(readableFileSize(size));
  tvDateModify.setText(convertTime(file.lastModified()));
  return convertView;
 }
 
 public static String readableFileSize(long size) {
     if(size <= 0) return "0 B";
     final String[] units = new String[] { "B", "KB", "MB", "GB", "TB" };
     int digitGroups = (int) (Math.log10(size)/Math.log10(1024));
     return new DecimalFormat("#,##0.#").format(size/Math.pow(1024, digitGroups)) + " " + units[digitGroups];
 }
 
 public String convertTime(long time){
     Date date = new Date(time);
     Format format = new SimpleDateFormat("yyyy MM dd HH:mm:ss");
     return format.format(date).toString();
 }
 
 public static long folderSize(File directory) {
     long length = 0;
     for (File file : directory.listFiles()) {
         if (file.isFile())
             length += file.length();
         else
             length += folderSize(file);
     }
     return length;
 }

}

MainActivity.java:


public class MainActivity extends ActionBarActivity {

 private ListView listView;
 private CustomListViewAdapter adapter;
 private File file;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  if (isExternalStorageWritable()) {
   listView = (ListView) findViewById(R.id.lv_file_view);
   file = Environment.getExternalStorageDirectory();
   adapter = new CustomListViewAdapter(this, file);
   listView.setAdapter(adapter);
  }
  else{
   Toast.makeText(this, "Can not interact with External Storage!", Toast.LENGTH_LONG).show();
  }
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
  // Handle action bar item clicks here. The action bar will
  // automatically handle clicks on the Home/Up button, so long
  // as you specify a parent activity in AndroidManifest.xml.
  int id = item.getItemId();
  if (id == R.id.action_settings) {
   return true;
  }
  return super.onOptionsItemSelected(item);
 }

 /* Checks if external storage is available for read and write */
 public boolean isExternalStorageWritable() {
  String state = Environment.getExternalStorageState();
  if (Environment.MEDIA_MOUNTED.equals(state)) {
   return true;
  }
  return false;
 }
}
link dowload source project: source