AndroidTXT阅读器的实现(—)扫描sd卡或选择文件路径添加文件到listview及listview的多选删除...

论坛 期权论坛 脚本     
匿名技术用户   2021-1-4 12:35   11   0

不知怎么突然有了想写一个txt阅读器的想法 ……目前只实现了一小部分功能,并且参考了网上很多大神的代码,受益匪浅!!~

目前实现的功能:

1.(1)首次打开阅读器时,会弹出选择对话框,可以选择扫描sd卡方式,扫描出sd卡上的所有txt文件并进行简单的筛选(>50KB)之后,得到的文件将被显示在ListView中;

(2)若选择了通过路径添加,则会弹出路径选择的Activity,点击确定后选择的txt文件将会出现在ListView的最后;

(3)若选择了稍后手动添加,则稍候可点击界面右上角加号弹出该选择对话框。

2.长按ListView中的item,则会进入多选删除模式。

嗯哼……开始贴代码了……

主activity的布局文件就不贴了 。。一个ListView。。。一个listitem。。。贴一下menu:book_list.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/action_addingbooks"
        android:icon="@android:drawable/ic_menu_add"
        android:orderInCategory="500"
        android:showAsAction="ifRoom"
        android:title="添加书籍"/>

</menu>

实现右上角的加号,点击弹出添加书籍对话框功能。

然后是BookListActivity.class

package com.ldgforever.jianreader;

import android.app.*;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.*;
import android.util.Log;
import android.view.*;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.AbsListView.MultiChoiceModeListener;
import com.ldgforever.jianreader.R;
import com.ldgforever.savedata.savedataListMap;
import java.io.File;
import java.util.*;

public class BookListActivity extends Activity {

 private static List<String> file_name;
 private static List<String> file_txt_path;
 private MyBookAdapter adapter;
 private File file;
 private List<Map<String, String>> listItems;
 private MultiModeCallback mCallback;
 private String mExternalStoragePath;
 private Handler mHandler;
 private ListView mListView;
 private ProgressDialog mProgressDialog;

 /**
  * 接收返回的路径
  */
 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  Log.d("com.ldgforever.jianreader", "receivingPath");
  if (data != null) {
   Log.d("com.ldgforever.jianreader", "onActivityResult");
   String mPath = data.getStringExtra("file");
   File pathFile = new File(mPath);
   Map<String, String> pathMap = new HashMap<String, String>();
   if (pathFile.exists()) {
    if (pathFile.getName().endsWith(".txt")) {
     pathMap.put("Name", pathFile.getName());
     pathMap.put("Path", pathFile.getPath());
     listItems.add(pathMap);
     savedataListMap.saveInfo(BookListActivity.this, "ListMap", listItems);
     ShowTxtFilesInList(listItems);
    } else {
     Toast.makeText(BookListActivity.this, "请选择一个txt文件!", 0).show();
     ;
    }
   }
  }
 }

 @Override
 protected void onCreate(Bundle bundle) {
  super.onCreate(bundle);
  setContentView(R.layout.activity_book_list);

  mProgressDialog = new ProgressDialog(BookListActivity.this);
  mProgressDialog.setCancelable(false);
  mProgressDialog.setMessage("正在搜索书籍,请稍候 ……");

  mExternalStoragePath = Environment.getExternalStorageDirectory().toString();
  file = new File(mExternalStoragePath);

  file_name = new ArrayList<String>();
  file_txt_path = new ArrayList<String>();
  listItems = new ArrayList<Map<String, String>>();

  listItems = savedataListMap.getInfo(BookListActivity.this, "ListMap");
  if (listItems.isEmpty()) {
   BookAddingDialog();
  } else {
   ShowTxtFilesInList(listItems);
  }

  mHandler = new Handler() {
   public void handleMessage(Message message) {
    switch (message.what) {
    case 11:
     ShowTxtFilesInList(listItems);
     savedataListMap.saveInfo(BookListActivity.this, "ListMap", listItems);
     if (mProgressDialog.isShowing()) {
      mProgressDialog.dismiss();
      return;
     }
     break;
    case 12:
     ShowTxtFilesInList(listItems);
     savedataListMap.saveInfo(BookListActivity.this, "ListMap", listItems);
     if (mProgressDialog.isShowing()) {
      mProgressDialog.dismiss();
      return;
     }
     break;
    default:
     break;
    }
    return;
   }
  };
 }

 /**
  * 书籍添加对话框
  */
 private void BookAddingDialog() {
  android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(this);
  builder.setTitle("请选择添加书籍的方式");
  builder.setPositiveButton("扫描SDCard添加", new android.content.DialogInterface.OnClickListener() {
   public void onClick(DialogInterface dialoginterface, int i) {
    listItems = new ArrayList<Map<String, String>>();
    mProgressDialog.show();
    new Thread() {
     public void run() {
      listFileTxt(file);
      mHandler.sendEmptyMessage(12);
     }
    }.start();
   }
  });
  builder.setNegativeButton("选择路径添加", new android.content.DialogInterface.OnClickListener() {

   public void onClick(DialogInterface dialoginterface, int i) {

    Intent intent = new Intent(BookListActivity.this, MyFileManager.class);
    startActivityForResult(intent, 2);
   }
  });
  builder.setNeutralButton("稍后手动添加", new android.content.DialogInterface.OnClickListener() {

   public void onClick(DialogInterface dialoginterface, int i) {
    dialoginterface.dismiss();
   }

  });
  builder.create().show();
 }

 /**
  * 将保存在List<Map<String,String>>中的书籍信息显示到ListView中
  * @param listItems
  */
 private void ShowTxtFilesInList(List<Map<String, String>> listItems) {
  if (file_name != null) {
   for (int i = 0; i < file_name.size(); i++) {
    HashMap<String, String> hashmap = new HashMap<String, String>();
    hashmap.put("Name", (String) file_name.get(i));
    hashmap.put("Path", (String) file_txt_path.get(i));
    listItems.add(hashmap);
   }
   adapter = new MyBookAdapter(this, listItems);
   mCallback = new MultiModeCallback();
   mListView = (ListView) findViewById(R.id.booklist);
   mListView.setChoiceMode(3); // Multi
   mListView.setMultiChoiceModeListener(mCallback);
   mListView.setAdapter(adapter);
  } else {
   failAddingDialog();
   return;
  }
 }

 /**
  * 添加书籍失败对话框
  */
 private void failAddingDialog() {
  android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(this);
  builder.setTitle("添加书籍失败");
  builder.setPositiveButton("确定", new android.content.DialogInterface.OnClickListener() {
   public void onClick(DialogInterface dialoginterface, int i) {
    dialoginterface.dismiss();
   }
  });
 }

 /**
  * 递归查找SD卡上所有书籍
  * @param file
  */
 public static void listFileTxt(File file) {
  File[] files = file.listFiles();

  try {
   for (File f : files) {
    if (!f.isDirectory()) {
     if (f.getName().endsWith(".txt")) {
      long size = f.length();
      if (size > 50 * 1024) {
       file_name.add(f.getName());
       file_txt_path.add(f.getAbsolutePath());
      }
     }
    } else if (f.isDirectory()) {
     listFileTxt(f);
    }
   }
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }

 public boolean onCreateOptionsMenu(Menu menu) {
  getMenuInflater().inflate(R.menu.book_list, menu);
  return super.onCreateOptionsMenu(menu);
 }

 public boolean onOptionsItemSelected(MenuItem menuitem) {
  switch (menuitem.getItemId()) {
  case R.id.action_addingbooks:
   BookAddingDialog();
   break;

  default:
   break;
  }
  return true;
 }

 private class MultiModeCallback implements MultiChoiceModeListener {

  public boolean onActionItemClicked(ActionMode actionmode, MenuItem menuitem) {
   switch (menuitem.getItemId()) {
   case R.id.menu_delete:
    adapter.deleteSeletcedItems();
    adapter.notifyDataSetChanged();
    actionmode.finish();
    return true;
   default:
    return false;
   }
  }

  public boolean onCreateActionMode(ActionMode actionmode, Menu menu) {
   actionmode.getMenuInflater().inflate(R.menu.book_actionmenu, menu);
   adapter.setItemMultiCheckable(true);
   adapter.notifyDataSetChanged();
   return true;
  }

  public void onDestroyActionMode(ActionMode actionmode) {
   savedataListMap.saveInfo(BookListActivity.this, "ListMap", listItems);
   adapter.setItemMultiCheckable(false);
   adapter.clearSeletedItems();
   adapter.notifyDataSetChanged();
  }

  public void onItemCheckedStateChanged(ActionMode actionmode, int i, long l, boolean flag) {
   if (flag)
    adapter.addSelectedItem(i);
   else
    adapter.cancelSelectedItem(i);
   adapter.notifyDataSetChanged();
   actionmode.invalidate();
  }

  public boolean onPrepareActionMode(ActionMode actionmode, Menu menu) {
   return false;
  }
 }
}


程序里有一定的注释0-0,直接看比较清晰。查找txt文件用的是递归查找文件名末尾为".txt"的文件,如果满足条件就添加到Map<String,String>里。这里还自定义了一个Adapter用以将txt文件更新到ListView上并且应用了ActionMode实现了ListView的多选和删除功能。关于ActionMode的使用参考了以下两篇文章,感谢!

1.http://blog.csdn.net/xyz_lmn/article/details/12754785

2.http://blog.csdn.net/ghost_programmer/article/details/46827933 (强推)

然后就是点击通过路径添加之后通过startForResult打开路径添加的Activity

嚄……贴一下actionmode的menu,里面只有一个删除的按钮

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
  
    <item
        android:id="@+id/menu_delete"
        android:icon="@android:drawable/ic_menu_delete"
        android:showAsAction="ifRoom"
        android:title="删除"/>

</menu>

贴一下自定义的BookAdapter,删除添加item的方法也写在了里面

package com.ldgforever.jianreader;

import android.content.Context;
import android.view.*;
import android.widget.*;
import java.util.*;

import com.ldgforever.jianreader.R;

public class MyBookAdapter extends BaseAdapter {

 private List<Map<String, String>> listItems;
 private static List<Map<String, String>> isSelected;
 private boolean itemMultiCheckable;
 private Context mContext;
 private ViewHolder mViewHolder;

 static class ViewHolder {
  public TextView mBookName;
  public CheckBox mCheckBox;
 }

 public MyBookAdapter(Context context, List<Map<String, String>> listItems) {
  this.mContext = context;
  this.listItems = listItems;
  isSelected = new ArrayList<Map<String, String>>();
 }

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

 @Override
 public int getCount() {
  return listItems.size();
 }

 @Override
 public Object getItem(int i) {
  return listItems.get(i);
 }

 @Override
 public View getView(int i, View view, ViewGroup viewgroup) {
  mViewHolder = new ViewHolder();
  if (view == null) {
   view = LayoutInflater.from(mContext).inflate(R.layout.booklist_item, null);
   mViewHolder.mBookName = (TextView) view.findViewById(R.id.book_name);
   mViewHolder.mCheckBox = (CheckBox) view.findViewById(R.id.mCheckBox);
   view.setTag(mViewHolder);
  } else {
   mViewHolder = (ViewHolder) view.getTag();
  }
  if (itemMultiCheckable) {
   mViewHolder.mCheckBox.setVisibility(View.VISIBLE);
   if (isSelected.contains(listItems.get(i))) {
    mViewHolder.mCheckBox.setChecked(true);
   } else {
    mViewHolder.mCheckBox.setChecked(false);
   }
  } else {
   mViewHolder.mCheckBox.setVisibility(View.GONE);
  }

  mViewHolder.mBookName.setText(listItems.get(i).get("Name"));
  return view;
 }

 public void addSelectedItem(int i) {
  isSelected.add(listItems.get(i));
 }

 public void cancelSelectedItem(int i) {
  isSelected.remove(listItems.get(i));
 }

 public void clearSeletedItems() {
  isSelected = new ArrayList<Map<String, String>>();
 }

 public void deleteSeletcedItems() {
  for (Map<String, String> map : isSelected) {
   listItems.remove(map);
  }
 }

 public void setItemMultiCheckable(boolean flag) {
  itemMultiCheckable = flag;
 }
}
为了每次打开应用不重新扫描txt……需要存储一下存有txt文件信息的List<Map<String,String>>,这里我主要查到了两种方法,1.序列化 2.存为JSON数组形式 然后保存在SharePreference中

1.序列化
package com.ldgforever.jianreader;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

public class SeriallizableList implements Serializable {

 private List<Map<String, String>> listItems;

 public SeriallizableList() {
 }

 public List<Map<String, String>> getListItems() {
  return listItems;
 }

 public void setListItems(List<Map<String, String>> list) {
  listItems = list;
 }
}

2.保存为JSON数组形式
这里就不贴了0.0 贴出参考的内容相同的博(虽然是在别的网站看见的但是贴站内好像比较友好……?),感觉没有什么改的必要。
http://blog.csdn.net/windowsxp2014/article/details/44620113

然后0.0就到了选择路径添加的部分……首先来看一下布局文件

一个用来显示当前目录路径的TextView,一个ListView列出可供选择的文件,线性布局的最下方是确定和取消两个按钮。这里还应用了Selector来改变点击ListView的item时的背景颜色,为了某种程度上的美观……?通过android:listSelector = "@drawable/mfilelist_view"设置

<?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:background="#FFFFFF"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/tv_path"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="5px"
        android:textColor="#436EEE"
        android:textSize="20sp" >
    </TextView>

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="9" 
        android:listSelector="@drawable/mfilelist_view">
    </ListView>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="#FFFFFF"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/btn_yes"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_margin="6dp"
            android:layout_weight="1"
            android:background="#436EEE"
            android:text="确定"
            android:textColor="#FFFFFF" />

        <Button
            android:id="@+id/btn_cancel"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_margin="6dp"
            android:layout_weight="1"
            android:background="#436EEE"
            android:text="取消"
            android:textColor="#FFFFFF" />
    </LinearLayout>

</LinearLayout>

mfilelist_view.xml如下

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >

  <item android:state_selected="true" 
        android:drawable="@color/lightyellow" /> 
        
  <item android:state_focused="true" 
        android:drawable="@color/lightyellow" />
  
  <item android:state_pressed="true" 
        android:drawable="@color/lightyellow" />
    
</selector>

及其应用的color.xml(values文件夹下)

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <color name="white">#ffffff</color>
    <color name="black">#000000</color>
    <color name="lightyellow">#FFEBCD</color>

</resources>

list_item懒得贴了,没有什么图标啥的就是一个光秃秃的TextView。

自定义的Adapter如下

package com.ldgforever.jianreader;

import java.io.File;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class MyFileAdapter extends BaseAdapter {

 private LayoutInflater mInflater;
 private List<String> items;
 private List<String> paths;

 public MyFileAdapter(Context context, List<String> items, List<String> paths) {
  mInflater = LayoutInflater.from(context);
  this.items = items;
  this.paths = paths;
 }

 public int getCount() {
  return items.size();
 }

 public Object getItem(int position) {
  return items.get(position);
 }

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

 public View getView(int position, View convertView, ViewGroup parent) {
  ViewHolder holder;

  if (convertView == null) {
   convertView = mInflater.inflate(R.layout.filelist_item, null);
   holder = new ViewHolder();
   holder.mFileTextView = (TextView) convertView.findViewById(R.id.list_text);

   convertView.setTag(holder);
  } else {
   holder = (ViewHolder) convertView.getTag();
  }

  File f = new File(paths.get(position).toString());
  if (items.get(position).toString().equals("b1")) {
   holder.mFileTextView.setText("返回根目录..");
  } else if (items.get(position).toString().equals("b2")) {
   holder.mFileTextView.setText("返回上一层..");
  } else {
   if (f.isDirectory()) {
    holder.mFileTextView.setText("+ "+f.getName());
   } else {
    holder.mFileTextView.setText(f.getName());
   }
  }

  return convertView;
 }

 private class ViewHolder {
  TextView mFileTextView;
 }
}

最后就路径添加的Activity了,若点击的为目录,则用ListView显示当前目录下的所有文件;反之就出现选中,背景颜色改变。点击确定后,将获取的选定的文件路径传回BookListActivity。若点击取消则直接finish掉当前Activity。
package com.ldgforever.jianreader;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class MyFileManager extends ListActivity {

 private List<String> items = null;
 private List<String> paths = null;
 private String rootPath = "/";
 private String curPath = "/";
 private TextView mPath;
 private MyFileAdapter adapter;
 private boolean mItemFlag = false;

 @Override
 protected void onCreate(Bundle bundle) {
  super.onCreate(bundle);
  setContentView(R.layout.activity_fileselect_list);

  mPath = (TextView) findViewById(R.id.tv_path);

  Button buttonConfirm = (Button) findViewById(R.id.btn_yes);
  buttonConfirm.setOnClickListener(new OnClickListener() {

   public void onClick(View v) {
    if (mItemFlag) {
     Intent data = new Intent(MyFileManager.this, BookListActivity.class);
     data.putExtra("file", curPath);
     Log.d("com.ldgforever.jianreader", curPath);
     setResult(2, data);
     finish();
    } else {
     Toast.makeText(MyFileManager.this, "请选择一个txt文件!", 0).show();
    }
   }
  });
  Button buttonCancle = (Button) findViewById(R.id.btn_cancel);
  buttonCancle.setOnClickListener(new OnClickListener() {

   public void onClick(View v) {
    finish();
   }
  });
  getFileDir(rootPath);
 }

 /**
  * 如果文件是目录,则将目录下的文件显示在listview中
  * 
  * @param filePath
  */
 private void getFileDir(String filePath) {
  mPath.setText(filePath);
  items = new ArrayList<String>();
  paths = new ArrayList<String>();
  File f = new File(filePath);
  adapter = new MyFileAdapter(this, items, paths);
  if (f.isDirectory()) {
   File[] files = f.listFiles();

   if (!filePath.equals(rootPath)) {
    items.add("b1");
    paths.add(rootPath);
    items.add("b2");
    paths.add(f.getParent());
   }

   if (files != null) {
    for (int i = 0; i < files.length; i++) {
     File file = files[i];
     items.add(file.getName());
     paths.add(file.getPath());
    }
   }
  }
  setListAdapter(adapter);
 }

 @Override
 protected void onListItemClick(ListView l, View v, int position, long id) {
  if (!mItemFlag) {
   v.setBackgroundColor(getResources().getColor(R.color.lightyellow));
   mItemFlag = true;
  } else {
   v.setBackgroundColor(getResources().getColor(R.color.white));
   mItemFlag = false;
  }
  File file = new File(paths.get(position));
  if (file != null) {
   if (file.isDirectory()) {
    curPath = paths.get(position);
    getFileDir(paths.get(position));
   } else {
    curPath = paths.get(position);
   }
  }
 }
}






转载于:https://www.cnblogs.com/ldgforever/p/5990946.html

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP