android文件搜索广播,Android 实现无网络传输文件
因为客户端可能会多次发起连接请求,所以当此处文件传输完成后(不管成功或失败),都需要重新 startService
,让服务再次堵塞等待客户端的连接请求
FileTransfer 包含三个字段,MD5码值用于校验文件的完整性,fileLength
是为了用于计算文件的传输进度
public class FileTransfer implements Serializable {
//文件路径
private String
filePath;
//文件大小
private long
fileLength;
//MD5码
private String md5;
···
}
为了将文件传输进度发布到外部界面,所以除了需要启动Service外,界面还需要绑定Service,此处就需要用到一个更新文件传输状态的接口
public
interface OnProgressChangListener {
//当传输进度发生变化时
void
onProgressChanged(FileTransfer fileTransfer, int
progress);
//当传输结束时
void
onTransferFinished(File file);
}
因此,需要将 progressChangListener
作为参数传给 WifiServerService
,并在进度变化时更新进度对话框
private
WifiServerService.OnProgressChangListener progressChangListener =
new WifiServerService.OnProgressChangListener() {
@Override
public
void onProgressChanged(final FileTransfer fileTransfer, final int
progress) {
runOnUiThread(new Runnable()
{
@Override
public void run() {
progressDialog.setMessage("文件名: " + new
File(fileTransfer.getFilePath()).getName());
progressDialog.setProgress(progress);
progressDialog.show();
}
});
}
@Override
public
void onTransferFinished(final File file) {
runOnUiThread(new Runnable()
{
@Override
public void run() {
progressDialog.cancel();
if (file
!= null && file.exists()) {
openFile(file.getPath());
}
}
});
}
};
四、客户端加入群组并发起文件传输请求
文件发送界面 SendFileActivity 需要实现
DirectActionListener 接口 首先,需要先注册P2P广播,以便获取周边设备信息以及连接状态
@Override
protected
void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_send_file);
initView();
mWifiP2pManager =
(WifiP2pManager)
getSystemService(Context.WIFI_P2P_SERVICE);
mChannel =
mWifiP2pManager.initialize(this, getMainLooper(), this);
broadcastReceiver = new
DirectBroadcastReceiver(mWifiP2pManager, mChannel,
this);
registerReceiver(broadcastReceiver,
DirectBroadcastReceiver.getIntentFilter());
}
通过
discoverPeers 方法搜索周边设备,回调函数用于通知方法是否调用成功
mWifiP2pManager.discoverPeers(mChannel, new
WifiP2pManager.ActionListener() {
@Override
public
void onSuccess() {
showToast("Success");
}
@Override
public
void onFailure(int reasonCode) {
showToast("Failure");
loadingDialog.cancel();
}
});
当搜索结束后,系统就会触发
WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION 广播,此时就可以调用
requestPeers 方法获取设备列表信息,此处用 RecyclerView 展示列表,在
onPeersAvailable 方法刷新列表
mWifiP2pManager.requestPeers(mChannel, new
WifiP2pManager.PeerListListener() {
@Override
public
void onPeersAvailable(WifiP2pDeviceList peers) {
mDirectActionListener.onPeersAvailable(peers.getDeviceList());
}
});
@Override
public
void onPeersAvailable(Collection wifiP2pDeviceList) {
Log.e(TAG, "onPeersAvailable
:" + wifiP2pDeviceList.size());
this.wifiP2pDeviceList.clear();
this.wifiP2pDeviceList.addAll(wifiP2pDeviceList);
deviceAdapter.notifyDataSetChanged();
loadingDialog.cancel();
}
之后,通过点击事件选中群主(服务器端)设备,通过 connect
方法请求与之进行连接
private void connect() {
WifiP2pConfig config = new WifiP2pConfig();
if
(config.deviceAddress != null && mWifiP2pDevice != null)
{
config.deviceAddress =
mWifiP2pDevice.deviceAddress;
config.wps.setup =
WpsInfo.PBC;
showLoadingDialog("正在连接 " +
mWifiP2pDevice.deviceName);
mWifiP2pManager.connect(mChannel, config, new
WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
Log.e(TAG,
"connect onSuccess");
}
@Override
public void onFailure(int reason) {
showToast("连接失败 " + reason);
dismissLoadingDialog();
}
});
}
}
此处依然无法通过函数函数来判断连接结果,需要依靠系统发出的
WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION
方法来获取到连接结果,在此处可以通过 requestConnectionInfo
获取到组连接信息,信息最后通过 onConnectionInfoAvailable
方法传递出来,在此可以判断当前设备是否为群主,获取群组IP地址
@Override
public void
onConnectionInfoAvailable(WifiP2pInfo wifiP2pInfo) {
dismissLoadingDialog();
wifiP2pDeviceList.clear();
deviceAdapter.notifyDataSetChanged();
btn_disconnect.setEnabled(true);
btn_chooseFile.setEnabled(true);
Log.e(TAG,
"onConnectionInfoAvailable");
Log.e(TAG,
"onConnectionInfoAvailable groupFormed: " +
wifiP2pInfo.groupFormed);
Log.e(TAG,
"onConnectionInfoAvailable isGroupOwner: " +
wifiP2pInfo.isGroupOwner);
Log.e(TAG,
"onConnectionInfoAvailable getHostAddress: " +
wifiP2pInfo.groupOwnerAddress.getHostAddress());
StringBuilder stringBuilder = new StringBuilder();
if
(mWifiP2pDevice != null) {
stringBuilder.append("连接的设备名:");
stringBuilder.append(mWifiP2pDevice.deviceName);
stringBuilder.append("\n");
stringBuilder.append("连接的设备的地址:");
stringBuilder.append(mWifiP2pDevice.deviceAddress);
}
stringBuilder.append("\n");
stringBuilder.append("是否群主:");
stringBuilder.append(wifiP2pInfo.isGroupOwner ? "是群主" :
"非群主");
stringBuilder.append("\n");
stringBuilder.append("群主IP地址:");
stringBuilder.append(wifiP2pInfo.groupOwnerAddress.getHostAddress());
tv_status.setText(stringBuilder);
if
(wifiP2pInfo.groupFormed && !wifiP2pInfo.isGroupOwner)
{
this.wifiP2pInfo =
wifiP2pInfo;
}
}
至此服务器端和客户端已经通过 Wifi P2P
连接在了一起,客户端也获取到了服务器端的IP地址,在选取好待发送的文件后就可以主动发起对服务器端的连接请求了
发起选取文件的方法
Intent intent = new
Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*
public class WifiClientTask extends AsyncTask
{
private
ProgressDialog progressDialog;
private
FileTransfer fileTransfer;
private
static final int PORT = 4786;
private
static final String TAG = "WifiClientTask";
public
WifiClientTask(Context context, FileTransfer fileTransfer)
{
this.fileTransfer =
fileTransfer;
progressDialog = new
ProgressDialog(context);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setCancelable(false);
progressDialog.setCanceledOnTouchOutside(false);
progressDialog.setTitle("正在发送文件");
progressDialog.setMax(100);
}
@Override
protected
void onPreExecute() {
progressDialog.show();
}
@Override
protected
Boolean doInBackground(String... strings) {
fileTransfer.setMd5(Md5Util.getMd5(new
File(fileTransfer.getFilePath())));
Log.e(TAG, "文件的MD5码值是:" +
fileTransfer.getMd5());
Socket socket =
null;
OutputStream outputStream =
null;
ObjectOutputStream
objectOutputStream = null;
InputStream inputStream =
null;
try {
socket = new Socket();
socket.bind(null);
socket.connect((new
InetSocketAddress(strings[0], PORT)), 10000);
outputStream =
socket.getOutputStream();
objectOutputStream = new
ObjectOutputStream(outputStream);
objectOutputStream.writeObject(fileTransfer);
inputStream = new FileInputStream(new
File(fileTransfer.getFilePath()));
long fileSize =
fileTransfer.getFileLength();
long total = 0;
byte buf[] = new byte[512];
int len;
while ((len = inputStream.read(buf)) != -1)
{
outputStream.write(buf, 0, len);
total +=
len;
int
progress = (int) ((total * 100) / fileSize);
publishProgress(progress);
Log.e(TAG,
"文件发送进度:" + progress);
}
outputStream.close();
objectOutputStream.close();
inputStream.close();
socket.close();
outputStream = null;
objectOutputStream = null;
inputStream = null;
socket = null;
Log.e(TAG, "文件发送成功");
return true;
} catch (Exception e)
{
Log.e(TAG, "文件发送异常 Exception: " +
e.getMessage());
} finally {
if (outputStream != null) {
try
{
outputStream.close();
} catch
(IOException e) {
e.printStackTrace();
}
}
if (objectOutputStream != null) {
try
{
objectOutputStream.close();
} catch
(IOException e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try
{
inputStream.close();
} catch
(IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try
{
socket.close();
} catch
(Exception e) {
e.printStackTrace();
}
}
}
return false;
}
@Override
protected
void onProgressUpdate(Integer... values) {
progressDialog.setProgress(values[0]);
}
@Override
protected
void onPostExecute(Boolean aBoolean) {
progressDialog.cancel();
Log.e(TAG, "onPostExecute: "
+ aBoolean);
}
}
五、校验文件完整性
传输文件的完整性主要是通过计算文件的MD5码值来保证了,在发送文件前,即在 WifiClientTask 的
doInBackground 方法中进行计算,将MD5码值赋给 FileTransfer 模型,通过如下方法计算得到
public class Md5Util {
public
static String getMd5(File file) {
InputStream inputStream =
null;
byte[] buffer = new
byte[2048];
int numRead;
MessageDigest md5;
try {
inputStream = new
FileInputStream(file);
md5 =
MessageDigest.getInstance("MD5");
while ((numRead = inputStream.read(buffer)) >
0) {
md5.update(buffer, 0, numRead);
}
inputStream.close();
inputStream = null;
return md5ToString(md5.digest());
} catch (Exception e)
{
return null;
} finally {
if (inputStream != null) {
try
{
inputStream.close();
} catch
(IOException e) {
e.printStackTrace();
}
}
}
}
private
static String md5ToString(byte[] md5Bytes) {
StringBuilder hexValue = new
StringBuilder();
for (byte b : md5Bytes)
{
int val = ((int) b) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return
hexValue.toString();
}
}
因为客户端会将 FileTransfer
传给服务器端,所以服务器端在文件传输结束后,可以重新计算文件的MD5码值,进行对比以判断文件是否完整
android文件搜索广播,Android 实现无网络传输文件相关推荐
- 吊炸天之Android 如何实现无网络传输文件
热文导读 | 点击标题阅读 欢迎加入Java和Android架构知识星球 Android大厂面试题锦集附答案(BAT TMD JD 小米) 程序员如何进阶成为大神? 作者:叶应是叶 原文:http:/ ...
- Android 实现无网络传输文件(2)
在我的上一篇文章:Android 实现无网络传输文件,我介绍了通过 Wifi Direct(Wifi 直连)实现 Android 设备之间进行文件传输的方法,可以在无移动网络的情况下实现点对点的文件传 ...
- oracle asm和文件系统,Oracle工具之--ASM与文件系统及跨网络传输文件
Oracle工具之--ASM与文件系统及跨网络传输文件 Oracle DBMS_FILE_TRANSFER可以实现文件系统和ASM磁盘组之间实现文件传输及ASM磁盘组之间跨网络的传输. DBMS_FI ...
- Oracle工具之--ASM与文件系统及跨网络传输文件
Oracle工具之--ASM与文件系统及跨网络传输文件 Oracle DBMS_FILE_TRANSFER可以实现文件系统和ASM磁盘组之间实现文件传输及ASM磁盘组之间跨网络的传输. DBMS_ ...
- Java 文件传输小工具,网络传输文件,内网传输
文件传输小工具,网络传输文件,内网传输 换了一台电脑,想把一台电脑的资料放到另一太电脑上,由于没有太大的U盘就动手用Java写了个小工具.有需要的朋友下载使用! 运行环境 运行环境需要安装JDK,并配 ...
- android加载网页pdf,android 一行代码搞定加载网络 pdf 文件
之前写过一篇Android打开本地pdf文件的文章,最后总结的时候说,后面一定要拓展库,让其也能打开网络的的pdf文件.今天终于可以兑现承诺了.frok一份代码github.com/JoanZapat ...
- 文件搜索工具android,Search Everything下载
在PC系统上,又一款很知名的本地文件搜索工具,名称叫做Everything,而在android平台上,也有一款如此功能的应用,它的名字叫 Search Everything,十分小巧,但是其功能却是十 ...
- android连路由器 mtu,解决app无网络问题,将宽带路由器MTU从1500修改成1480
问题描述 移动宽带路由器MTU=1500时某些app无网络,改成1480就解决了,是什么原因造成的? 正文 出问题的APP,使用手机默认MTU =1500来发送TCP报文.到达宽带路由器WAN出口时, ...
- Android允许应用程序使用Http明文网络传输
自Android9.0系统开始,应用程序默认只允许使用HTTPS类型的网络请求,HTTP类型的网络请求因为有安全隐患默认不再支持.为了让应用程序支持HTTP请求,可以做如下设置: 1.在res/xml ...
最新文章
- Tomcat配置虚拟路径,使上传文件与服务器及工程文件分离开
- asin c语言中 返回值范围_大学C语言考试易错知识点总结
- Storyboard.storyboard could not be opened. Could not read the archive.
- 有关fwrite语句的用法
- 保险的现金价值是什么意思?
- 模拟任务调度算法 C语言 【留学生作业】
- 怎么利用微博进行营销?
- 常见英文咒语与低俗词汇一览表(应避免使用)
- 功率因数 matlab,基于Matlab的功率因数校正电路的仿真分析
- 北京消费扶贫双创中心启用 2000余种特色产品长期展销
- 计算机如何磁盘整理,如何整理磁盘碎片让Win7电脑运行更快?
- java金额三位一撇方法_Java数据格式化问题
- 锂离子电池电量计的选择
- 商汤科技发布新一代SensePass工业级可视人脸识别门禁全新升级
- dhcp snooping华为_华为交换机DHCP snooping
- 【03yy and triangle】
- Tomcat的8005、8009,8080端口解释
- CSS布局:CSS三大特性、盒子模型
- 【系统分析师之路】面向对象开发方法,Coad方法、Booch方法和OMT方法及UML
- 高中必备学习软件_有哪些适合高中生的学习软件?