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


    不知怎么突然有了想写一个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);
    			}
    		}
    	}
    }






  • 相关阅读:
    二、java 与 scala相互调用
    Gradle Tips#1-tasks
    Guice 学习(六)使用Provider注入服务( Provider Inject Service)
    C++第15周(春)项目3
    cocos2d-x3.2中怎样优化Cocos2d-X游戏的内存
    jqGrid源代码分析(一)
    OCP-1Z0-051-题目解析-第6题
    PHP连接sql server 2005环境配置
    【剑指offer】替换字符串中的空格
    android 推断Apk是否签名和 签名是否一致
  • 原文地址:https://www.cnblogs.com/ldgforever/p/5990946.html
Copyright © 2020-2023  润新知