毕业实训报告
课题名称: android资源管理器
专 业: 软件设计(游戏开发方向)
班 级:
学 号:
学生姓名:
指导教师:
年 月 日
摘 要
相信大家对Android的发展历史多少都有一些了解,Android曾经是一家创立于旧金山的公司的名字,该公司于2005年8月份被Google收购,并从此踏上了飞速发展的道路。经过这几年的发展,它已经发展成了一个平台、一个生态体系。现在Android在移动领域已经得到了广泛的应用。根据Google于2011年6月份公布的数字,现在每天激活的Android设备高达50万台,比5月份的数据增加了10万台,Google还透露目前已经与36家OEM厂商和215家运营商合作共激活了超过1亿台Android设备。
本文的软件开发环境采用了Eclipse3.4 + Android SDK集成环境,编程语言采用了Java。
关键词: Activity; Fragment;Service
目 录
摘 要IIII
第1章 项目分析11
1.1 问题描述11
1.2技术分析11
1.2.1 Android四大组件11
1.2.2用户界面22
1.2.3 Activity3
1.2.4 Fragment4
1.2.5 SQLite数据库55
1.3工程进度计划66
第2章 系统需求分析77
2.1系统功能需求分析77
2.1.1文件系统的浏览77
2.1.2文件及文件夹得操作99
2.1.3文件系统安全管理1010
2.2 系统开发需求1010
2.2.1Android资源管理器的开发平台1111
2.2.2Android开发框架1111
2.3操作系统及所需软件需求1515
2.3.1 Android开发环境及变量配置1616
2.3.2 安装配置JDK616JDK616JDK616
2.3.3 安装配置SDK18SDK18SDK18
2.3.4 Eclipse的设置1818
2.3.5 Android版本配置1818
2.4系统非功能性需求1818
第3章 系统总体设计1919
3.1 基本框架与布局1919
3.1.1主界面ListView的实现1919
3.1.2 ListView监听事件2525
3.2 帮助与提示2727
3.2.1 帮助与提示的原理与实现2727
3.2.2 文件的读取2929
3.2.3帮助与提示功能实现时遇到的问题及解决3030
3.3 文件打开的实现3131
3.3.1 判断文件类型,分析打开方式3131
3.3.2 文件夹的打开3131
3.3.3 非文件夹类型文件的打开3333
3.3.4 效果图示例示例:3838
3.3.5 在此功能实现过程中遇到的问题示例:3838
3.4 文件的复制,粘贴3939
3.4.2 此功能中遇到的问题4444
第4章 结束语4545
第1章 项目分析
基于Android手机的日益蓬勃发展,各种技术断更新,智能机的大众化走向,越来越多的繁琐的文件出现在我们的手机上。因此,我们想要做一个Android资源管理系统来处理手机上的文件,让用户更好的使用手机。
1.1 问题描述
1.文件的各种操作功能的实现所遇到的问题
(1)文件(文件夹)的复制与粘贴(涉及IO流的操作)实现不了。
(2)文件(文件夹)的新建功能,目录的新建一直有问题,不能达到预期的目标。
(3)文件(文件夹)的搜索功能,关于搜索我们一直想实现搜索提示但是没有实现。
(4)各种功能的使用,权限不够问题、对文件夹进行操作时,会弹出警告信号,甚至退出程序。
(5)文件夹的复制于文件的复制问题,只能实现文件的操作,不能对文件夹进行操作
课题的研究总是伴随着问题的出现,问题总是要解决的,我们首先自己多多的实验自己的想法,通过各种发放解决出现的问题,多方查阅资料,观看视频,并咨询指导老师,从而解决出现的问题。
1.2技术分析
一句话概括Android应用:基于Android系统的软件开发,语言基础是java语言,通过控件的设置以及方法调用,实现一系列的功能,目前,Android系统的手机十分的火爆,因此我们准备做一个基于Android手机的资源管理器。
1.2.1 Android四大组件
Android系统有四个重要的组件,分别是Activity、ServiceBroadcastReceiver和ContentProvider。
Activity是Android程序的曾宪曾,显示可视化的用户界面,并接受与用户交互所产生的界面事件,与窗体的概念非常相似。Android一般启动程序后会呈现一个Activity,用于提示用户程序已经正常启动。Activity在界面的表现形式一般是全屏窗体,也可以是非全屏悬浮窗体或对话框。
Service一般用于没有用户界面,但是需要长时间在后台运行的应用。例如,在播放MP3音乐时,使用Service播放MP3音乐,可以在关闭播放器界面的情况下长时间的播放MP3音乐,并通过对外公开service的通信接口,控制MP3音乐的播放启动、暂停和停止。
BroadcastReceiver是用来接收并响应广播消息的组件。大部分广播消息是由系统产生的,例如失去改变、电量低或者语言选项改变等,但应用程序也可以产生广播消息,例如数据下载完毕等。BroadcastReceiver不包含任何用户界面,但是可以通过启动Activity或者Notification通知用户接受到重要的消息。Notification能够通过多种方法提示用户,包括闪动背景灯、震动设备、发出声音或在状态栏上防止一个持久的图标等。
ContentProvider是Android系统提供的一种标准的数据共享机制,应用程序可以通过ContentProvider访问其他的应用程序的私有数据。私有数据可以是存储在文件系统中的文件,也可以是SQLite数据库中的数据。Android系统内部也提供一些内置的ContentProvider,能够用为应用程序提供重要的数据信息,例如联系人的信息和通话记录等。
1.2.2用户界面
Android系统的界面空间分为定制控件。定制空间是用户独立开发的空间,或者通过继承并修改系统空间后所产生的新空间,能够提供特殊的功能和显示需求。系统控件是Android系统中已经封装好的界面控件,而在代码中动态修改需要更新状态的界面元素。当然,用户也可以将所有的界面元素,无论在程序运行后是否需要修改其内容,都放在代码中进行定义和声明。很明显这不是一种良好的界面设计模式,会给后期界面修改带来不必要的麻烦,是应用程序开发过程中最常见的功能控件。系统控件更有利于进行快速开发,同事能够使Android应用程序的界面保持一定的一致性。
常见的系统控件包括TextView、EditView、Button、ImageButton、CheckButton、Spinner、ListView和Tablehost。
界面布局(layout)是用户界面结构的描述,定义界面中所有的元素、结构和相互关系。一般生命Android程序的界面布局有两种方法,第一种是使用XML文件描述界面的布局,另一种是在程序运行时动态添加或修改界面布局。
Android系统在生命界面布局上提供了很好的灵活性,用户既可以独立使用任何一种声明布局的方式,也可以同时使用两种方式。一般情况下,使用XML文件来描述用户界的基本元素,而在代码中动态修改需要更新状态的界面元素。当然,用户也可以将所有的界面元素,无论在程序运行后是否需要修改其内容,都放在代码中进行定义和声明。很明显这不是一种良好的界面设计模式,会给后期界面修改带来不必要的麻烦,而且界面较多时,程序代码也会显示凌乱不堪。
使用XML文件声明界面布局,能够更多地将程序的表现层和控制层分离,在修改界面时将不再需要更改程序的源代码。
界面布局的种类:
(1).线性布局:线性布局(LinearLayout)是一种重要的界面布局,也是经常使用的界面布局。在线性布局中,所有子元素都在垂直或水平方向按照顺序在界面上排序。
(2).框架布局: 框架布局(FrameLayout)是最简单的界面布局,用来存放一个元素的空白控件,且子元素的位置不能够制定的,只能够放置在空白空间的左上角。
(3) .表格布局:(TableLayout)也是一种常用的界面布局,它将屏幕划分为表格,通过制定行和列可以将界面元素添加到表格中。
(4).相对布局:(RelativeLayout)是一种非常灵活的布局方式,能够通过指定界面元素与其他元素的相对位置关系,确定界面中所有元素的布局为止。
(5).绝对布局:(AbsoluteLayout)能通过指定界面元素的坐标文职,来确定用户界面的整体布局。
1.2.3 Activity
Android中的一个Activity就是一个界面,比如说手机拨号界面,通讯录界面等都是活动,在应用程序中,可以有一个或多个活动,但是如果新建一个活动,必须要在AndroidMainfest.xml中声明。
创建一个Activity需要注意的要点:
一个Activity就是一个类,并且这个类要继承Activity;
需要复写oncreate()方法
每一个Activity都是需要在android Mainfest.Xml文件中进行配置
为Activity添加必要的控件
Activity 的生命周期
在Android开发中,Activity是非常重要的。Activity主要负责创建和显示窗口,也可以把一个Activity理解成一个显示的屏幕;在Android的应用中不是仅有一个Activity,而是由很多个Activity存在。因其重要性,开发Android务必熟悉Activity生命周期,参照图1.1。
onCreateView:Activity初次创建时被调用,一般在这里创建view,初始化布局信息,将数据绑定到list以及设置监听器等。如果Activity首次创建,本方法将会调用onStart();如果是停止后重新显示,则将调用onRestart()。
onStart:当Activity对用户即将课件的时候被调用onResume()。
onRestart:当Activity停止后重新显示的时候被调用,然后调用onStart()。
onPause:当系统要启动一个其他的Activity时调用(其他的Activity显示之前),这个方法使用来停止动画和其他占用CPU资源的事情,所以这这里应该保存那些持久数据,这些数据可以在onResume()方法中读出。
onStop:当另一个Activity恢复并遮盖住当前Activity,导致其对用户不再可见时调用,一个新的Activity启动,其他Activity重新回到前景与用户交互时会重新调用onResume(),如果Activity将退出则调用哦你D额story()。
onDestory:在当前Activity被销毁之前所调用的最后一个方法,当进程 终止前调用。
图:1.1生命周期
1.2.4 Fragment
Fragment的主要目的在大屏幕设备上实现灵活的、动态的界面设计。例如,在Android的平板电脑上,因为屏幕有更多的空间来配置更多的组件,并且这些组件之间还会产生一定的数据交互。
Fragment支持这种设计理论,开发人员不需要管理复杂的试图结构变化,而且把这些动态的管理交给Fragment和回退堆栈(back stack)完成,在进行界面设计时,只需要将界面布局按照功能和取于划分为不同的模块,每个模块设计成一个Fragment即可。
Fragment具有和Activity类似的生命周期,但是比Activity支持更多的事件回调函数。Fragment生命周期中回调函数,以及之间的调用顺序可参照图1.2。
创建Fragment
销毁Fragment
onAttach()
onDetach()
onCreate()
onDistroyView()
onCreateView()
通过回退堆栈
onDestroyView()
onActivityCreateView()
onStart()
onStop()
onResume()
onPause()
Fragment处于活动状态
图1.2状态图
1.2.5 SQLite数据库
SQLite是一个2000年D.Richard Hipp发布的开源嵌入式关系数据库。自从出现商业应用程序依赖,数据库就一直是应用程序的主要组成部分,数据库的管理系统也比较庞大和复杂,且会占用较多的系统资源。随着嵌入式的应用程序大量的出现。一种新型的轻量级数据库SQLite也随之产生。SQLite数据库比传统的数据库更加适合用于嵌入式系统,因为它占用资源少,运行高效可靠,可移植性强,并且提供了零配置运行模式。
1.3工程进度计划
表1.1 工程进度计划
项目进度的时间计划
项目进度的具体内容
2013-04-25至2013-05-04
选择项目题目,了解需求,分析研究课题的具体工程计划,具体的分工,以及时间的安排,资料的查找,资源的收集。
2013-05-05至2013-05-15
代码的构想,分析设计,问题的发现与解决功能代码的实现,测试,应用的初步美工
25号05-16至2013-05-24
应用的美工,功能的完善,代码的优化,课题报告的整理
第2章 系统需求分析
类似于PC中的资源管理器,手机文件管理器主要就是要起到手机文件系统与用户之间沟通的桥梁作用,正确的反映文件系统的信息并为用户方便高效地对系统文件的操作管理提供支持。应用的研究目标为针对手机应用开发的特点。研究并设计一款满足手机用户文件系统浏览、文件操作管理、文件删除、文件粘贴、文件复制等需求的手机应用软件,实现内容包括系统的界面设计,与用户之间的交互,内部的操作流程,各个模块之间的协同处理等,并最终成功运行于Android操作系统上。
2.1系统功能需求分析
从用户的使用角度出发,文件管理器的功能包括五个部分:文件浏览、文件操作管理、文件删除、文件粘贴、文件复制。
2.1.1文件系统的浏览
文件管理器启动后,将在主界面上显示应用主目录信息所知路径下的内容,用户也可以随后在使用过程中对主目录信息进行修改和保存。用户可以执行目录的跳转操作,如选择进入当前目录的某一子目录下,或者跳转到当前目录的父目录中,也可以在任意目录下直接快速的跳转到系统指定的主目录下。
目录跳转的过程中要事先对路径的有效性和用户的权限进行判断。能够正确判断当前显示的路径或要跳转到的路径在文件系统的状态,动态监测因文件创建、删除、SD卡的插入、移除等原因而导致的路径变化情况并对界面进行及时的刷新。非管理员用户不能浏览系统关键路径下的内容。以免用户的误操作对系统文件造成破坏。从而导致手机的不能使用。
用户可以设定在目录跳转的过程中是否对历史路径进行保存,如果选择保存,则在浏览的过程中按返回键后应用将跳转到前一个界面且可见位置与跳转前保存一致,以此类推,知道返回至刚进入应用的目录界面状态后退出;如果选择不保存,则在浏览的过程中按返回键直接推出。
另外,作为直接与用户进行交互的主界面,其形式标准也要进行相互的规范。出于方便直观的考虑,主界面采用列表的形式,每一个界面代表文件系统中一个文件夹下内容,列表的每一行代表文件夹下的一个目录项。对于文件夹,出于现实反应速度考虑。以免用户的误操作对系统文件造成破坏。
每一行所显示的信息只包括文件夹图标、文件夹名称等。对于文件,显示的信息包括文件类型图形、文件名称、文件的大小和修改时间等,对应于不同类型的文件,需要有不同的图标与只对应。在一般情况下每一行的左端还是需要一个触发按钮以供用户对该文件方便的选取和应用。如图2.2所示
是 否
返回主界面
图2.2 流程图
2.1.2文件及文件夹得操作
文件管理器除了能够在界面上对文件系统进行正确的显示,还要能够为用户提供各种文件操作的支持。具体操作类型和操作要求如表2.2所示。
表2.2 文件及文件夹操作
操作类型
操作对象
备注
新建
文件夹
用户执行新建操作命后,弹出对话框供用户输入文件件的名字时输入框中默认进行名字的初始化,形式为” new directory”。如果当前目录中已经在同名文件夹,则默认形是为“new directory( 0 )”,若仍存在同名文件夹,在括号内的数字依次递增并继续判断,直到满足文件夹名称位一为止。用户确认后文件夹在当前目录下成功创建。新建的文件夹在当前界面下按排序要求显示。
选取
文件夹/文件
用户可以对一个或多个目录下的文件夹/文件进行单个或多个选取操作。作为下一部文件管理操作的对象
查询
文件夹/文件
用户可以了解文件夹的路径、类型、修改时间、大小等属性信息。
重命名
文件夹/文件
用户可以对单个文件夹/文件重命名,用户可以在弹出的对话框编辑区中输入新的名字并进行确认操作,而对话框默认在编辑区中填充并选择文件夹/文件的名字,特别的,文件只有选择后缀外的其他不分。要保证新修改的名字在当前目录下的唯一性,否则重命名失败,重命名后给出用户提示并保存目录下的按序排列。
复制
文件夹/文件
用户可以对选取完整的文件夹/文件对象执行复制操作,并粘贴纸至目标中。目标目录不能为选取对象中某一文件夹下的子文件夹,不能选取目标目录下的文件夹/文件作为复制操作对象,目标目录下不能存在与选取对象同命名的文件夹/文件。操作执行之前列出已选取的对象,用户确认后执行复制操作,最后给出操作的结果提示并保持目录下的按序排列。
粘贴
文件夹/文件
从复制文件后在后台有存档可以找到文件目录下进行粘贴文件夹/文件。
删除
文件夹/文件
用户可以的选取完毕的文件夹/文件对象执行删除操作,操作执行之前列出已选取的对象,用户确认后执行删除操作,最后给出操作的结果提示并保持目录下的按序排列。用户可以指定删除操作的执行方式,既是否删除非空文件夹,如果选否,则选取文件的非空文件夹删除失败。
搜索
文件夹/文件
用户可以指定关键字并递归搜索当前目录下名称包含所给关键字的所有操作文件夹/文件,将结果以列表的形式显示。文件管理器还需要提供其它应用搜索操作的接口以达到目的。
2.1.3文件系统安全管理
文针对当前各种恶意软件的威胁和用户数据保护的需求,文件管理器还需要包含对文件系统安全管理的功能,能够实时的检测文件系统中各种文件基本操作信息,包括文件打开、读操作、写操作、文件关闭等,并把相应的进程名和文件名以日志的方式记录下来,提供给用户查询。作为文件管理器的高级功能,默认于系统启动后在后台保持运行状态,用户可以在文件管理器使用的过程中选择停止或重新启用该项功能,对信息的持久化要考虑到用户手机应用的特殊性。
2.2 系统开发需求
Android的应用,开发采用了Java语言,所以它的学习曲线相对比较平缓。对于那些有一些编程语言,如C/C++/Java等,训练的学生,都可以考虑学习Android应用开发。当然,如果处于一个没落的行业,个人再努力,可能都赶不上整个行业坠落的速度。
如果你希望从事Android游戏开发,那么,最好能在高数、离散数学甚至计算机图形学等方面有比较扎实的基础。如果后续想往底层开发如系统移植、驱动开发等方向发展,或者为了更好地理解Android 应用架构体系,那么,具备一定的操作系统知识是必要的当然并不需要你对操作系统有多精通,而是对其基本原理有一定了解即可。系统中的应用软件依赖于不同的硬件平台,不同的手机型号又对应着不同的功能需求同事也要注意到,同一种软件的主体功能还是相同的,知识某些方法少有差异,如何有效的管理众多的版本代码同事提高软件的开发效率。
2.2.1Android资源管理器的开发平台
文本Eclipse: Eclipse是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,附带了一个标准的插件集,包括 Java 开发工具(Java Development Tools,JDT)。Eclipse是一个开放源代码的软件开发项目,专注于为高度集成的工具开发提供一个全功能的、具有商业品质的工业平台。
它主要由Eclipse项目、Eclipse工具项目和、Eclipse技术项目三个项目组成,具体包括四个部分组成——Eclipse Platform、JDT、CDT和PDE。JDT支持Java开发、CDT支持C开发、PDE用来支持插件开发,Eclipse Platform则是一个开放的可扩展IDE,提供了一个通用的开发平台。它提供建造块和构造并运行集成软件开发工具的基础。Eclipse Platform允许工具建造者独立开发与他人工具无缝集成的工具从而无须分辨一个工具功能在哪里结束,而另一个工具功能在哪里开始。
2.2.2Android开发框架
下面图2.2是Android的体系架构图,自上而下分别为应用层、应用框架、类库和Alvik运行时环境以及Linux内核。
图2.2 Android的体系架构图
一般来说,我们想从事Android开发,可以从应用开发作为切入点,逐渐熟悉其整个体系,并慢慢往其底层渗,从而能做到软硬兼备,Android系统开发班的课程设置就充分考虑到了这一点,既涉到应用开发的透彻掌握,又帮助大家在系统开发层面上做好充分的准备。而从学习的路线图上来说,先熟悉Java SE编程,能比较熟练的使用Java语言进行编程,熟悉Java语言语法特点,熟悉Java IO、Java线程、网络编程、XML处理等。另外,因为很多的Android应用在运行时都需要去访问网站服务器,因此,熟悉一种网络编程语言也是必要的。
无论是从开发班的课程设置就充分考虑到了这一点,既涉到应用开发的透彻掌握,又帮助大家在系统开发层面上做好充分的准备。而从学习的路线图上来学习的方便性还是市场占有情况来说使用JSP/Servlet都是不二的选择,另外,在这个阶段也顺便学习一下SQL语法和熟悉一种SQL数据库,以方便后续Android开发中进行SQLite数据库开发。学习完这些课程后,就可以开始进行Android的应用开发的学习,例如Android中的UI组件、基本组件、数据存储、传感器、图形图像处理、多媒体处理、游戏开发等。
Android包含一套C/C++库,Android系统的各式组件都在使用。这些功能通过Android应用框架暴露给开发人员。Android的核心类库提供Java类库所提供的绝大部分功能。每个Android应用都运行在自己的进程上,享有Dalvik虚拟机为它分配的专有实例。为了支持多个虚拟机在同一个设备上高效运行,Dalvik被改写过。 Dalvik虚拟机执行的是Dalvik格式的可执行文件(.dex)该格式经过优化,以降低内存耗用到最低。Java编译器将Java源文件为class文件,class文件又被内置的dx工具转化为dex格式文件,这种文件在Dalvik虚拟机上注册并运行。在一些底层功能——比如线程和低内存管理方面,Dalvik虚拟机是依赖Linux内核的。
为了更好地进行应用编程,可以有选择的对其Lib类库进行分析,以加深对其工作机制的理解。再往下,就是操作系统层级了,这里应该要对Linux操作系统进行学习,熟悉其内核和运行原理,熟悉ARM体系架构以及常用指令并熟悉驱动的编写方式,掌握其移植方法等。Android的核心应用程序就是依赖框架层次API开发的,程序员们可以充分使用这些API。应用架构设计的初衷是,简化组件复用机制,任何应用都能发布自己的功能,这些功能又可以被任何其他应用使用,当然要受来自框架的强制安全规范的约束。
每个Android应用程序都存在于它自己的世界之中,默认情况下,每个应用程序均运行于它自己的Linux进程中。当应用程序中的任意代码开始执行时,Android启动一个进程而当不再需要此进程而其它应用程序又需要系统资源时,则关闭这个进程。 每个进程都运行于自己的Java虚拟机(VM)中。所以应用程序代码实际上与其它应用程序的代码是隔绝的。 默认情况下,每个应用程序均被赋予一个唯一的Linux用户ID,并加以权限设置,使得应用程序的文件仅对这个用户、这个应用程序可见。当然,也有其它的方法使得这些文件同样能为别的应用程序所访问。
Android应用的构成和工作流程如图2.3:
图2.3 Android的构成
每个Android应用程序都存在于它自己的世界之中,默认情况下,每个应用程序均运行于它自己的Linux进程中。当应用程序中的任意代码开始执行时,Android启动一个进程而当不再需要此进程而其它应用程序又需要系统资源时,则关闭这个进程。每个进程都运行于自己的Java虚拟机(VM)中。所以应用程序代码实际上与其它应用程序的代码是隔绝的。默认情况下,每个应用程序均被赋予一个唯一的Linux用户ID,并加以权限设置,使得应用程序的文件仅对这个用户、这个应用程序可见。当然,也有其它的方法使得这些文件同样能为别的应用程序所访问。
(l)应用程序架构:在应用程序架构内已经具备多种不同的基础组件,在开发应用程序时,就可以直接调用这些组件来使用,可以节省开发应用程序的心力及时间。
(2)Dalvik虚拟机器:在Android平台上所使用Java虚拟机,不是Sim公司的标准Java虚拟机,而是使用Google自主开发的代号为Dalvik的虚拟机,它在保证API方面的兼容的同时,针对移动手机进行了大幅优化,占用资源更小,运行效率更高。
(3)集成的浏览器:集成的浏览器是Android内建的浏览器,是以WebKit的浏览引擎为基础所开发成的。WedKit是一个开源浏览器网页排版引擎,目前使用WebKit引擎的浏览器主要有:Safari、Midori、Epiphany等。配合Android手机的功能,可以在浏览网页时,达到更好的效果,例如:局部性的缩放网页上的资讯、触控式的操作等效果。
(4)优化的绘图能力:在程序里可以用到的绘图功能分为2D与3D两个方面。在2D方面Android提供了一套特有的类库(SGL;而在3D方面则是使用OpenGLES1.0(openGL for Embedded systems)规范的类库。它们是一种非常快的图形引擎,并且支持硬件加速。
(5)SQLite数据库:SQLite提供结构化的数据存取。SQLite是一款轻型的数据库,它的设计目标是嵌入式的,目前已经在很多嵌入式产品中使用了它,它占用的资源非常低。它能够支持Windows/Linux/U nix等主流的操作系统,同时能够跟很多程序语言相结合,比如:php、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL来讲,它的处理速度比它们都快。它无需安装和管理配置,它是一个储存在单一磁盘文件中的完整数据库,体积小只有250KB但支持数据库大小至2TB。它虽然很小巧,但是支持的SQL语句毫不逊色于其它开源数据库。同时它还支持事务功能和并发处理等等。SQLite也是一套开放性的关联式资料库其特点在于轻量性方面的设计结构,更适合在手机上使用。
(6)多媒体的支持能力:主要用于播放媒体文件。这同时包括对音频(如播放MP3或其他音乐文件等)和视频(如播放从网上下载的视频)的支持,并支持“播放URI地址”(Note:URI即是统一资源识别地址)模式—在网络上直接播放的流媒体。另外支持各种通用的静态图像格式,例如:JPG、PNG、GIF等格式。
(7)GSM技术:Global System for Mobile Communications,即全球移动通讯系统,俗称”全球通”,是一种起源于欧洲的移动通信技术标准,是第二代移动通信技术,其开发目的是让全球各地可以共同使用一个移动电话网络标准,让用户使用一部手机就能行遍全球。GSM技术是属于手机硬件方面的展现,。它无需安装和管理配置,它是一个储存在单一磁盘文件中的完整数据库,体积小只有250KB但支持数据库大小至2TB。它虽然很小巧,但是支持的SQL语句毫不逊色于其它开源数据库。默认情况下,每个应用程序均运行于它自己的Linux进程中。当应用程序中的任意代码开始执行时,Android启动一个进程而当不再需要此进程而其它应用程序又需要系统资源时,则关闭这个进程。每个进程都运行于自己的Java虚拟机(VM)中。所以应用程序代码实际上与其它应用程序的代码是隔绝的。默认情况下,每个应用程序均被赋予一个唯一的Linux用户ID,同时它还支持事务功能和并发处理等等也是在开发Android应用程序时可以突出的特点之一。
(8)蓝牙、EDGE、3G及Wi-Fi:蓝牙是一种新型、开放、低成本、短距离的无线连接技术可取代短距离的电缆,实现话音和数据的无线传输。EDGE(Enhanced Data Rate for GSMEvolution),即增强型数据速率GSM演进技术。EDGE是一种从GSM到3G的过渡技术它主要是在GSM系统中采用了一种新的调制方法,即最先进的多时隙操作和SPSK调制技术。由于8PSK可将现有GSM网络采用的GMSK调制技术的信号空间从2扩展到8,从而使每个符号所包含的信息是原来的4倍。Wi-Fi(WirelessFidelity),即无线保真技术,与蓝牙技术一样,是一种起源于欧洲的移动通信技术标准,是第二代移动通信技术,其开发目的是让全球各地可以共同使用一个移动电话网络标准,让用户使用一部手机就能行遍全球。GSM技术是属于手机硬件方面的展现,这些通讯能力也是属于手机硬件方面的展现,也是在开发Android应用程序时可以突出的特点之一。
(9)GPS: Global Positioning System,即全球定位系统,它是一个由覆盖全球的247 颗卫星组成的卫星系统。这个系统可以保证在任意时刻和任何地点都可以同时观测到4颗卫星,以保证卫星可以采集到该观测点的经纬度和高度,以便实现导航、定位、授时等功能。这项技术可以用来引导飞机、船舶、车辆以及个人。这个同样也是属于手机硬体方面的体现也是在开发Android应用程序是可以突出的特点之一
2.3操作系统及所需软件需求
每个应用程序均运行于它自己的Linux进程中。当应用程序中的任意代码开始执行时,Android启动一个进程而当不再需要此进程而其它应用程序又需要系统资源时,则关闭这个进程。每个进程都运行于自己的Java虚拟机(VM)中。所以应用程序代码实际上与其它应用程序的代码是隔绝的。默认情况下,每个应用程序均被赋予一个唯一的Linux用户ID,并加以权限设置,使得应用程序的文件仅对这个用户、这个应用程序可见。当然,也有其它的方法使得这些文件同样能为别的应用程序所访问。新下载好的Android源码,只用配置好编译的环境,在根目录下执行make命令,就可以生成系统镜像,然后由Android模拟器加载并运行,对于实际圣餐中的源码编译来说,系统中的应用软件依赖于不同的硬件平台,不同的手机型号又对应着不同的功能需求同事也要注意到,同一种软件的主体功能还是相同的,知识某些方法少有差异。
编写Android的应用程序,需要一套个人电脑系统。至于操作系统的部份,几个主流操作系统都有支持。支持的操作系统如下,Windows XP 、Vista或Windows 7。
在开始搭建Android的开发环境之前,需要准备的软件包如下,
(2) Eclipse(eclipse-java-galileo-SR2-win32.zip)
(3) Android SDK 1.6(android-sdk-windows-1.6_r1.zip)
(4) Android SDK Setup(android-sdk_r06-windows.zip)
(5) ADT 0.9.7(ADT-0.9.7.zip)
2.3.1 Android开发环境及变量配置
Eclipse设计的美妙之处,在于所有东西都是外链,除了底层的核心以外。这种外设计让Eclipse具备强大扩充性,但更重要的是,此平台提供一个定义明确的机制,让各种外
挂程序共通合作(透过延伸点extension points)与贡献(contributions),因此新功能可以轻易且无缝地加入平台。
2.3.2 安装配置JDK6
下载后安装是下的解压包那就解压到某目录,例如解压到是C:\Java\jdk1.6.0_20:右键点击我的电脑 ->属性 ->高级,点击下面的环境变量,在下面的“系统变量”处选择新建在变量名处输入 JAVA_HOME变量值中输入刚才的目录,比如我的是在目录
C:\Java\jdk1.6.0_20下,效果如图2.4所示,
图2.4进入环境变量
确定后再新建一个变量名为CLASSPATH,变量值
为 %JAVA_HOME%/lib/rt.jar;%JAVA_HOME%/lib/tools.jar ,确定后找到Path的变量,双击或点击编辑,在变量值最前面加上%JAVA_HOME%/tools; 注意里面的是。确定、确定、确定后即可。具体如下图2.5所示,
图 2.5环境变量的设置
接着在“开始->运行”,输入cmd,然后在命令行提示符中输入:java -version,如果能够看到java version “1.6.0_20″信息就表示JDK安装成功。
2.3.3 安装配置SDK
将下载android-sdk-windows-1.6_r1.zip解压缩到C:\android-sdk-windows-1.6_r1目录中。新建一个“系统变量”,在“变量名”中填Android_Home,在“变量值”加填C:\android-sdk-windows-1.6_r1。“编辑”PATH变量,在“变量值”后面加上;%Android_Home%\tools。这样,Android SDK 1.6就安装好了。“开始->运行”,输入cmd,
然后在命令行提示符中输入:android -help,应该能够看到帮助信息:Android SDK 1.6安装成功。
2.3.4 Eclipse的设置
将下载到的Eclipse解压缩到C:\eclipse,然后进入这个文件夹,双击eclipse.exe,启动Eclipse。关联Adnroid SDK菜单“Windows->Preferences”,打开Preferences对话框,点击Android,在右侧的Android Reference中,点SDK Location文本框右侧的Browse?按钮,找到C:\android-sdk-windows-1.6_r1,“确定”。安装ADT菜单“Help -> InstallNew Software?”,打开Install对话框,点击Add?按钮,添加站点,Add Site,,在Name 中填ADT,在Location中填https://dl-ssl.google.com/android/eclipse/。然后,下载安装ADT。第四步,解压Android SDK Setup,下载更新Android SDK 2.0和2.1将下载到android-sdk_r04-windows.zip解压缩到C:\android-sdk-windows,然后进入这个文件夹,双击SDK Setup.exe,启动Android SDK and AVD Manager,选中左侧Settings项,然后在右侧面板选中Force https://? sources to be fetched using http://,然后选择Save & Apply。
2.3.5 Android版本配置
在Eclipse中,Window > Android SDK and AVD Manager,选择左侧Available Package,在右侧Sites,Packages and Archives列表中勾选出SDK Platform Android 2.1, API 7revision 2和SDK Platform Android 2.2, API 8 revision 2,点击界面右下方"Install Selected",开始升级至Android SDK 2.1和Android SDK 2.2。到此,在Windows下的Android2.2开发环境就搭建成功了。
2.4系统非功能性需求
1.文件管理器作为手机基本应用的一部分,需要经常与用户进行交互,其设计细节直接影响用户的感受及工作效率,为了取得较好的效果,开发时需要注意以下几点,文件管理器的整体风格要与其他应用保持一致,合理使用图标等辅助表达方式;合理规划界面布局,优化文件管理操作流程;操作前由用户确认,操作后文用户显示结果,提供应用帮助说明文档。
2.文件管理器赢支持不同的硬件平台上多分辨率显示的情况,在相同的功能需求的前提下,一次开发,多次利用。
3.文化管理器考虑到手机存储资源的相对不足,对文件安全监测的持久化信息进行精简,避免软件运行带来的不利影响。
4.文件管理器的设计应具有可扩展性,尽量提高硬件的无关性,要考虑到后续功能的变更情况,增强软件的适应能力。
5.新下载好的Android源码,只用配置好编译的环境,在根目录下执行make命令,就可以生成系统镜像,然后由Android模拟器加载并运行,对于实际圣餐中的源码编译来说,系统中的应用软件依赖于不同的硬件平台,不同的手机型号又对应着不同的功能需求同事也要注意到,同一种软件的主体功能还是相同的,知识某些方法少有差异,如何有效的管理众多的版本代码同事提高软件的开发效率,是包括文件管理器在内的整个系统开发与编译过程中需要解决的问题。
第3章 系统总体设计
在本章中,将会对本文件管理器的部分功能进行介绍,以下的几个小节中会详细的介绍的我在本应用中承担的部分工作以及实现的功能。其中主要介绍的功能有的布局实现,文件的部分操作,如:文件粘贴、文件复制、帮助与提示界面的实现,文件打开的实现等。
3.1 基本框架与布局
3.1.1主界面ListView的实现
在此程序中可视的基本框架主要有,刚进入应用的帮助与提示对话框,然后就是程序的主界面一个TextView来显示文件当前的地址,然后用一个ListView用列表的形式来显示所有的File,最下面是一个GridView,来显示手机、SD卡、搜索、创建、粘贴、退出这几个功能,而这所得的控件主要是由一个布局文件main.xml提供的,main.xml布局文件如下:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/background">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/mPath"
android:textSize="20sp"
android:singleLine="true"></TextView>
<ListView
android:id="@+id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/mPath"
android:cacheColorHint="#00000000"
android:divider="@drawable/line"
android:layout_marginBottom="70px"></ListView>
<GridView
android:id="@+id/file_gridview_toolbar"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:layout_alignParentBottom="true"></GridView>
</RelativeLayout>
效果图如下:
图 3-1 主界面效果图01 图 3-2 主界面效果图02
控件的选择:由于ListView可以一列表的形式显示一个布局,所以在这里用此控件来作为文件的可视化组件,并且ListView的内容是由一个布局文件list-child.xml实现的,list-child.xml的布局文件如下:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:gravity="left|center"
android:layout_height="38dp">
<ImageView
android:id="@+id/image_list_childs"
android:layout_height="40dip"
android:layout_width="40dip"></ImageView>
<TextView
android:id="@+id/text_list_childs"
android:layout_width="fill_parent"
android:textSize="20sp"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"></TextView>
</LinearLayout>
由于ListView是一个需要有适配器的组件所以要为其创建一个适配器来显示List
View的内容,因此就需要创建一个Adapter适配器FileAdapter让其继承BaseAdapter,然后是重写BaseAdapter中的四个方法:getCount()、getItem()、getItemId()、getView(),并且实现这些方法。其中getCount()的作用就是,这个ListView要显示多少行,而这个行数有事传过来的文件的子File个数Files,所以就要显示files.length行。第二个方法的返回值就是,当前ListView的第几项。第四个方法才是重点,作用就是控制ListView显示的内容,再此方法中首先就要获取一个布局文件并转化为一个View,然后通过为View中的两个控件ImageView和TextView设置内容来让ListView显示出来。
Adapter部分源码:
/**自定义Adapter内部类*/
class FileAdapter extends BaseAdapter{
private Bitmap mBackRoot;private Bitmap mBackUp;private Bitmap mImage;private Bitmap mAudio;private Bitmap mRar;
private Bitmap mVideo;private Bitmap mFolder;private Bitmap mApk;private Bitmap mOthers;private Bitmap mTxt;private Bitmap mWeb;
private Context mContext;private List<String> mFileNameList;private List<String> mFilePathList;
public FileAdapter(Context context,List<String> fileName,List<String> filePath){
mContext = context;
mFileNameList = fileName;
mFilePathList = filePath;
mBackRoot = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.back_to_root);
mBackUp = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.back_to_up);
mImage = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.image);
/****不同文件类型的图片加载代码块****/
}
public int getCount() {
return mFilePathList.size();
}
public Object getItem(int position) {
return mFileNameList.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup viewgroup) {
ViewHolder viewHolder = null;
if (convertView == null) {
viewHolder = new ViewHolder();
LayoutInflater mLI = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = mLI.inflate(R.layout.list_child, null);
viewHolder.mIV = (ImageView)convertView.findViewById(R.id.image_list_childs);
viewHolder.mTV = (TextView)convertView.findViewById(R.id.text_list_childs);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
File mFile = new File(mFilePathList.get(position).toString());
if(mFileNameList.get(position).toString().equals("BacktoRoot")){
viewHolder.mIV.setImageBitmap(mBackRoot);
viewHolder.mTV.setText("返回根目录");
}else if(mFileNameList.get(position).toString().equals("BacktoUp")){
viewHolder.mIV.setImageBitmap(mBackUp);
viewHolder.mTV.setText("返回上一级");
}else if(mFileNameList.get(position).toString().equals("BacktoSearchBefore")){
viewHolder.mIV.setImageBitmap(mBackRoot);
viewHolder.mTV.setText("返回搜索之前目录");
}else{
/***(文件图标设置代码块)***/
}
return convertView;
}
class ViewHolder {
ImageView mIV;
TextView mTV;
}
}
由于文件的类型有很多样如:txt、Pdf、html、chm、mp4、mp3等,所以每种类型的文件也要配上不同的图标这样才便于观看和查找,所需要的文件。而在此程序中每个类型的文件使用的是同一种图标,例如:mp3、wav等音乐格式为一种,mp4、3GP、flv、rmvb等视频格式为一种,gif、jpg、png等图片格式为一种,html等网页格式为一种还有其他的好多的类型。所以在上边的代码中的图片加载区中的代码是对每种类型的图标进行加载的,部分源代码如下:
mAudio = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.audio);
mVideo = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.video);
mApk = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.apk);
mTxt = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.txt);
mOthers = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.others);
mFolder = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.folder);
mRar = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.zip_icon);
mWeb = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.web_browser);
mAudio = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.audio);
mVideo = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.video);
mApk = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.apk);
mTxt = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.txt);
mOthers = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.others);
mFolder = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.folder);
mRar = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.zip_icon);
mWeb = BitmapFactory.decodeResource(mContext.getResources(),
R.drawable.web_browser);
而每种文件图标的设置原理是根据文件的后缀名字来确定的,例如文件的后缀名判断为fileEnds.equals("jpg")||fileEnds.equals("gif")||fileEnds.equals("png")||fileEnds.equals
("jpeg")||fileEnds.equals("bmp"),则应该显示图像类型的图标,而且每一个类型的文件基本都需要判断的,所以在上述代码中的文件图标判断区域的代码应该为,先对文件的名字进行提取,提取方法为:首先用file.getName().lastIndexOf(".")判断出最后一个点“.”出现的位置,因为在此“.”以后的字符串就是文件的扩展名,即文件的类型。因为文件的扩展名不包括“.”,所以file.getName().lastIndexOf(".")返回的Int类型的Index要加1,然后用substring(file.getName().lastIndexOf(".") + 1,file.getName().length())来获取文件的后缀名,并用toLowerCase()方法把后缀名字全部改为小写,之后就根据文件的扩展名来判断文件的类型。例如文件的后缀名字为影音类型end.equals("m4a")||end.equals("mp3")||end.
equals("mid")||end.equals("xmf")||end.equals("ogg")||end.equals("wav")){returngetAudioFileIntent (filePath);},根据判断后的结果来分别显示文件所应该现实的图标,具体的判断方法如下:
String fileName = mFile.getName();
viewHolder.mTV.setText(fileName);
if(mFile.isDirectory()){
viewHolder.mIV.setImageBitmap(mFolder);
}else{
String fileEnds = fileName.substring(fileName.lastIndexOf(".")+1,fileName.length()).toLowerCase();//取出文件后缀名并转成小写
//判断文件类型 选择显示的文件的图标
if(fileEnds.equals("m4a")||fileEnds.equals("mp3")||fileEnds.equals("mid")||fileEnds.equals("xmf")||fileEnds.equals("ogg")||fileEnds.equals("wav")){
viewHolder.mIV.setImageBitmap(mVideo);
}else if(fileEnds.equals("3gp")||fileEnds.equals("mp4")){
viewHolder.mIV.setImageBitmap(mAudio);
}else if(fileEnds.equals("jpg")||fileEnds.equals("gif")||fileEnds.equals("png")||fileEnds.equals("jpeg")||fileEnds.equals("bmp")){
viewHolder.mIV.setImageBitmap(mImage);
}else if(fileEnds.equals("apk")){
viewHolder.mIV.setImageBitmap(mApk);
}else if(fileEnds.equals("txt")){
viewHolder.mIV.setImageBitmap(mTxt);
}else if(fileEnds.equals("zip")||fileEnds.equals("rar")){
viewHolder.mIV.setImageBitmap(mRar);
}else if(fileEnds.equals("html")||fileEnds.equals("htm")||fileEnds.equals("mht")){
viewHolder.mIV.setImageBitmap(mWeb);
}else {
viewHolder.mIV.setImageBitmap(mOthers);
}
}
当适配器中的所有内容都准备完毕后就开始为ListView来进行设置了,只需要把当前文件的所有子文件即Files传递到适配器对象中,然后受用ListView的的setAdapter方法把适配器对象传递进去就可以了。
3.1.2 ListView监听事件
在ListView中有两个监听事件,第一个就是onListItemClick事件,还有一个就是initItemLongClickListener事件。onListItemClick事件的作用就是代开文件或者文件夹,initItemLongClickListener的作用就是打开文件相关操作的对话框如图3-3所示。
onListItemClick事件的功能:当用户点击一个listView中的文件时,程序会判断用户点击的文件在ListView中的位置Position,然后根据Position来判断是哪个File,如果此File是文件夹则直接打开文件夹,然后刷新文件列表。如果是文件则直接调用openFile()方法来打开文件,onListItemClick方法内容如下:
/**列表项点击时的事件监听*/
@Override
protected void onListItemClick(ListView listView, View view, int position, long id){
final File mFile = new File(mFilePaths.get(position));
if(mFile.canRead()){//如果该文件是可读的,我们进去查看文件
if(mFile.isDirectory()){//如果是文件夹,则直接进入该文件夹,查看文件目录
initFileListInfo(mFilePaths.get(position));
}else{//如果是文件,则用相应的打开方式打开
openFile(mFile);
}
}else{//如果该文件不可读,我们给出提示不能访问,防止用户操作系统文件造成系统崩溃等
Toast.makeText(MainActivity.this, "对不起,您的访问权限不足!", Toast.LENGTH_SHORT).show();
}
}
ListView中的另一个点击事件initItemLongClickListener在此应用的主要功能就是调出文件相关操作的对话框,其中对话框中有"复制","重命名","删除","打开"四个选项,效果如图3-3所示。而且在此对话框中也设置了按键监听事件,每个选项都有相应的操作文件的方法。
initItemLongClickListener部分源码如下:
/**长按文件或文件夹时弹出的带ListView效果的功能菜单*/
private void initItemLongClickListener(final File file){
OnClickListener listener = new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog, int item) {//item的值就是从0开始的索引值(从列表的第一项开始)
if(file.canRead()){//注意,所有对文件的操作必须是在该文件可读的情况下才可以,否则报错
if(item == 0){//复制
Toast.makeText(MainActivity.this, "已复制!", Toast.LENGTH_SHORT).show();
isCopy = true;
mCopyFileName = file.getName();
mOldFilePath = mCurrentFilePath+java.io.File.separator+mCopyFileName;
}else if(item == 1){//重命名
initRenameDialog(file);
}else if(item == 2){//删除
initDeleteDialog(file);
}else if(item==3){
openFile(file);
}
}else{
Toast.makeText(MainActivity.this, "对不起,您的访问权限不足!", Toast.LENGTH_SHORT).show();
}
}
};
String[] mMenu = {"复制","重命名","删除","打开"};
new AlertDialog.Builder(MainActivity.this)
.setTitle("请选择操作!")
.setItems(mMenu, listener)
.setPositiveButton("取消",null).show()}
图 3-3 initItemLongClickListener事件对话框
3.2 帮助与提示
3.2.1 帮助与提示的原理与实现
帮助与提示的原理就是利用一个单独的布局在FE文件夹管理器运行行时首先跳出界面对用户进行提示, 帮助与提示的显示原理是利用Dialog的子类AlretDialog来实现创建的的。
在AlretDialog显示时用setTitle(“帮助和关于”)方法,为其设置Dialog标题。用setMessage(String Text)方法为其设置文本内容,而文本的内容是调用getDocument(String fileName)方法,并且把文件的地址作为getDocument()方法的参数传递过去,在getDocument()方法中去读取出文件的内容然后返回到setMessage()中作为Dialog的内容显示出来。然后再用setPositiveButton()方法为其设置确定按钮,而在setPositiveButton(String buttonName,OnClickListener on)方法中有两个参数,第一个参数为PositiveButton按钮的显示内容,第二个参数为PositiveButton的OnClickListener点击监听事件。
在为PositiveButton设置监听事件时由于此PositiveButton使用一次所以在这里的监听事件我用匿名内部类来设置的监听事件,而且由于newPositiveButton不是button的子类所以在此处监听事件设置方法不是用view.View.OnClikListener()来设置监听方法而是用 DialogInterface.OnClickListener()来设置监听方法。
在此Dialog中由于调用时直接用的new方法,新建出来的,而不是在createDialog方法中创建,然后由showDialog(int number)调用显示出来的,所以在AlertDialog的新建方法的最后必须用show()方法来让其调用时就直接显示出来,否则就会运行但是却不显示没反应也看不出来效果。
如下为代码片段:
private void dialogOfHelpAndAbout(){
new AlertDialog.Builder(MainActivity.this)
.setTitle("帮助和关于")//设置Dialog的标题
.setMessage(getDocument("txt/help_about.txt"))//读取本地文件来显示帮助和关于的内容
.setPositiveButton("确定", new //设置确定按钮及确定按钮的按键响应
DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog,int which){
initFileListInfo(mSDCard);
//一开始程序的时候加载手机目录下的文件列
//表 mSDCard为file类型是指SD卡的的路径名称
}
}).show();
}
效果图示例:
图 3-4 帮助与提示对话框 图 3-5 应用的主界面
3.2.2 文件的读取
在程序的文件提示与帮助中getDocument(String mPath)方法的主要作用就是读取本地assets文件夹下的“帮助和关于.txt”的文本中的内容并用一个String字符串返回出去文本中的内容。
在getDocument(String mPath)方法中有一个字符串类型的参数而此参数的作用就是传递过来“帮助和关于.txt”文本在assets文件夹下的地址路径。而在读取“帮助和关于.txt”文本的内容时,使用的安卓系统自带的getAssets().open(mPath)方法来读取assets文件夹下的“帮助和关于.txt”文本。安卓系统自带的getAssets().open(mPath)方法读取后的返回值是一个InputStream类型的输入流对象,然后再用此对象的reader(Byte[] bytes)方法来把文本中的内容读取出来。而在用到此对象的reader(Byte[] bytes)方法时,由于要把文本中的内容读取到一个Byte类型的数组里面,所以数组的大小应该适当,否则就会造成系统资源的浪费。所以在为此数组的大小进行设置时我用的是InputStream对象的available()方法来实现,而此方法的作用就是读取出文件的有效长度,再用此方法的返回值为byte数组设置长度,这样就可以为读取文件时来节约系统资源,提高性能。
如下为代码片段:
/**读取观过程下assets文件夹中的"帮助和关于.txt"文档*/
public String getDocument(String mPath){
// String mPath 传进来文件的地址
String mTxt = null;
try {
InputStream is = MainActivity.this.getAssets().open(mPath);
//安卓自带的getAssets()方法读取 Assets文件夹下的文件内容
byte[] mByte = new byte[is.available()];
//为输入流建立一个缓冲减少文件的读写频率 起到缓冲作用 节约系统资源
//is.available() 有效字节数 有效长度
is.read(mByte); //文件内容读取到byte[] mByte中
mTxt = new String(mByte,"GB2312"); //显示出来时的编码
} catch (IOException e) {
e.printStackTrace();
}
return mTxt;
}
3.2.3帮助与提示功能实现时遇到的问题及解决
1、创建Dialog后没有显示
问题描述:
当我写好了dialogOfHelpAndAbout()方法,在方法中也用了new AlertDialog.Builder()方法创建玩Dialog对话框并且也为其设置好标题、内容、按钮等一系列属性时,我就在程序里面调用了此方法。但是结果却是程序也能正常运行没有报错,但是弹出帮助与提示对话框那个阶段没有了,而且由于我在对话框的点击事件中初始化的程序刚进入时的界面,所以程序就一直是白屏!
问题的解决过程:
我还以为我没有调用所以就去看看程序中,结果发现在onCreate()方法中已经调用。所以我就知道运行了但是没有显示,因此我就在dialogOfHelpAndAbout()方法中用Log.(“debug”,”Dialog”)输出调试了一下,而且程序再次运行时在LogCat中有我用Log输出的内容“Dialog”,所以我就知道了必定是我的创建的问题。然后就检查了一下,发现Dialog方法中的show()方法没有漏写了,至此终于明白还是我的不认真造成了此错误。
文件的读取后发现只要是中文的就出现乱码
问题描述:
我所有的在本地assets文件夹下的“帮助和关于.txt”的文本中的内容,只要是中文,经过读取就会出现乱码。
问题的解决过程:
由于这个问题以前我也曾遇到过,知道是编码格式的不统一造成的,但是却不知道怎么解决,于是就请教了指导老师,问老师这是怎么了.老师就对我说在String创建对象时,new String()方法中可传递两个参数,第一个是第一个可以是Byte[]数组,第二个参数就是字符编码如:UTF-8、GB1312、GBK。。。。。。,因为我只写了一个参数,所以造成编码格式的不统一了,因此就会出现乱码了。最后在老师的指导下我把创建String对象的方法改为了:mTxt = new String(mByte,"GB2312"),这个问题就有顺利的被解决了。
3.3 文件打开的实现
文件打开功能的原理是在此程序中,如果想要打开一个文件的话,要在lisview控件上点击你想要打开的文件,程序会先在openFile()这个方法中判断用户点击的是文件还是文件夹,如果这个文件是文件夹的话,则会调用打开文件夹的方法,如果点击的文件的话,则调用打开文件的方法。
3.3.1 判断文件类型,分析打开方式
当用户点击一个listView中的文件时,程序会判断用户点击的文件在ListView中的位置Position,然后根据Position来判断是哪个File,之后就会调用openFiles()这个方法来把文件File传递过去,当File传递到openFiles(File fiel)的时候,在openFile(File file)方法中,程序会首先判断当前操作的文件file的类型,用file.isDirectory()方法判断传过来的file是不是文件夹。
判断文件代码示例:
/**调用文件的打开方法,根据文件类型判断文件的具体打开方法*/
private void openFiles(File file){
if(file.isDirectory()){
initFileListInfo(file.getPath());
}else{//如果是文件则调用文件的打开方法。
//隐式Intent跳转
Intent openFileIntent = OpenFilePort.openFile(file.getPath());
startActivity(openFileIntent);
}
}
3.3.2 文件夹的打开
如果是文件夹则调用initFileListInfo(file.getPath())方法并把当前文件夹的路径传递过去,然后在initFileListInfo()方法中刷新文件列表。
刷新文件列表方法:
private void initFileListInfo(String filePath){
isAddBackUp = false;
mCurrentFilePath = filePath;
mPath.setText(filePath);
mFileName = new ArrayList<String>();
mFilePaths = new ArrayList<String>();
File mFile = new File(filePath);
File[] mFiles = mFile.listFiles();
//遍历出该文件夹路径下的所有文件/文件夹
if(menuPosition == 1&&!mCurrentFilePath.equals(mRootPath)){
initAddBackUp(filePath,mRootPath);
}else if(menuPosition == 2&&!mCurrentFilePath.equals(mSDCard)){
initAddBackUp(filePath,mSDCard);
}
/*将所有文件信息添加到集合中*/
for(File mCurrentFile:mFiles){
mFileName.add(mCurrentFile.getName());
mFilePaths.add(mCurrentFile.getPath());
}
/*适配数据*/
setListAdapter(new FileAdapter(MainActivity.this,mFileName,mFilePaths));
}
在initFileListInfo()方法中有一个参数,即当前点击的文件,因为当前操作的文件是文件夹才调用此方法,所以传进来的地址就是当前操作的文件夹的地址。因为要显示的文件夹列表就是当前文件夹下的所有子文件,所以mFiles= mFile.listFiles(),然后便利所有的子文件并添加文件的路径和文件的名字用两个ArrayList集合来分别保存。再次方法中还有一个参数isAddBackUp,isAddbackUp=false的意思就是在文件列表的最上方是否添加返回上一层的按钮,而且在这里设为false是为其初始化,在下面会用一个判断方法initAddBackUp(参数一,参数二)来判断此按钮是否应该显示,其中第一个参数为当前的文件夹的地址,即当前现实的所有文件的父文件夹,第二个参数为系统的根目录,然后用equals方法来判断传进来的两个文件地址是否一样,如果一样则不添加“返回根目录”和“返回上一级”,如果不一样即返回值为false则添加“返回根目录”和“返回上一级”。
initAddBackUp()方法如下:
private boolean isAddBackUp = false;
/**根据点击“手机”还是“SD卡”来加“返回根目录”和“返回上一级”*/
private void initAddBackUp(String filePath,String phone_sdcard){
if(!filePath.equals(phone_sdcard)){
/*列表项的第一项设置为返回根目录*/
mFileName.add("BacktoRoot");
mFilePaths.add(phone_sdcard);
/*列表项的第二项设置为返回上一级*/
mFileName.add("BacktoUp");
mFilePaths.add(new File(filePath).getParent());//回到当前目录的父目录即回到上级
isAddBackUp = true;
}
3.3.3 非文件夹类型文件的打开
再点击文件列表中的一个文件时,还有一种情况就是当前操作的文件不是文件夹,即file.isDirectory()的返回值为false。那么这时就需要根据文件的名称来判断文件的打开方式,并把文件的打开方式显示出来便于选择,效果图如下其中图3-3为当在文件列表中的文件长按点击时所弹出的对话框,及其中的的功能,图3-4为当点击mp3文件后的点击事件所触发的,文件打开方式所有关联的播放软件列表:
图 3-6 文件的长按点击事件对话框 图 3-7 音频文件的打开方式
文件打开方法部分源码:
/**调用文件的打开方法,根据文件类型判断文件的具体打开方法*/
private void openFiles(File file){
if(file.isDirectory()){
initFileListInfo(file.getPath());
}else{//如果是文件则调用文件的打开方法。
//隐式Intent跳转
Intent openFileIntent = OpenFilePort.openFile(file.getPath());
startActivity(openFileIntent);
}
}
在以上方法中当file.isDirectory的返回值为false时,就调用文件打开的工具类OpenFilePort中的openFile方法来判断文件的具体打开方法,然后用隐式Intent来实现跳转,获取文件的打开方法。在openFile()方法中首先要判断此文件是否存在,如果不存在则直接返回为Null,不在跳转,如果存在,则继续执行。当文件存在时首先要用file.getName()获取文件的名字,然后根据当前的文件名字来提取出文件的后缀名字,即文件的类型。获取方法是:首先用file.getName().lastIndexOf(".")判断出最后一个点“.”出现的位置,因为在此“.”以后的字符串就是文件的扩展名,即文件的类型。因为文件的扩展名不包括“.”,所以file.getName().lastIndexOf(".")返回的Int类型的Index要加1,然后用substring(file.getName().lastIndexOf(".") + 1,file.getName().length())来获取文件的后缀名,并用toLowerCase()方法把后缀名字全部改为小写,之后就根据文件的扩展名来判断文件的打开方法。例如文件的后缀名字为影音类型即end.equals("m4a")||end.equals("mp3")||end.equals("mid")||
end.equals("xmf")||end.equals("ogg")||end.equals("wav")){
return getAudioFileIntent(filePath);}根据判断后的结果来调用getAudioFileIntent(filePath)这个方法来实现影音文件的打开方式的关联。
影音文件类型的文件getAudioFileIntent(filePath)方法示例:
public static Intent getAudioFileIntent( String param ){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("oneshot", 0);
intent.putExtra("configchange", 0);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "audio/*");
return intent;
}
因为文件的类型有很多种所以判断的方法也很多,一下为文件打开方式的部分示例:
public class OpenFilePort {
public static Intent openFile(String filePath){
File file = new File(filePath);
if(!file.exists()) return null;
/* 取得扩展名 */
String end=file.getName().substring(file.getName().lastIndexOf(".") + 1,file.getName().length()).toLowerCase();
/* 依扩展名的类型决定MimeType */
if(end.equals("m4a")||end.equals("mp3")||end.equals("mid")||
end.equals("xmf")||end.equals("ogg")||end.equals("wav")){
return getAudioFileIntent(filePath);
}else if(end.equals("3gp")||end.equals("mp4")){
return getAudioFileIntent(filePath);
}else if(end.equals("jpg")||end.equals("gif")||end.equals("png")||
end.equals("jpeg")||end.equals("bmp")){
return getImageFileIntent(filePath);
}else if(end.equals("apk")){
return getApkFileIntent(filePath);
}else if(end.equals("ppt")){
return getPptFileIntent(filePath);
}else if(end.equals("xls")){
return getExcelFileIntent(filePath);
}else if(end.equals("doc")){
return getWordFileIntent(filePath);
}else if(end.equals("pdf")){
return getPdfFileIntent(filePath);
}else if(end.equals("chm")){
return getChmFileIntent(filePath);
}else if(end.equals("txt")){
return getTextFileIntent(filePath,false);
}else{
return getAllIntent(filePath);
}
}
//Android获取一个用于打开APK文件的intent
public static Intent getAllIntent( String param ) {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(android.content.Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri,"*/*");
return intent;
}
//Android获取一个用于打开APK文件的intent
public static Intent getApkFileIntent( String param ) {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(android.content.Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri,"application/vnd.android.package-archive");
return intent;
}
//Android获取一个用于打开VIDEO文件的intent
public static Intent getVideoFileIntent( String param ) {
Intent intent = new Intent("android.intent.action.VIEW");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("oneshot", 0);
intent.putExtra("configchange", 0);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "video/*");
return intent;
}
//Android获取一个用于打开AUDIO文件的intent
public static Intent getAudioFileIntent( String param ){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("oneshot", 0);
intent.putExtra("configchange", 0);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "audio/*");
return intent;
}
//Android获取一个用于打开Html文件的intent
public static Intent getHtmlFileIntent( String param ){
Uri uri = Uri.parse(param ).buildUpon().encodedAuthority("com.android.htmlfileprovider").scheme("content").encodedPath(param ).build();
Intent intent = new Intent("android.intent.action.VIEW");
intent.setDataAndType(uri, "text/html");
return intent;
}
//Android获取一个用于打开图片文件的intent
public static Intent getImageFileIntent( String param ) {
Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "image/*");
return intent;
}
//Android获取一个用于打开PPT文件的intent
public static Intent getPptFileIntent( String param ){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "application/vnd.ms-powerpoint");
return intent;
}
//Android获取一个用于打开Excel文件的intent
public static Intent getExcelFileIntent( String param ){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "application/vnd.ms-excel");
return intent;
}
//Android获取一个用于打开Word文件的intent
public static Intent getWordFileIntent( String param ){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "application/msword");
return intent;
}
//Android获取一个用于打开CHM文件的intent
public static Intent getChmFileIntent( String param ){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "application/x-chm");
return intent;
}
//Android获取一个用于打开文本文件的intent
public static Intent getTextFileIntent( String param, boolean paramBoolean){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (paramBoolean){
Uri uri1 = Uri.parse(param );
intent.setDataAndType(uri1, "text/plain");
}else{
Uri uri2 = Uri.fromFile(new File(param ));
intent.setDataAndType(uri2, "text/plain");
}
return intent;
}
//Android获取一个用于打开PDF文件的intent
public static Intent getPdfFileIntent( String param ){
Intent intent = new Intent("android.intent.action.VIEW");
intent.addCategory("android.intent.category.DEFAULT");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromFile(new File(param ));
intent.setDataAndType(uri, "application/pdf");
return intent;
}
}
3.3.4 效果图示例示例:
图3-8 手机根目录 图 3-9 手机SD卡根目录
3.3.5 在此功能实现过程中遇到的问题示例:
遇到的问题:
1、文件的打开方式的关联。
2、操作文件的地址间的传递
3、文件列表的刷新
解决过程:
文件的打开方式的关联:这是问的老师本来只会做出Txt文档的打开,还是用的输入输出流然后读取出文本中的内容然后显示到编辑框中。但后来问过老师才知道这种类似的文件打开方式还是有接口的,体统提供方法,直接用工具类就可以解决了。于是就在老师的帮助下,在网上找到了一段有关文件打开的工具类,就实现类文件的打开方式的链接。
文件操作的地址间的传递:在文件列表中的文件操作时,每当有点击事件时,都会有文件和文件地址间的传递。而在地址传递时要特别注意所操作的是哪个文件,一旦文件的地址或者文件传递错误,程序就会异常终止。
文件列表的刷新:每当点击文件列表中的文件夹时就会用到文件列表的刷新方法,而且每当创建文件,或者文件夹时,也会要有文件的刷新操作。
3.4 文件的复制,粘贴
文件的复制和粘贴的原理就是,当文件复制时用一个局部变量mOldFilePath把当前操作的文件地址保存起来,当粘贴时就会在新地址mNewFilePath中把,mOldFilePath所在的地址的文件,及其文件夹下的所有文件全部遍历复制。
在此功能中最主要的就是文件的粘贴,而文件的复制的方法只是保存下文件的地址。
所以此功能的主要实现方法几乎全部在文件的粘贴功能中。在文件的粘贴方法中,每当点击粘贴时就会产生新的当前路径粘贴路径mNewFilePath,而新的粘贴路径mNewFilePath有三个部分组成。第一部:分文件粘贴的地址是由当前所在的文件夹,即当前所显示的所有文件的文件列表的父文件夹mCurrentFilePath。第二部分:为一个文件地址分隔符“/”,而此分割符的产生使用java中的方法java.io.File.separator来产生的,java.io.File.separator方法的主要作用就是,根据不同的系统来创建,符合当前系统的文件分隔符。第三部分:在进行复制操作时所操作的文件的名字,即mCopyFileName。新文件的产生必须要加上所复制的文件的名字,然后来创建所要复制的文件夹的同名文件夹。然后在此文件下进行文件的复制操作。
文件的操作需要在不同的路径下才可以进行,因为用mOldFilePath.equals(mNew
FilePath)来判断,复制操作时的文件路径是否和粘贴的操作的文件路径是否相同,不同则进行后续的操作,相同则停止。而且每当复制时就会把变量isCopy变为ture,即表示文件是允许复制的,且执行了文件的复制操作。所以还要判断isCopy是否为ture,如果为ture在可以进行粘贴操作,否则就用Toast.makeText(MainActivity.this, "您还没有\"复制\"某个文件,又或者您在当前目录下执行了粘贴,这样是不可以\"粘贴\"滴。",Toast.LENGTH_LONG).
show()方法发出一个提示,提示你不可以进行粘贴操作。当判断后确定可以复制时,然后就进行判断文件夹是否存在,如果粘贴的位置有文件有复制的文件的存在,则用AlertDialog产生一个对话框,new AlertDialog.Builder(MainActivity.this).setTitle("提示!").setMessage("该文件名已存在,是否要覆盖?").setPositiveButton("确定", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog,int which){
copyFile(mOldFilePath,mNewFilePath);
initFileListInfo(mCurrentFilePath);//刷新列表
}})在此对话空中会询问是否覆盖已经存在的文件。如果点击确定就会执行copyFile(mOldFilePath,mNewFilePath)方法来进行文件的复制操作,在复制之后也要进行文件的刷新操作,否则新粘贴后文件或者文件夹是没法立即显示出来的。文件的复制及粘贴效果图如下:
图3-10 进行复制的对话框 图 3-11 错误粘贴命令提示
图 3-12 同名文件覆盖提示 图 3-13 执行复制后的提示
文件的的粘贴部分源码:
private void palseFile(){
mNewFilePath = mCurrentFilePath+java.io.File.separator+mCopyFileName;//得到新路径 ***要加上mCopyFileName复制文件的名字 不然只能复制源文件的内容本文件夹没有被复制
Log.d("copy", "mOldFilePath is "+mOldFilePath+"| mNewFilePath is "+mNewFilePath+"| isCopy is "+isCopy);
if(!mOldFilePath.equals(mNewFilePath)&&isCopy == true){//在不同路径下复制才起效 注意isCopy为true
//iscopy是指 你已执行了复制 不然只运行粘贴时没有用的
if(!new File(mNewFilePath).exists()){//判断粘贴的地址同级的文件中是否存在相同名字的文件夹 没有则复制
copyFile(mOldFilePath,mNewFilePath);
Toast.makeText(MainActivity.this, "执行了粘贴", Toast.LENGTH_SHORT).show();
initFileListInfo(mCurrentFilePath);
}else{
//Toast.makeText(MainActivity.this, "已存在该文件!", Toast.LENGTH_SHORT).show();
//存在相同文件则弹出对话框问是否覆盖。。。。
new AlertDialog.Builder(MainActivity.this)
.setTitle("提示!")
.setMessage("该文件名已存在,是否要覆盖?")
.setPositiveButton("确定", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface dialog,int which){
copyFile(mOldFilePath,mNewFilePath);
initFileListInfo(mCurrentFilePath);//刷新列表
}
})
.setNegativeButton("取消", null).show();
}
}else{//如果没有选则复制 直接粘贴就提示。。。
Toast.makeText(MainActivity.this, "您还没有\"复制\"某个txt文本文件,又或者您在当前目录下执行了粘贴,这样是不可以\"粘贴\"滴。", Toast.LENGTH_LONG).show();//
}
}
复制方法copyFile(参数一,参数二)中第一个参数为文件的源地址,即要复制的文件的地址,第二个参数为目标地址,即将要粘贴的文件的地址。在文件的复制方法中首先要判断要复制的是文件还是文件夹,如果是文件则直接调用文件的复制方copyFiles(sourcePath, targetPath)并把源文件的地址和目标的的地址传递过去,然后在copyFiles()中建立输入输出流,来实现文件的复制。如果是文件夹则首先遍历此文件夹下的多有子File,然后再逐一判断所有的子File,如果子File为文件则调用文件的复制方法,如果子File为文件夹则继续遍历,调用本方法。
/**复制方法*/
// copyFile()件的地址 目标地址
public void copyFile(String sourcePath,String targetPath){
if(new File(sourcePath).isFile()){//是否是文件
//判断文件的类型 是文件则直接复制
//File file=new File(targetPath+"/"+new File(sourcePath).getName());
copyFiles(sourcePath, targetPath);
}else{
//不是文件则创建文件夹
必须先创建文件夹 不然文件没法粘贴进去
new File(targetPath).mkdir();
遍历源文件下的所有哦文件
File[] listFiles = new File(sourcePath).listFiles();
for (File file2 : listFiles) {
System.out.println("FIle2:"+file2.getName());
if(file2.isFile()){
//如果是文件类型则直接调用文件复制的方法
copyFiles(file2.getPath(), targetPath+"/"+file2.getName());
}
else{
String targetPath1=targetPath+"/"+file2.getName();
String sourcePath1=sourcePath+"/"+file2.getName();
/*传过去地址 地址要注意 记得都加file.getname() 而且要改变成员变量sourcePath1,targetPath1的地址不然遍历复制时只能复制当前文件夹的下一层文件 没在向深处遍历*/
copyFile(sourcePath1, targetPath1);
}
}}
}
文件的复制方法copyFiles(String sourcePath, String targetPath)也有两个参数,中第一个参数为文件的源地址,即要复制的文件的地址,第二个参数为目标地址,即将要粘贴的文件的地址。然后再此方法中主要是建立一个输入流BufferedInputStream来读取文件,然后还建立了一个输出流BufferedOutputStream来粘贴文件进行复制。
//文件的复制
private void copyFiles(String sourcePath, String targetPath) {
FileInputStream input = null;
BufferedInputStream inBuff = null;
BufferedOutputStream outBuff = null;
FileOutputStream output = null;
try {
input = new FileInputStream(sourcePath);
inBuff=new BufferedInputStream(input);
// 新建文件输出流并对它进行缓冲
output = new FileOutputStream(targetPath);
outBuff=new BufferedOutputStream(output);
// 缓冲数组
byte[] b = new byte[1024 * 5];
int len;
while ((len =inBuff.read(b)) != -1) {
outBuff.write(b, 0, len);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
// 刷新此缓冲的输出流
try {
outBuff.flush();
//关闭流
inBuff.close();
outBuff.close();
output.close();
input.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3.4.2 此功能中遇到的问题
遇到的问题:
1、isCopy的使用
2、文件的路径问题
解决的过程:
由于刚用时没有用到isCopy这个属性,所以就造成就算没有复制粘贴键也可以使用,但是却会程序异常终止,因为根本就没有复制,多以复制的地址为空,会报出空指针异常NullPointException。于是便开始向一个方法可以让程序记录下,到底有没有执行过复制操作,因此便想到了创建一个Boolean类型的变量来记录复制操作的执行与否。
有关文件的路径一直都是此程序的一个难点,特别是在此功能中。当执行粘贴操作时如果要复制的是文件夹,则首先就要创建一个文件夹,即要复制的的那个文件夹,否则就会造成源文件夹中的内容全部复制过去了,唯独要复制的父文件夹没有复制。而且每次复制文件时targetPath1,sourcePath1都要刷新,targetPath1=targetPath+"/"+file2.
getName(),sourcePath+"/"+file2.getName(),否则就会造成要复制的文件夹中的内容,却只会复制文件夹下的第一层子文件夹。还有每当要复制时都要new File(targetPath).mkdir(),否则就会造成要复制的文件内容,复制到粘贴的地方时发生,路径错误,找不到文件夹。
第4章 结束语
课题设计中着实感到自己对知识掌握的熟练度太低,经常会出现一些似懂非懂的知识点,在这次课题设计中,我深刻的认识到需要学习的只是还有很多,随着知识圈的增大,才发现需要懂得更多,要知道的知识也不在限制与课堂上老师讲的了。毕竟老师讲的只能是少数,更多地还是要靠自己,多研究,多学习。在这次编程中我也发现了, 编程水平也不是越多越好,在增长新知识的同时,一定要把老的知识学得更精,学得更透并学会灵活运用。而且实践永远比想象更重要,不要只理解了就认为会了,要去实践才知道自己的不足,才知道想象中其实有很多的错误,如果你不去实践,你就永远不知道自己哪里会出错,错误也只会越积越多,最终自己只有一事无成。
在课题设计中出现问题时应该及时和同学们进行交流,多交流才能使学到的知识更深入到心里,也使我更明白理论与实践相结合的重要性,只有理论是远远不够的,只有把所学的理论和实践相结合起来,从实践中得到结论,才能真正的提高自己的水平,从而提高自己的实际动手能力和独立思考的能力。它提高了我的软件设计和程序编制能力,使我对软件开发有了一个比较清楚的认识,对软件生命周期各个阶段的目的、工作有了更深刻的体会,加深了我对软件工程、程序设计的学习,极大的增强了我综合运用本专业的思维、方式方法分析、解决问题的能力;在其他方面,它又锻炼了我的耐心、毅力和坚持到底的精神。这些都将是终生的财富,必将给今后的学习和工作带来更多的收益。 通过课程设计,也发现了自己存在的一些不足,由于自己的分析设计和程序经验不足,该系统设计和实现过程中,还有许多没有完善的地方,这些都有待进一步完善和提高,使自己达到一个更高的层次。我的缺点是,在很多情况下都是眼高手低,功能想着简单,会想就以为会编这个程序了,可实际编程的时候却发现想着简单做着难,很多预期的功能无法做到位。总之眼高手低是绝对不可取的,实践出真知理解容易会写难。通过这次的中工导航开发学到了很多的知识,也熟练了平时学的技术使之运用变的更加熟练。
这次实训,我们更多学到的是不论做什么时都应该尽自己的最大的努力,不要害怕失败,一时的失败也只是为将来的成功做铺垫,也只是为下一次的努力提供经验。只要你尽自己的最大的努力,不管成败,拼去吧!
在编程之路上,我们还有很长的路要走,还有很多不懂得的知识需要我们去虚心学习,即使学习过的也需要不断地练习实践,更加熟练的运用。只有这样才能开发出更好玩儿的游戏,才能减少开发程序时的时间浪费,提高效率。既然我们选择了编程这条路,那么便要拿出自己百分之二百的热情去投身到这个事业中,不求有一个惊天动地的成就,只求尽自己最大的努力,对得起自己,无怨无悔!
参考文献
[1] 童爱红. Visual C#.NET应用教程[M]. 北京:人民邮电出版社,2004.3
[2] 李兰友 杨晓光. Visual C#.NET程序设计[M] 北京:清华大学出版社,2004.5
[3] 韩玉民. 计算机专业英语教学研究与实践 [J].计算机与信息技术,2008,(6):106-107.
[4] When mouse use computer.[EB/OL]. http://www.danscartoons.com/comp_demo101.gif, 2008-12-26.