在ReactNative使用過程中,我們使用最多的是通過fetch的方法來訪問網絡。但是當用于下載的時候,好像沒有什么好的辦法可以顯示進度條。下面主要介紹的是在安卓原生中自定義網絡請求模塊來請求網絡并且顯示進度。
首先用AndroidStudio打開RN項目下的android文件夾。我們可以看到一個很標準的安卓項目結構。
Paste_Image.png
在項目中我們用已經封裝好的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,
}
});
效果圖
Paste_Image.png