android項目源碼解析03——vudroid閱讀器源碼解析01:主介面

來源:互聯網
上載者:User

        vudroid是一款能讀PDF和djvu兩種格式的閱讀器,其特點是能夠跳頁、全屏閱讀、能夠一次兩頁連續緩衝、能自由進行頁面的縮放、能記憶閱讀位置、劃屏翻頁流暢。其缺點是當檔案大時,渲染速度較慢,偶爾會退出。

        在分析vudroid源碼的過程中,我們將其分為三個部分:

        1)操作主介面(選擇檔案、瀏覽閱讀曆史部分)

        2)閱讀介面(涉及閱讀時的操作、事件處理)

        3)源檔案解析部分(主要是讀取PDF和djvu檔案部分,該部分涉及對相關檔案的格式解析)

1、主介面

        vudroid的主介面 比較簡單,主要包括一個檔案瀏覽介面和一個瀏覽閱讀曆史介面,使用一個tabHost來實現 ,其介面如下:

        browse介面瀏覽sdcard檔案夾,顯示其中的檔案目錄,對於檔案只顯示pdf、djvu、djv三種格式檔案。而recent則顯示最近瀏覽過的檔案清單。

        這一部分的實現是比較簡單的,主要包括了3個檔案:

1、MainBrowserActivity

我們先來看看MainBrowserActivity.java的源碼:

public class MainBrowserActivity extends BaseBrowserActivity{    private final static HashMap<String, Class<? extends Activity>> extensionToActivity = new HashMap<String, Class<? extends Activity>>();    static    {        extensionToActivity.put("pdf", PdfViewerActivity.class);        extensionToActivity.put("djvu", DjvuViewerActivity.class);        extensionToActivity.put("djv", DjvuViewerActivity.class);    }    @Override    protected FileFilter createFileFilter()    {        return new FileFilter()        {            public boolean accept(File pathname)            {                for (String s : extensionToActivity.keySet())                {                    if (pathname.getName().endsWith("." + s)) return true;                }                return pathname.isDirectory();            }        };    }    @Override    protected void showDocument(Uri uri)    {        final Intent intent = new Intent(Intent.ACTION_VIEW, uri);        String uriString = uri.toString();        String extension = uriString.substring(uriString.lastIndexOf('.') + 1);        intent.setClass(this, extensionToActivity.get(extension));        startActivity(intent);    }}

        這裡將所有與介面相關的東西都留給BaseBrowserActivity.java去做了。MainBrowserActivity只負責判斷可以閱讀類型的檔案,並轉到相關的處理處理類去處理。MainBrowserActivity重載了createFileFilter函數,用於建立一個檔案篩選器。這實際上是一個解耦合的過程,後續需要添加其他格式的檔案,如txt,則只需修改createFileFilter函數即可,而沒有必要動BaseBrowserActivity中的代碼。

2、BaseBrowserActivity

       對於BaseBrowserActivity檔案,其實可以猜到它所完成的功能:產生兩個listview去填充tabHost。於是看它的oncreate函數:

 @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.browser);        viewerPreferences = new ViewerPreferences(this);        final ListView browseList = initBrowserListView();        final ListView recentListView = initRecentListView();        TabHost tabHost = (TabHost) findViewById(R.id.browserTabHost);        tabHost.setup();        tabHost.addTab(tabHost.newTabSpec("Browse").setIndicator("Browse").setContent(new TabHost.TabContentFactory()        {            public View createTabContent(String s)            {                return browseList;            }        }));        tabHost.addTab(tabHost.newTabSpec("Recent").setIndicator("Recent").setContent(new TabHost.TabContentFactory()        {            public View createTabContent(String s)            {                return recentListView;            }        }));    }

       這裡對於 tabHost的兩個tab:第一個browse,需要顯示當前檔案目錄,點擊檔案夾時顯示下一個檔案夾目錄,而點擊檔案時則轉到瀏覽該檔案的activity;而第二個recent,則只需要做到點擊檔案時,轉到瀏覽該檔案的activity即可。於是我們可以看到,這兩個tab中listview的setOnItemClickListener是有區別的。

        對於browse:

private ListView initBrowserListView()    {        final ListView listView = new ListView(this);        adapter = new BrowserAdapter(this, filter);        listView.setAdapter(adapter);        listView.setOnItemClickListener(onItemClickListener);        listView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));        return listView;    }
private final AdapterView.OnItemClickListener onItemClickListener = new AdapterView.OnItemClickListener()    {        @SuppressWarnings({"unchecked"})        public void onItemClick(AdapterView<?> adapterView, View view, int i, long l)        {            final File file = ((AdapterView<BrowserAdapter>)adapterView).getAdapter().getItem(i);            if (file.isDirectory())            {                setCurrentDir(file);            }            else            {                showDocument(file);            }        }    };

而對於recent:

private ListView initRecentListView()    {        ListView listView = new ListView(this);        recentAdapter = new UriBrowserAdapter();        listView.setAdapter(recentAdapter);        listView.setOnItemClickListener(new AdapterView.OnItemClickListener()        {            @SuppressWarnings({"unchecked"})            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l)            {                showDocument(((AdapterView<UriBrowserAdapter>) adapterView).getAdapter().getItem(i));            }        });        listView.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));        return listView;    }

從源碼可以看出,這兩者的區別是顯而易見的。

3、ViewerPreferences

ViewerPreferences檔案主要是利用SharedPreferences儲存了兩個參數:是否全屏(FULL_SCREEN)、最近瀏覽檔案清單。

對於最近瀏覽檔案,其代碼為:

public void addRecent(Uri uri)    {        SharedPreferences.Editor editor = sharedPreferences.edit();        editor.putString("recent:" + uri.toString(), uri.toString() + "\n" + System.currentTimeMillis());        editor.commit();    }    public List<Uri> getRecent()    {        TreeMap<Long, Uri> treeMap = new TreeMap<Long, Uri>();        for (String key : sharedPreferences.getAll().keySet())        {            if (key.startsWith("recent"))            {                String uriPlusDate = sharedPreferences.getString(key, null);                String[] uriThenDate = uriPlusDate.split("\n");                treeMap.put(Long.parseLong(uriThenDate.length > 1 ? uriThenDate[1] : "0"), Uri.parse(uriThenDate[0]));            }        }        ArrayList<Uri> list = new ArrayList<Uri>(treeMap.values());        Collections.reverse(list);        return list;    }

4、adapter

項目中用到的兩個Adapter都是重載過的:BrowserAdapter和UriBrowserAdapter。

Adapter的作用主要是串連view和dataset。其中有一個比較重要的函數是getView,每個資料集的一條資料會產生一個view,該view就是通過該函數得來的。因此如果你如果要讓一個view顯示自己的資料,就必須重載該函數。

 public View getView(int i, View view, ViewGroup viewGroup)    {        final View browserItem = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.browseritem, viewGroup, false);        final ImageView imageView = (ImageView) browserItem.findViewById(R.id.browserItemIcon);        final Uri uri = uris.get(i);        final TextView textView = (TextView) browserItem.findViewById(R.id.browserItemText);        textView.setText(uri.getLastPathSegment());        imageView.setImageResource(R.drawable.book);        return browserItem;    }

另外,Adapter的資料集在發生變化時,需要通知view去改變,是通過notifyDataSetInvalidated()函數完成的。

public void setUris(List<Uri> uris)    {        this.uris = uris;        notifyDataSetInvalidated();    }

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.