一个月没有更新内容,因为想要实践一下自己的理论知识,于是参加了一个软件类比赛,选题为移动设备之间的文件互传。
不得不说,实践的确是锻炼解决问题能力的最好办法。 遇到了很多自己在一般demo中,并没有发现的问题,并且学习很多新的知识。
准备将这个Android实例的开发过程记录。
软件功能:
- 各类型文件的快速访问
- 实现手机的文件的快速分享
- 通过电脑对于手机的文件访问
主要技术:
1.文件阅览:
已安装APK软件:
通过packageManager这个用于管理应用程序包,便能获取已安装程序的许多相应信息。具体到软件中的实现参考了 郭霖 公众号中推送的这篇仿QQ获取手机中的APK并分享。
多媒体文档以及office文档:通过MediaStore的方式,根据相应文件类型的Uri来进行查找。MediaStore是android系统提供的一个多媒体数据库,android中多媒体信息都可以从这里提取。(MediaStore相应基础知识)。
可以通过相应的SQL语句对数据进行查询。如music则传入
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
;
例PPT则为
MediaStore.Files.getContentUri("external"),type
type为查询得的MIME类型
MediaStore.Files.FileColumns.MIME_TYPE==application/mspowerpoint
在按上面说明的Cursor,定义一个总的读取数据的方式。
public synchronized List<TFile> getMediaFiles(Activity cxt , Uri uri,String select) { //TFile 为一个总的文件管理类,包含文件的信息Cursor mCursor = cxt.managedQuery(uri,new String[] {MediaStore.Audio.Media.DATA}, select,null, " date_modified desc");cxt.startManagingCursor(mCursor);int count = mCursor.getCount();if(count>0){List<TFile> data = new ArrayList<TFile>();if (mCursor.moveToFirst()) {do {TFile.Builder builder = new TFile.Builder(mCursor.getString(0));TFile bxfile = builder.build();if(null != bxfile&&bxfile.getFileSize()>819200)data.add(bxfile);} while (mCursor.moveToNext());}return data;}else{return null;}}
很大程度上学习了github上TracyZhangLei的FileExplorer,不仅仅是MediaStore,而是很多代码上方式,设计模式,对整个工程上的框架的大体建立。
照片的显示:通过ImageLoader对照片的加载,通过gridview的显示。根据获取的屏幕大小,调节Item的大小。这一块自己写的很失败…..加载过程中总是各种问题不断,最后还是参考了别人的代码才完成。在照片的更新上的显示还存在问题,每次都是对于listview的整体更新,体验比较差,以后有时间修正。
文件阅览的基本功能: 对当前文件夹遍历,读取文件夹下的文件信息,通过ListView的显示。当时遇到的主要问题是,阅览界面作为一个Fragment,对于Activity的back键的监听重载上,网上有很多种办法,但是尝试之后都遇到了问题,最后在Activity中回调函数的方式解决。2.电脑互传:
搜索之后,发现有2种方式实现,一种是通过ftp协议实现,Android手机作为数据传输过程中的ftp服务器;
一种是通过http协议实现。Android手机作为数据传输过程中的http服务器。
在这篇Android基于WIFI实现电脑和手机间数据传输的技术方案研究中,对很多例子进行了说明。
最后选择通过ftp协议的方式,采用Apache FtpServerFTP服务器引擎解决,这种方法的问题是需要的第三方jar包比较多,比较麻烦。参考了android 基于apache ftp server。
实现之后在同一WiFi网络下,便可以通过相应的ftp地址对手机上的文件访问。
热点模式为通过手机上的APWiFi,电脑与之相连接,同样可以达到访问的效果。
public boolean setWifiApEnabled(boolean enabled) { //热点的开启WifiManager wifiManager = null;wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);if (enabled) { // disable WiFi in any case//wifi和热点不能同时打开,所以打开热点的时候需要关闭wifiwifiManager.setWifiEnabled(false);}try {//热点的配置类WifiConfiguration apConfig = new WifiConfiguration();//配置热点的名称(可以在名字后面加点随机数什么的)apConfig.SSID = "快传";final Myapplication Date = (Myapplication) getApplication();if(Date.getName().equals("")){apConfig.SSID = Date.getName();}//配置热点的密码//通过反射调用设置热点Method method = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, Boolean.TYPE);ap_name.setText("用户名");ap_name.setVisibility(View.VISIBLE);wifi_title.setText(" 连接电脑至本机热点:");//返回热点打开状态return (Boolean) method.invoke(wifiManager, apConfig, enabled);} catch (Exception e) {return false;}}
3.蓝牙分享:
很简单的分享方式,通过手机中自带的bluetooth,传入相应的apk的URi地址,startActivity,便开始的文件的传递。
Intent intent_bluetooth = new Intent();intent_bluetooth.setAction(Intent.ACTION_SEND);intent_bluetooth.setType("*/*");intent_bluetooth.setClassName("com.android.bluetooth", "com.android.bluetooth.opp.BluetoothOppLauncherActivity");File f = new File("///data/app/com.wifidirect-1/base.apk");intent_bluetooth.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f));Log.d("ConnectFragment", "onItemLongClick: "+Uri.fromFile(f));startActivity(intent_bluetooth);
在确定文件地址的过程中,从data/app中寻找相应文件。但是不确定是否有误android版本的原因,显示格式不再是查到的data/app + [包名]-N.apk(覆盖安装N次),而是data/app/包名-N/base.apk,并且在我多次覆盖安装后,N也并没有发生变化,直接从该路径读取文件并没有发生问题。
4.手机连接:
查询到的连接方式有ad hoc模式和WiFiDirect模式。
QQ上的面对面快传以及快牙 从使用上来说,感觉都是采用ad hoc模式,可能是因为ad hoc设备支持比较广,android2.3便可以使用,而WiFiDirect为android4.0以上开始支持。并且从连接方式上,感觉ad hoc比较方便。而WiFiDirect的一些优点:强大的发现功能,如更高的数据速率、企业管理能力、WMM? Quality of Service模式,以及点到点连接的电源管理协议,安全性;在实际使用上,并没有太大的体现。
但是由于找到的WiFiDirect的资料比较多,并且理论上WiFiDirect更为优秀(WiFiDirect在使用中不会对正在使用WiFi网络造成影响,ad hoc则必须断开。)最后还是采用了WiFiDirect作为了连接方式。
个人对其完全只能说是使用的程度,只能罗列自己在学习过程中查询到的资料:
在sdk\samples\android-22\legacy\WiFiDirectDemo 中,可以看到官方的WiFiDriect的demo,虽然比较简单,但是还是有比较大的帮助,在github上搜索,同样可以找到。
WiFi P2P 官方文档
《深入理解Android:Wi-Fi,NFC和GPS》章节连载[节选]–第七章 深入理解Wi-Fi P2P
Android平台Wifi_Direct使用
5.文件传输:
文件传输方式,采用了与官方WiFiDirect demo中相同的socket方式。由于之前对通信相关的知识完全一点不了解,在这个过程中跌了无数坑,一路模仿着demo,查找着相关内容………..
socket起源于UNIX,在Unix一切皆文件哲学的思想下,socket是一种”打开—读/写—关闭”模式的实现,服务器和客户端各自维护一个”文件”,在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。
基础实现并不复杂,但是又很多可以扩展的,比如多线程,断点传输……..
断点传输查询了一些信息,需要用到数据库,对当前下载文件信息的的记录….然而处于考试月并且ACM的省赛,区域赛需要准备,只能归于未来完成计划。
Socket的文档:
简单理解Socket
很详细的例子Android 基于Socket的聊天室
最后采用的socket的单线程传输方式,因为根据传输带宽由取决于双方的硬件,多线程下载只会使单个文件下载速度下降(不确定)。
官方demo中传输的文件类型唯一,并且传输文件名为随机时间命名。后查询到采用包含文件信息的文件流解决问题。文件信息和文件合并后在写入socket输出流,从中获取信息,先确定文件类型,再写入相应文件。
基于TCP协议的文件传输,传输带文件名等信息的文件流
6.下载信息更新:
通过Handler机制实现。在主线程中,对各个发送状态进行监听,相应的更新UI。在Socket通信过程中,不断更新信息,发送信息。
参考了一些下载器demo的实现。
主要内部实现就是如上,但是只是对于知识点的大概记录,很多方面并没有能够完成依靠自己完成,仅仅知道学习,使用,模仿的程度,如果完全要求自己独立完成,感觉还是比较吃力。已经完成的这部分,就已经相应再进行学习,掌握。
接下来会是对于软件UI的实现记录,主要使用的UI方式,例子。
一些人问的代码分享
这个demo在github上的地址:https://github.com/lucky-code/Practice/tree/master/kuaichuan2.0
其次由于android6.0新的权限管理机制,这个demo需要补上一个权限申请,一个坑以后再填啦…..