安卓文件管理器-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);
        }
        ...
    }

  這裏寫圖片描述

  以上就是我的項目的文件結構。


以上是我覺得要寫出來與大家學習的部分,其實文件管理器實現不難,多的是細節的處理,用戶體驗和優化得做好。最後來一張最終效果圖:
  

這裏寫圖片描述

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