原文:The Best Android Networking Library for Fast and Easy Networking。
最近我发布了一个library,我认为它是安卓上处理网络的最简方式。
以下是Fast Android Networking优于它库的几个方面:
每个请求都可以轻易的定制OkHttpClient-比如超时等。
因为它使用了OkHttpClient和Okio,所以速度很快
支持把JSON解析成java对象(同时支持Jackson解析)。
可以得到任何请求的详细数据分析。你可以知道发送了多少字节,接收了多少字节,以及请求所花的时间。这些数据是很重要的,这样你就可以识别出慢的请求。
你可以得到当前的带宽和网络质量以写出更合理的代码-网络质量高的时候下载高质量的图片,不好的时候下载低质量的图片。
Proper Response Caching— which leads toreduced bandwidth usage.
很好的响应请求-可以减少带宽的使用。
一个executor可以被传递给任何请求让响应在另一个线程中被获取。如果你在响应中做了很重的任务,你不可以在主线程中做。
一个库就能处理所有类型的网络问题-下载,上传,multipart。
可以通过设置prefetch(预取)让请求在需要的时候立即返回缓存。
任何类型的自定义都是可以的
立即请求真的是立即发生的。
很好的取消请求。
如果一个请求完成了指定的百分比,可以阻止其取消。
一个简单的接口就可以做任何类型的请求。
为什么你应该使用Fast Android Networking Library?
最近Android Marshmallow(Android M)上对HttpClient的移除让其它的网络库都过时了。
没有哪个单一的库做完了所有的事情,比如发送请求,下载任意类型的文件,上传文件,在ImageView中加载网络图片,等等。有一些库可以但是都过时了。
因为使用了sOkHttp,所以支持HTTP/2。
没有哪个库为网络中所有类型的事情提供了简单的接口,比如设置优先级,取消请求等。
如何使用Fast Android Networking:
build.gradle
compile 'com.amitshekhar.android:android-networking:0.2.0'
发起GET请求
AndroidNetworking.get("http://api.localhost.com/{pageNumber}/test")
.addPathParameter("pageNumber", "0") //参数
.addQueryParameter("limit", "3") //参数
.addHeaders("token", "1234") //请求头
.setTag("test") //相当于名字
.setPriority(Priority.LOW)
.build()
.getAsJSONArray(new JSONArrayRequestListener() {
@Override
public void onResponse(JSONArray response) {
// do anything with response
}
@Override
public void onError(ANError error) {
// handle error
}
});
发起POST请求
AndroidNetworking.post("http://api.localhost.com/createAnUser")
.addBodyParameter("firstname", "Amit") //参数
.addBodyParameter("lastname", "Shekhar") //参数
.setTag("test") //名字
.setPriority(Priority.MEDIUM) //类型
.build()
.getAsJSONArray(new JSONArrayRequestListener() {
@Override
public void onResponse(JSONArray response) {
// do anything with response
}
@Override
public void onError(ANError error) {
// handle error
}
});
和JAVA对象一起使用 - JSON Parser
/*--------------Example One -> Getting the userList----------------*/
AndroidNetworking.get("http://api.localhost.com/getAllUsers/{pageNumber}")
.addPathParameter("pageNumber", "0")
.addQueryParameter("limit", "3")
.setTag(this)
.setPriority(Priority.LOW)
.build()
//与实体类结合 注意Gosn转换的类型
.getAsParsed(new TypeToken<List<User>>() {}, new ParsedRequestListener<List<User>>() {
@Override
public void onResponse(List<User> users) {
// do anything with response
Log.d(TAG, "userList size : " + users.size());
for (User user : users) {
Log.d(TAG, "id : " + user.id);
Log.d(TAG, "firstname : " + user.firstname);
Log.d(TAG, "lastname : " + user.lastname);
}
}
@Override
public void onError(ANError anError) {
// handle error
}
});
/*--------------Example Two -> Getting an user----------------*/
AndroidNetworking.get("http://api.localhost.com/getAnUser/{userId}")
.addPathParameter("userId", "1")
.setTag(this)
.setPriority(Priority.LOW)
.build()
.getAsParsed(new TypeToken<User>() {}, new ParsedRequestListener<User>() {
@Override
public void onResponse(User user) {
// do anything with response
Log.d(TAG, "id : " + user.id);
Log.d(TAG, "firstname : " + user.firstname);
Log.d(TAG, "lastname : " + user.lastname);
}
@Override
public void onError(ANError anError) {
// handle error
}
});
/*-- Note : TypeToken and getAsParsed is important here --*/
从服务器下载一个文件
AndroidNetworking.download(url,dirPath,fileName)
.setTag("downloadTest")
.setPriority(Priority.MEDIUM)
.build()
.setDownloadProgressListener(new DownloadProgressListener() {
@Override
public void onProgress(long bytesDownloaded, long totalBytes) {
// do anything with progress
}
})
.startDownload(new DownloadListener() {
@Override
public void onDownloadComplete() {
// do anything after completion
}
@Override
public void onError(ANError error) {
// handle error
}
});
上传一个文件
AndroidNetworking.upload(url)
.addMultipartFile("image",file)
.setTag("uploadTest")
.setPriority(Priority.IMMEDIATE)
.build()
.setUploadProgressListener(new UploadProgressListener() {
@Override
public void onProgress(long bytesUploaded, long totalBytes) {
// do anything with progress
}
})
.getAsJSONObject(new JSONObjectRequestListener() {
@Override
public void onResponse(JSONObject response) {
// do anything with response
}
@Override
public void onError(ANError error) {
// handle error
}
});
得到一个响应并在另一个线程executor中完成
(注 : 错误和进度总是在主线程中返回)
AndroidNetworking.upload(url)
.addMultipartFile("image",file)
.setTag("uploadTest")
.setPriority(Priority.IMMEDIATE)
.build()
.setExecutor(Executors.newSingleThreadExecutor()) // setting an executor to get response or completion on that executor thread
.setUploadProgressListener(new UploadProgressListener() {
@Override
public void onProgress(long bytesUploaded, long totalBytes) {
// do anything with progress
}
})
.getAsJSONObject(new JSONObjectRequestListener() {
@Override
public void onResponse(JSONObject response) {
// below code will be executed in the executor provided
// do anything with response
}
@Override
public void onError(ANError error) {
// handle error
}
});
取消一个请求
任何一个指定了tag的请求都可以被取消。
AndroidNetworking.cancel("tag");//这个就是那个名字
把从网络加载的图片放到ImageView
<com.androidnetworking.widget.ANImageView
android:id="@+id/imageView"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center" />
imageView.setDefaultImageResId(R.drawable.default);
imageView.setErrorImageResId(R.drawable.error);
imageView.setImageUrl(imageUrl);
从url获取指定了一些参数的Bitmap
AndroidNetworking.get(imageUrl)
.setTag("imageRequestTag")
.setPriority(Priority.MEDIUM)
.setBitmapMaxHeight(100)
.setBitmapMaxWidth(100)
.setBitmapConfig(Bitmap.Config.ARGB_8888)
.build()
.getAsBitmap(new BitmapRequestListener() {
@Override
public void onResponse(Bitmap bitmap) {
// do anything with bitmap
}
@Override
public void onError(ANError error) {
// handle error
}
});
预取请求(以便它可以在需要时立即从缓存中返回)
AndroidNetworking.get(ApiEndPoint.BASE_URL + ApiEndPoint.GET_JSON_ARRAY)
.addPathParameter("pageNumber", "0")
.addQueryParameter("limit", "30")
.setTag(this)
.setPriority(Priority.LOW)
.build()
.prefetch();
为某个请求自定义OkHttpClient
OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
.addInterceptor(new GzipRequestInterceptor())
.build();
AndroidNetworking.get("http://api.localhost.com/{pageNumber}/test")
.addPathParameter("pageNumber", "0")
.addQueryParameter("limit", "3")
.addHeaders("token", "1234")
.setTag("test")
.setPriority(Priority.LOW)
.setOkHttpClient(okHttpClient) // passing a custom okHttpClient
.build()
.getAsJSONArray(new JSONArrayRequestListener() {
@Override
public void onResponse(JSONArray response) {
// do anything with response
}
@Override
public void onError(ANError error) {
// handle error
}
});
用ConnectionClass Listener得到当前网络质量和带宽
// Adding Listener
AndroidNetworking.setConnectionQualityChangeListener(new ConnectionQualityChangeListener() {
@Override
public void onChange(ConnectionQuality currentConnectionQuality, int currentBandwidth) {
// do something on change in connectionQuality
}
});
// Removing Listener
AndroidNetworking.removeConnectionQualityChangeListener();
// Getting current ConnectionQuality
ConnectionQuality connectionQuality = AndroidNetworking.getCurrentConnectionQuality();
if(connectionQuality == ConnectionQuality.EXCELLENT){
// do something
}else if (connectionQuality == ConnectionQuality.POOR){
// do something
}else if (connectionQuality == ConnectionQuality.UNKNOWN){
// do something
}
// Getting current bandwidth
int currentBandwidth = AndroidNetworking.getCurrentBandwidth(); // Note : if (currentBandwidth == 0)
通过在请求上设置分析器来获取对请求的
AndroidNetworking.download(url,dirPath,fileName)
.setTag("downloadTest")
.setPriority(Priority.MEDIUM)
.build()
.setAnalyticsListener(new AnalyticsListener() {
@Override
public void onReceived(long timeTakenInMillis, long bytesSent, long bytesReceived, boolean isFromCache) {
Log.d(TAG, " timeTakenInMillis : " + timeTakenInMillis);
Log.d(TAG, " bytesSent : " + bytesSent);
Log.d(TAG, " bytesReceived : " + bytesReceived);
Log.d(TAG, " isFromCache : " + isFromCache);
}
})
.setDownloadProgressListener(new DownloadProgressListener() {
@Override
public void onProgress(long bytesDownloaded, long totalBytes) {
// do anything with progress
}
})
.startDownload(new DownloadListener() {
@Override
public void onDownloadComplete() {
// do anything after completion
}
@Override
public void onError(ANError error) {
// handle error
}
});
Note : If bytesSent or bytesReceived is -1 , it means it is unknown
和RxJava一起使用Fast Android Networking请看这里。
package com.kunminx.samples.ui.networking;
import android.os.Bundle;
import android.util.Log;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.kunminx.samples.R;
import com.kunminx.samples.databinding.FragmentNetworkingBinding;
import com.kunminx.samples.model.ApiUser;
import com.kunminx.samples.model.User;
import com.kunminx.samples.model.UserDetail;
import com.kunminx.samples.utils.Utils;
import com.rx2androidnetworking.Rx2AndroidNetworking;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.BiFunction;
import io.reactivex.functions.Function;
import io.reactivex.functions.Predicate;
import io.reactivex.schedulers.Schedulers;
/**
* Created by amitshekhar on 04/02/17.
*/
public class NetworkingFragment extends Fragment {
public static final String TAG = NetworkingFragment.class.getSimpleName();
private FragmentNetworkingBinding mBinding;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_networking, container, false);
mBinding = FragmentNetworkingBinding.bind(view);
mBinding.setClickProxy(new ClickProxy());
return view;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
private Observable<List<User>> getCricketFansObservable() {
return Rx2AndroidNetworking.get("https://fierce-cove-29863.herokuapp.com/getAllCricketFans")
.build()
.getObjectListObservable(User.class);
}
/*
* This observable return the list of User who loves Football
*/
private Observable<List<User>> getFootballFansObservable() {
return Rx2AndroidNetworking.get("https://fierce-cove-29863.herokuapp.com/getAllFootballFans")
.build()
.getObjectListObservable(User.class);
}
/*
* This do the complete magic, make both network call
* and then returns the list of user who loves both
* Using zip operator to get both response at a time
*/
private void findUsersWhoLovesBoth() {
// here we are using zip operator to combine both request
Observable.zip(getCricketFansObservable(), getFootballFansObservable(),
new BiFunction<List<User>, List<User>, List<User>>() {
@Override
public List<User> apply(List<User> cricketFans, List<User> footballFans) {
List<User> userWhoLovesBoth =
filterUserWhoLovesBoth(cricketFans, footballFans);
return userWhoLovesBoth;
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<User>>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(List<User> users) {
// do anything with user who loves both
Log.d(TAG, "userList size : " + users.size());
for (User user : users) {
Log.d(TAG, "user : " + user.toString());
}
}
@Override
public void onError(Throwable e) {
Utils.logError(TAG, e);
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
});
}
private List<User> filterUserWhoLovesBoth(List<User> cricketFans, List<User> footballFans) {
List<User> userWhoLovesBoth = new ArrayList<>();
for (User footballFan : footballFans) {
if (cricketFans.contains(footballFan)) {
userWhoLovesBoth.add(footballFan);
}
}
return userWhoLovesBoth;
}
private Observable<List<User>> getAllMyFriendsObservable() {
return Rx2AndroidNetworking.get("https://fierce-cove-29863.herokuapp.com/getAllFriends/{userId}")
.addPathParameter("userId", "1")
.build()
.getObjectListObservable(User.class);
}
private Observable<List<User>> getUserListObservable() {
return Rx2AndroidNetworking.get("https://fierce-cove-29863.herokuapp.com/getAllUsers/{pageNumber}")
.addPathParameter("pageNumber", "0")
.addQueryParameter("limit", "10")
.build()
.getObjectListObservable(User.class);
}
private Observable<UserDetail> getUserDetailObservable(long id) {
return Rx2AndroidNetworking.get("https://fierce-cove-29863.herokuapp.com/getAnUserDetail/{userId}")
.addPathParameter("userId", String.valueOf(id))
.build()
.getObjectObservable(UserDetail.class);
}
public class ClickProxy {
public void map() {
Rx2AndroidNetworking.get("https://fierce-cove-29863.herokuapp.com/getAnUser/{userId}")
.addPathParameter("userId", "1")
.build()
.getObjectObservable(ApiUser.class)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(new Function<ApiUser, User>() {
@Override
public User apply(ApiUser apiUser) {
// here we get ApiUser from server
User user = new User(apiUser);
// then by converting, we are returning user
return user;
}
})
.subscribe(new Observer<User>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(User user) {
Log.d(TAG, "user : " + user.toString());
}
@Override
public void onError(Throwable e) {
Utils.logError(TAG, e);
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
});
}
public void zip() {
findUsersWhoLovesBoth();
}
public void flatMapAndFilter() {
getAllMyFriendsObservable()
.flatMap(new Function<List<User>, ObservableSource<User>>() { // flatMap - to return users one by one
@Override
public ObservableSource<User> apply(List<User> usersList) {
return Observable.fromIterable(usersList); // returning user one by one from usersList.
}
})
.filter(new Predicate<User>() {
@Override
public boolean test(User user) {
// filtering user who follows me.
return user.isFollowing;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<User>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(User user) {
// only the user who is following me comes here one by one
Log.d(TAG, "user : " + user.toString());
}
@Override
public void onError(Throwable e) {
Utils.logError(TAG, e);
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
});
}
public void take() {
getUserListObservable()
.flatMap(new Function<List<User>, ObservableSource<User>>() { // flatMap - to return users one by one
@Override
public ObservableSource<User> apply(List<User> usersList) {
return Observable.fromIterable(usersList); // returning user one by one from usersList.
}
})
.take(4) // it will only emit first 4 users out of all
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<User>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(User user) {
// // only four user comes here one by one
Log.d(TAG, "user : " + user.toString());
}
@Override
public void onError(Throwable e) {
Utils.logError(TAG, e);
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
});
}
public void flatMap() {
getUserListObservable()
.flatMap(new Function<List<User>, ObservableSource<User>>() { // flatMap - to return users one by one
@Override
public ObservableSource<User> apply(List<User> usersList) {
return Observable.fromIterable(usersList); // returning user one by one from usersList.
}
})
.flatMap(new Function<User, ObservableSource<UserDetail>>() {
@Override
public ObservableSource<UserDetail> apply(User user) {
// here we get the user one by one
// and returns corresponding getUserDetailObservable
// for that userId
return getUserDetailObservable(user.id);
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<UserDetail>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onError(Throwable e) {
Utils.logError(TAG, e);
}
@Override
public void onNext(UserDetail userDetail) {
// do anything with userDetail
Log.d(TAG, "userDetail : " + userDetail.toString());
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
});
}
public void flatMapWithZip() {
getUserListObservable()
.flatMap(new Function<List<User>, ObservableSource<User>>() { // flatMap - to return users one by one
@Override
public ObservableSource<User> apply(List<User> usersList) {
return Observable.fromIterable(usersList); // returning user one by one from usersList.
}
})
.flatMap(new Function<User, ObservableSource<Pair<UserDetail, User>>>() {
@Override
public ObservableSource<Pair<UserDetail, User>> apply(User user) {
// here we get the user one by one and then we are zipping
// two observable - one getUserDetailObservable (network call to get userDetail)
// and another Observable.just(user) - just to emit user
return Observable.zip(getUserDetailObservable(user.id),
Observable.just(user),
new BiFunction<UserDetail, User, Pair<UserDetail, User>>() {
@Override
public Pair<UserDetail, User> apply(UserDetail userDetail, User user) {
// runs when network call completes
// we get here userDetail for the corresponding user
return new Pair<>(userDetail, user); // returning the pair(userDetail, user)
}
});
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Pair<UserDetail, User>>() {
@Override
public void onComplete() {
// do something onCompleted
Log.d(TAG, "onComplete");
}
@Override
public void onError(Throwable e) {
// handle error
Utils.logError(TAG, e);
}
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Pair<UserDetail, User> pair) {
// here we are getting the userDetail for the corresponding user one by one
UserDetail userDetail = pair.first;
User user = pair.second;
Log.d(TAG, "user : " + user.toString());
Log.d(TAG, "userDetail : " + userDetail.toString());
}
});
}
}
}
只是用法 都有注释