在ReactNative使用过程中,我们使用最多的是通过fetch的方法来访问网络。但是当用于下载的时候,好像没有什么好的办法可以显示进度条。下面主要介绍的是在安卓原生中自定义网络请求模块来请求网络并且显示进度。
首先用AndroidStudio打开RN项目下的android文件夹。我们可以看到一个很标准的安卓项目结构。
在项目中我们用已经封装好的OkHttp工具来实现在原生的网络访问。
在gradle下添加
compile 'com.zhy:okhttputils:2.6.2'
在Application对OkhttpUtils进行初始化。
OkHttpClient okHttpClient = new OkHttpClient.Builder()
// .addInterceptor(new LoggerInterceptor("TAG"))
.connectTimeout(10000L, TimeUnit.MILLISECONDS)
.readTimeout(10000L, TimeUnit.MILLISECONDS)
//其他配置
.build();
OkHttpUtils.initClient(okHttpClient);
做好准备工作,接下来就正式进行自定义网络模块的封装。
首先新建MyNetModule继承ReactContextBaseJavaModule。直接放出代码
public class MyNetModule extends ReactContextBaseJavaModule{
private static final String REQUSETURL= "URL";
private static final String FILEPAHT = "PATH";
public static boolean myflag=false;
public ProgressDialog mDialog,upDialog;
public MyNetModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "MyHttpRequest";
}
@ReactMethod
public void download(final String url, final String filename) {
mDialog=new ProgressDialog(getCurrentActivity());
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setTitle("正在下载...");
mDialog.setCancelable(true);
mDialog.setCanceledOnTouchOutside(false);// 设置在点击Dialog外是否取消Dialog进度条
mDialog.setMax(100);
mDialog.setButton(DialogInterface.BUTTON_POSITIVE,"取消下载",new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
myflag=true;
OkHttpUtils.getInstance().cancelTag(getCurrentActivity());
File file=new File(Environment.getExternalStorageDirectory().getAbsolutePath(),filename);
file.delete();
}
});
mDialog.show();
OkHttpUtils//
.get()//
.url(url)//
.tag(getCurrentActivity())
.build()//
.execute(new FileCallBack(Environment.getExternalStorageDirectory().getAbsolutePath(), filename)//
{
@Override
public void onError(Call call, Exception e, int id) {
mDialog.dismiss();
if (myflag) {
Toast.makeText(getCurrentActivity(), "下载失败,用户取消了下载", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getCurrentActivity(), "下载失败", Toast.LENGTH_LONG).show();
Log.v("wt", e.getMessage());
}
myflag=false;
}
@Override
public void onResponse(File response, int id) {
mDialog.dismiss();
Toast.makeText(getCurrentActivity(),"下载成功",Toast.LENGTH_LONG).show();
Log.v("wt",response.getAbsolutePath());
}
@Override
public void inProgress(float progress, long total, int id) {
super.inProgress(progress, total, id);
mDialog.setProgress((int) (progress*100));
Log.v("wt", String.valueOf(progress));
}
});
}
public class MyStringCallback extends StringCallback
{
@Override
public void inProgress(float progress, long total, int id) {
super.inProgress(progress, total, id);
Log.v("up", String.valueOf(progress));
upDialog.setProgress((int) (progress*100));
}
@Override
public void onBefore(Request request, int id)
{
}
@Override
public void onAfter(int id)
{
}
@Override
public void onError(Call call, Exception e, int id)
{
upDialog.dismiss();
Log.v("wt",e.getMessage());
}
@Override
public void onResponse(String response, int id)
{
upDialog.dismiss();
Log.e("wt", "onResponse:complete");
Toast.makeText(getCurrentActivity(),"上传成功",Toast.LENGTH_LONG).show();
}
}
@ReactMethod
public void upload(String url, final String filename){
upDialog=new ProgressDialog(getCurrentActivity());
upDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
upDialog.setTitle("正在上传...");
upDialog.setCancelable(true);
upDialog.setCanceledOnTouchOutside(false);// 设置在点击Dialog外是否取消Dialog进度条
upDialog.setMax(100);
upDialog.setButton(DialogInterface.BUTTON_POSITIVE,"取消上传",new DialogInterface.OnClickListener(){
@Override
public void onClick(DialogInterface dialog, int which) {
myflag=true;
Toast.makeText(getCurrentActivity(),"用户取消上传",Toast.LENGTH_LONG).show();
OkHttpUtils.getInstance().cancelTag(getCurrentActivity());
}
});
upDialog.show();
Map<String, String> headers = new HashMap<>();
headers.put("application", "octet-stream");
File file = new File(Environment.getExternalStorageDirectory(), filename);
Log.v("wt", String.valueOf(file.exists()));
OkHttpUtils
.post().addFile("upload",filename,file)
.url(url)
.tag(getCurrentActivity())
.build()
.execute(new MyStringCallback());
}
}
在上面的代码中。主要利用okhttpUtils实现了上传和下载的功能以及用ProgressDialog显示进度。需要注意的是在getName()方法中返回的字符串,在js调用的时候会使用到。
封装好了MyNetMoudule模块。我们还需要在ReactPackage中对这个模块进行注册。注册的代码如下。
public class RCTCommonToolsPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules=new ArrayList<>();
modules.add( new RCTCommonTools(reactContext));
modules.add(new MyNetModule(reactContext));
return modules;
}
@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
上面的代码主要是写一个RCTCommonToolsPackage 类继承于ReactPackage.并在里面实现其三个方法。在createNativeModules方法里面注册我们自己定义的模块
注册完成后,我们还需要在MainApplication里面对我们自定义的package进行注册。主要代码如下
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage(),
new RCTCommonToolsPackage(),
new ReactImageZoom()
);
}
};
到了这里,我们的自定义网络模块封装完毕。
接下来是使用。
'use strict';
var { NativeModules } = require('react-native');
module.exports = NativeModules.MyHttpRequest;
'use strict';
import React, {Component} from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
TouchableOpacity,
ToastAndroid,
Alert,
NativeModules
} from 'react-native';
var url="http://sw.bos.baidu.com/sw-search-sp/software/453ba7195c823/QQPhoneManager_5.6.1.5116.exe";
var fliename="my.apk";
var flie="my.apk";
var uploadurl='http://108.88.0.101:8080/uploadProgress/upload';
import MyHttpRequest from './DwithU.js'
export default class AwesomeProject extends Component{
HttpDown(){
MyHttpRequest.download(url,flie)
}
HttpUp(){
MyHttpRequest.upload(uploadurl,fliename)
}
render() {
return (
<View style = { {flex: 1,justifyContent: 'center',alignItems: 'center' }}>
<TouchableOpacity onPress = {this.HttpDown }style = {styles.button} >
<Text > DOWN</Text>
</TouchableOpacity>
<TouchableOpacity onPress = {this.HttpUp} style = {styles.button } >
<Text> UPLOAD </Text>
</TouchableOpacity>
</View>
);
}
}
var styles = StyleSheet.create({
button: {
width: 180,
height: 50,
justifyContent: 'center',
backgroundColor: '#e2e2e2',
alignItems: 'center',
margin: 10,
}
});