android项目源码解析03——vudroid阅读器源码解析01:主界面

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(); }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值