Android-文件浏览器(一)
题记:Hi,好久没更新了,深感坚持写技术博客的不易,不过把自己学到的东西拿出来跟大家分享真的很快乐,本人技术水平有限,还望海涵!
项目需求:Android平台下的 文件浏览器,我们默认浏览SD卡中的文件。
需求分析:我们知道Android SD卡也是一个文件夹,他的目录在../mnt/sdcard,注意android2.2之前目录是../sdcard,这个大家了解下就行了,那么我们考虑用J2se中的File 就可以遍历这个文件夹,获得里面的文件信息,所以还是比较简单的。
step1:新建项目A_FileBrowser,我们考虑,由于可能手机没有安装SD卡,所以考虑主界面使用ViewFlipper,可以检查SD是否可用后进行相应界面的切换后显示操作提示,这里我们一切从简,没有对布局进行太多的考虑,xml文件如下:
<?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="fill_parent"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
android:id="@+id/tvTips"
/>
<ViewFlipper
android:id="@+id/viewFlipper1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical"
>
<!-- (0)loading -->
<LinearLayout
android:id="@+id/loadLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
>
<ProgressBar
android:id="@+id/loadProgressbar"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
></ProgressBar>"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
>
<TextView
android:id="@+id/tvload"
android:layout_marginLeft="15dip"
android:layout_marginTop="10dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/loading"
/>
</LinearLayout>
</LinearLayout>
<!-- (1) listview -->
<LinearLayout
android:id="@+id/showLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#0f0000"
></ListView>
</LinearLayout>
<!-- (2) falied layout -->
<LinearLayout
android:id="@+id/retryLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
>
<TextView
android:id="@+id/tvFalied"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/load_falied"
></TextView>
<Button
android:id="@+id/retryBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/retry"
/>
</LinearLayout>
</ViewFlipper>
</LinearLayout>
step2:编写刚才创建的Activity中的代码:
这里要重点说明一下这一段代码:
private class NewsTask extends AsyncTask<String ,Void,FileAttr [] > {
@Override
protected FileAttr[] doInBackground(String... params) {
//sd card is aviable else show falied
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
{
File file = new File(params[0]);
if(file == null || !file.isDirectory())
{
return null;
}
mStack.push(params[0]);
File [] fileList = file.listFiles();
ArrayList<FileAttr> arrayList = new ArrayList<FileAttr>();
//
for(File fi : fileList)
{
Log.d(TAG,fi.getName());
FileAttr attr = new FileAttr();
if(fi.isDirectory())
{
attr.setFileName(fi.getName() );
attr.setFileType(AttrDefine.DIC);
Log.d(TAG,"is dic");
}
else if(fi.getName().endsWith(".txt"))
{
attr.setFileName(fi.getName());
attr.setFileType(AttrDefine.TXT);
}
else if(fi.getName().endsWith(".mp3"))
{
attr.setFileName(fi.getName());
attr.setFileType(AttrDefine.AUD);
}
else if(fi.getName().endsWith(".3gp"))
{
attr.setFileName(fi.getName());
attr.setFileType(AttrDefine.VID);
}
else if(fi.getName().endsWith(".png") || fi.getName().endsWith(".jpeg"))
{
attr.setFileName(fi.getName());
attr.setFileType(AttrDefine.PIC);
}
else
{
attr.setFileName(fi.getName());
attr.setFileType(AttrDefine.UNKNOW);
}
arrayList.add(attr);
}
if(arrayList.size() > 0)
{
FileAttr [] fileAttrs = new FileAttr[arrayList.size()];
for(int i = 0 ;i <arrayList.size() ; i ++)
{
fileAttrs[i] = arrayList.get(i);
}
return fileAttrs;
}
return null;
}
else
{
// mViewFlipper.setDisplayedChild(2);
// FileAttr[] files = new FileAttr[1];
// files[0] = new FileAttr();
// files[0].setFileType(0);
// return files;
return null;
}
}
@Override
protected void onPostExecute(FileAttr[] result) {
if( result == null)
{
mViewFlipper.setDisplayedChild(2);
}
else
{
mViewFlipper.setDisplayedChild(1);
Log.d(TAG,result[0].getFileType() + "");
adapter = new ImageAdapter(result,A_FileBrowserActivity.this);
mListView.setAdapter(adapter);
adapter.notifyDataSetChanged();
mListView.setOnItemLongClickListener(listListener);
Log.d(TAG,((FileAttr) adapter.getItem(0)).getFileType() + "");
}
super.onPostExecute(result);
}
@Override
protected void onPreExecute() {
mViewFlipper.setDisplayedChild(1);
super.onPreExecute();
}
@Override
protected void onProgressUpdate(Void... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
}
}
private class NewsTask extends AsyncTask<String ,Void,FileAttr [] >,我们新建了一个私有类,并继承了AsyncTack这个类,后面的三个参数是有选的,如果不需要用的话就用Void代替就可以了,这个类的作用是在后台替我们执行一段代码,并根据我们的输入运行我们需要实现的功能,当然我们可以在他的对应的成员方法中做我们需要做的事情,其中doInBackground(String... params)就是在后台要做的事情,params是我们传递的参数,onPostExecute(FileAttr[] result)是后台执行完毕后,根据后台方法返回值进行下一步代码执行。在这里我们完成了对SD卡的检测,并切换到对应界面,然后对SD卡根目录进行浏览遍历,在listview中显示,运行效果如下:

这里还要提一下的是,由于列表显示,Android里面适配器一般都是由我们自己来重写实现,毕竟自由度很大,这也是我认为的Android平台最大魅力的地方,足够开放,我们自定义了一个ImageAdapter extends BaseAdapter,代码如下:
public class ImageAdapter extends BaseAdapter {
public static final int S_YEAR = 1970;
public static final int S_MONTH = 1;
public static final int S_DAY = 1;
private FileAttr [] mFileAttr;
private Context mContext;
public ImageAdapter(FileAttr [] fileAttr , Context context)
{
this.mFileAttr = fileAttr;
this.mContext = context;
}
public FileAttr[] getmFileAttr() {
return mFileAttr;
}
public void setmFileAttr(FileAttr[] mFileAttr) {
this.mFileAttr = mFileAttr;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mFileAttr.length;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mFileAttr[position];
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View tag = convertView;
if(tag == null)
{
tag = LayoutInflater.from(mContext).inflate(R.layout.adapter, null);
}
ImageView btn = (ImageView)tag.findViewById(R.id.imageView1);
TextView tv = (TextView)tag.findViewById(R.id.textView1);
TextView tvAttr = (TextView)tag.findViewById(R.id.tvFileMsg);
switch(mFileAttr[position].getFileType())
{
case AttrDefine.DIC:
btn.setImageResource(R.drawable.dic);
break;
case AttrDefine.AUD:
btn.setImageResource(R.drawable.audio);
break;
case AttrDefine.TXT:
btn.setImageResource(R.drawable.text);
break;
case AttrDefine.VID:
btn.setImageResource(R.drawable.video);
break;
case AttrDefine.PIC:
btn.setImageResource(R.drawable.pic);
break;
case AttrDefine.UNKNOW:
btn.setImageResource(R.drawable.unknow);
break;
// default:
// btn.setImageResource(R.drawable.ic_launcher);
}
tv.setText(mFileAttr[position].getFileName());
File file = new File(A_FileBrowserActivity.mCurPath + "/" + mFileAttr[position].getFileName());
if(file != null)
{
long length = file.length();
length /=1000;
long updataTime = file.lastModified();
updataTime /= 1000; //ms 单位
updataTime /= (3600*24); //换算成天
long iyear = updataTime / 365;
long inext = updataTime - iyear * 365;
long imonth = inext/30;
long iday = inext - 30 * imonth;
iyear += this.S_YEAR;
tvAttr.setText(String.valueOf(length) + " kB\n " + String.valueOf(iyear) + "."+String.valueOf(imonth) + "." + String.valueOf(iday) );
}
return tag;
}
}
这一块其实大家都应该比较熟了,不再赘述,但是我们的文件信息里面有一个最后修改的时间,这个直接通过File的lastModified方法,返回的是一个相对于1970年1月1号的 一个 long型长整数,而且是ms级的,所以我们进行了一下转换,这里关于闰年没有进行考虑,只是随便简单算了一下,存在不足,有兴趣的童鞋可以去实现一下,不是很难的,还有这里我对几种常见的文件的图标进行了分类显示,这个也很容易做到,不再赘述,这一篇就到这吧,下一篇我们继续,不然一篇太长了吧,你我看了都累!-。-
浙公网安备 33010602011771号