安卓文件管理器-GridView实现

  前段时间做了个九宫格文件管理器(GridView实现,1920*1080分辨率,定制Android,目前只在MTK和MSTAR平台上测试及完善过),由于此工程为公司项目中的子项目,代码就不公开了(不过,实现不难,以下只提供主要代码处理和实现考虑情况)
  

  • /storage为根路径

      这里写图片描述

  • 静默安装应用(过程中会有类ProgressBar滚动直到完成操作或操作失败。静默安装过程放在线程中以防止UI卡顿或者因为权限等原因造成ANR使进程被Kill(原生安卓只有在极端情况下才会kill进程,相关源码:ActivityManagerService.java中管理Activity的代码))

      这里写图片描述
      

  • 静默卸载应用(同上)

      这里写图片描述
      
    这里写图片描述

      
      以上仅供参考学习!其实文件管理器实现起来很简单,只不过过多的细节需要进行考虑而已①。还是得一边做一边在脑海中与原生的文件管理器模拟对比,逐渐完善。
      ①细节包括:
        1. 文件管理器中安装应用后,返回到文件管理器时焦点位置是否要记录还原,如果不还原文件过多时可能要翻好多下才能找到安装的apk文件。
        2.在正在使用的存储介质拔出时,提示并只能退出。提示控件对话框(以下叫dialog)截获onKeyDown事件致使点一次返回响应两次返回操作的问题:先dialog消失,接着Activity响应back事件,也就是事件冲突和截获,可以了解一下onKeyDown返回值代表的意思。而真实的路径已经不存在,所以即使按返回,dialog要消失且程序要有“待机”界面或不友好点直接退出。
        3.文件或文件夹可能会有权限问题要处理,在清单文件AndroidManifest.xml中配置android:sharedUserId=”android.uid.system”让应用程序成为系统应用,但最好的做法还是区分文件和文件夹进行相同的提示,但给予不同的操作。
        其实,一分析,有很多的…还是要以用户的角度去做东西。
      
      好了,直接上代码,在这里只放上写的Demo的Adaper部分供大家学习:
      
    BaseAdapter.java


public class GridAdapter extends BaseAdapter {
    private LayoutInflater inflater;
    private Bitmap directory, file_notinstall, file_hasinstall,backBitmap;
    private ArrayList<String> names = null;
    private ArrayList<String> paths = null;
    private ArrayList<String> states = null;
    public Context getmContext() {
        return mContext;
    }

    public void setmContext(Context mContext) {
        this.mContext = mContext;
    }

    public ArrayList<String> getNames() {
        return names;
    }

    public void setNames(ArrayList<String> names) {
        this.names = names;
    }

    public ArrayList<String> getPaths() {
        return paths;
    }

    public void setPaths(ArrayList<String> paths) {
        this.paths = paths;
    }

    public ArrayList<String> getStates() {
        return states;
    }

    public void setStates(ArrayList<String> states) {
        this.states = states;
    }

    public GridAdapter(Context context, ArrayList<String> name,
            ArrayList<String> path, ArrayList<String> state) {
        names = name;
        paths = path;
        states = state;
        if (this.mContext == null)
            this.mContext = context;
        BitmapFactory.Options opts = new BitmapFactory.Options();
        //缩放比例,缩放比为原图的1/n。
        opts.inSampleSize = 1;
        //每个像素占用2byte内存(565没有透明度属性),默认ARGB_8888一个像素4byte
        opts.inPreferredConfig = Bitmap.Config.RGB_565;
        //要真正做到大数量的列表,可以采用分页式的数据显示,或者使用LruCache缓存图片
        //(分页的原理也就是只显示和加载当前屏幕中显示到的数据,即滑动事件中监听并对边缘的判断和处理),

        //其实这里可以不用每个都判断是否为空,
        //而是这四种图片之一拿出来判断即可,因为它们都是同时初始化和同时释放资源的,且不是多线程运行。
        if (directory == null)

            directory = BitmapFactory.decodeResource(context.getResources(),
                    R.drawable.directory, opts);
        if (file_notinstall == null)
            file_notinstall = BitmapFactory.decodeResource(
                    context.getResources(), R.drawable.file_nodownload, opts);
        if (file_hasinstall == null)
            file_hasinstall = BitmapFactory.decodeResource(
                    context.getResources(), R.drawable.filehasdownload, opts);
        if (backBitmap == null)
            backBitmap = BitmapFactory.decodeResource(context.getResources(),
                    R.drawable.back, opts);
        if (inflater == null)
            inflater = LayoutInflater.from(context);
    }

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

    @Override
    public Object getItem(int position) {
        return names.get(position);
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (null == convertView) {
            convertView = inflater.inflate(R.layout.file, null);
            holder = new ViewHolder();
            holder.text = (TextView) convertView.findViewById(R.id.ItemText);
            holder.image = (ImageView) convertView.findViewById(R.id.ItemImage);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        File f = new File(paths.get(position).toString());
        if (names.get(position).equals("@HOME")) {//保留
            holder.text.setText("/");
            holder.image.setImageBitmap(directory);
        } else if (names.get(position).equals("@BACK")) {//返回上一页
            holder.text.setText("..");
            holder.image.setImageBitmap(backBitmap);
        } else {
            holder.text.setText(f.getName());
            if (f.isDirectory()) {
                holder.image.setImageBitmap(directory);
            } else if (f.isFile()) {
                if (states.get(position).equals(KeyStringConst.APK_HASINSTALL)) {
                    holder.image.setImageBitmap(file_hasinstall);
                } else if (states.get(position).equals(
                        KeyStringConst.APK_NOINSTALL)) {
                    holder.image.setImageBitmap(file_notinstall);
                }
            } else {
                System.out.println(f.getName());
            }
        }
        return convertView;
    }
    //缓存每个item的模版类
    private class ViewHolder {
        private TextView text;
        private ImageView image;
    }

    private Bitmap small(Bitmap map, float num) {
        Matrix matrix = new Matrix();
        matrix.postScale(num, num);
        return Bitmap.createBitmap(map, 0, 0, map.getWidth(), map.getHeight(),
                matrix, true);
    }
}

  
  如上Adapter部分的代码所示,图片的inflate只产生一次。而在Activity中需要更新界面时代码如下:
  

    private void showFileDir(String path) {
    ...
    if (adapter != null) {//避免多次new GridAdapter(),而直接修改参数并通过adapter适配界面。
    //而先判断不为空,因为大多情况下adapter都不为空,如果是if-else if-...-else结构,主体部分放在靠前的位置判断,
    //能够省去不必要的判断。虽然这对于程序执行而言没有明显改善,但要是从机器语言执行顺序角度思考这绝对是好的习惯。
            adapter.setNames(names);
            adapter.setPaths(paths);
            adapter.setStates(states);
            adapter.notifyDataSetChanged();//Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.

        } else {
            adapter = new GridAdapter(getApplicationContext(), names, paths,
                    states);
            gridView.setAdapter(adapter);
        }
        ...
    }

  这里写图片描述

  以上就是我的项目的文件结构。


以上是我觉得要写出来与大家学习的部分,其实文件管理器实现不难,多的是细节的处理,用户体验和优化得做好。最后来一张最终效果图:
  

这里写图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章