AsyncHttp是目前使用较为多的数据请求框架,
官网地址:> http://loopj.com/android-async-http/
1. 概念:
这个网络请求库是基于Apache HttpClient库之上的一个异步网络请求处理库,网络处理均基于Android的非UI线程,通过回调方法(匿名内部类)处理请求结果。
2. 特征:
(1).处理异步Http请求,并通过匿名内部类处理回调结果
(2).Http异步请求均位于非UI线程,不会阻塞UI操作。
(3).通过线程池处理并发请求处理文件上传、下载,响应结果自动打包JSON格式。
3. 相应的核心类的介绍:
(1).AsyncHttpResponseHandler:请求返回处理成功、失败、开始、完成等自定义的消息的类。
(2).BinaryHttpResponseHandler:AsyncHttpResponseHandler的子类。该类是一个字节流返回处理的类。用于处理图片等。
(3).JsonHttpResponseHandler:AsyncHttpResponseHandler的子类。这是一个服务器与客户端之间用Json数据交流时使用的类。客户端请求服务器的参数是Json数据类型的,服务器返回给客户端的数据也是Json数据类型的。
(4).RequestParams:封装参数处理的类。将客户端请求的参数封装在该类中。
(5).AsyncHttpClient:异步客户端请求的类。
(6).SyncHttpClient:同步客户端请求的类。AsyncHttpClient的子类。
使用该类的时候需注意:studio中需要在build.gradle添加以下代码时的位置容易弄错,注实在app下的build.greale中添加,最好是调成project格式好辨认
dependencies {
compile 'com.loopj.android:android-async-http:1.4.9'
}
简单介绍用法:
AsyncHttpClient client = new AsyncHttpClient();
//第一种JsonHttpResponseHandler是用来进行下载并处理JSON文件
client.get(url, new JsonHttpResponseHandler("utf-8") {
@Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
super.onSuccess(statusCode, headers, response);
}
@Override
public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
super.onFailure(statusCode, headers, responseString, throwable);
}
});
//第二种AsyncHttpResponseHandler用来下载数据并传换成字节
client.get(url, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
}
});
//第三种FileAsyncHttpResponseHandler(file)用来将下载数据直接保存到指定文件file中
//File to store response within, must not be null
client.get(url, new FileAsyncHttpResponseHandler(new File("/")) {
@Override
public void onFailure(int statusCode, Header[] headers, Throwable throwable, File file) {
}
@Override
public void onSuccess(int statusCode, Header[] headers, File file) {
}
});
//以上三种当请求成功后,都在success中进行最后的数据处理
那当我们将数据下载完了,不想保存到文件,而是想在调用的地方就能得到下载的数据,如何实现呢?
这就是封装是会遇到的问题,个人使用的是接口回调,在封装的时候个人觉得下载东西就应给有一个通知或者进度条的明显提示,所以在下面的代码中我会使用到通知栏,和界面的进度条提示,个人由于工作需要所以是下载了一个apk进行安装;各位可以下载字符串等其他信息测试
对AsyncHttp请求的封装类;
public class XxxUtils {
boolean flag = true;
private ValueInterface vi;
private RequestValues rv;
private MainActivity mainActivity;
private ProgressDialog dialog;
private ProgressBar progress, progress2;
private TextView tvMsg;
private Notification notification;
private RemoteViews contentView;
private NotificationManager notificationManager;
public XxxUtils(Context context) {
if (context instanceof ValueInterface) {
vi = (ValueInterface) context;
}
if (context instanceof MainActivity) {
mainActivity = (MainActivity) context;
dialog = new ProgressDialog(mainActivity);
}
progress = (ProgressBar) mainActivity.findViewById(R.id.pb_pro);
progress2 = (ProgressBar) mainActivity.findViewById(R.id.pb_pro2);
tvMsg = (TextView) mainActivity.findViewById(R.id.tv_msg);
}
//此方法是将下载的数据写入到文件中,当然使用了接口回调此数据一样可以在调用处获得
public void putFile(String url, final String director, final String fileName) {
rv = new RequestValues();
AsyncHttpClient client = new AsyncHttpClient();
client.setResponseTimeout(5000);
client.setConnectTimeout(5000);
RequestHandle requestHandle = client.get(url, new AsyncHttpResponseHandler() {
@Override
public void onStart() {
super.onStart();
createNotification();
}
@Override
public void onProgress(long bytesWritten, long totalSize) {
super.onProgress(bytesWritten, totalSize);
int downCount = (int) (bytesWritten * 100 / totalSize);
tvMsg.setText((int) (bytesWritten * 100 / totalSize) + "%");
progress.setMax((int) totalSize);
progress.setProgress((int) bytesWritten);
mainActivity.setProgressBarIndeterminateVisibility(true);
// 改变通知栏
contentView.setTextViewText(R.id.notificationPercent, downCount + "%");
contentView.setProgressBar(R.id.notificationProgress, 100, downCount, false);
notification.contentView = contentView;
notificationManager.notify(R.layout.test_notification_item, notification);
}
@Override
public void onPostProcessResponse(ResponseHandlerInterface instance, HttpResponse response) {
super.onPostProcessResponse(instance, response);
}
@Override
public void onFinish() {
super.onFinish();
notificationManager.cancel(R.layout.test_notification_item);
}
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
boolean file = XxxxFile.createFile(director, fileName);
if (file) {
Log.i("TAG", "file status=" + file);
Log.i("TAG", "file path=" + XxxxFile.file2.getAbsolutePath());
ByteArrayInputStream bais = null;
FileOutputStream fos = null;
try {
bais = new ByteArrayInputStream(responseBody);
fos = new FileOutputStream(new File(director + "/" + fileName));
int len;
byte[] bytes = new byte[1024];
while ((len = bais.read(bytes)) != -1) {
fos.write(bytes, 0, len);
fos.flush();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
rv.setStatus(StatusFlag.FILEOPERATEFAILURE);
rv.setRequestMsg(e.getMessage());
vi.onFailured(rv);
dialog.dismiss();
} catch (IOException e) {
e.printStackTrace();
rv.setStatus(StatusFlag.FILEOPERATEFAILURE);
rv.setRequestMsg(e.getMessage());
vi.onFailured(rv);
dialog.dismiss();
} finally {
if (fos != null) {
try {
fos.close();
bais.close();
} catch (IOException e) {
e.printStackTrace();
rv.setStatus(StatusFlag.FILEOPERATEFAILURE);
rv.setRequestMsg(e.getMessage());
vi.onFailured(rv);
dialog.dismiss();
}
}
}
Log.i("TAG", "chenggong ");
//请求成功后,在这里我们就可以使用接口回调的方法将数据传出
rv.setStatus(StatusFlag.REQUESTSUCCESS);
vi.onSuccessed(rv);
dialog.dismiss();
} else {
rv.setStatus(StatusFlag.CREATEFILEFAILURE);
rv.setRequestMsg("Create file failure");
vi.onFailured(rv);
}
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
rv.setStatus(StatusFlag.REQUESTFAILURE);
rv.setRequestMsg(responseBody.toString());
vi.onFailured(rv);
}
});
}
//此方法是用来返回下载的数据
public void getData(String url) {
rv = new RequestValues();
AsyncHttpClient client = new AsyncHttpClient();
client.setResponseTimeout(5000);
client.setConnectTimeout(5000);
client.get(url, new AsyncHttpResponseHandler() {
@Override
public void onStart() {
super.onStart();
dialog.setTitle("提示信息");
dialog.setMessage("数据请求中......");
dialog.show();
}
@Override
public void onFinish() {
super.onFinish();
dialog.dismiss();
}
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
if (statusCode == 200) {
ByteArrayInputStream bais = null;
ByteArrayOutputStream baos = null;
try {
bais = new ByteArrayInputStream(responseBody);
baos = new ByteArrayOutputStream();
int len;
byte[] bytes = new byte[1024];
while ((len = bais.read(bytes)) != -1) {
baos.write(bytes, 0, len);
baos.flush();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
rv.setStatus(StatusFlag.FILEOPERATEFAILURE);
rv.setRequestMsg(e.getMessage());
vi.onFailured(rv);
} catch (IOException e) {
e.printStackTrace();
rv.setStatus(StatusFlag.FILEOPERATEFAILURE);
rv.setRequestMsg(e.getMessage());
vi.onFailured(rv);
} finally {
if (baos != null) {
try {
bais.close();
baos.close();
} catch (IOException e) {
e.printStackTrace();
rv.setStatus(StatusFlag.FILEOPERATEFAILURE);
rv.setRequestMsg(e.getMessage());
vi.onFailured(rv);
}
}
}
Log.i("TAG", "success ");
if (baos.toString() != null) {
//请求成功后,在这里我们就可以使用接口回调的方法将数据传出
rv.setStatus(StatusFlag.REQUESTSUCCESS);
rv.setRequestMsg(baos.toString());
vi.onSuccessed(rv);
} else {
rv.setStatus(StatusFlag.REQUESTFAILURE);
rv.setRequestMsg("ByteArrayOutputStream write failure");
vi.onFailured(rv);
}
} else {
rv.setStatus(StatusFlag.REQUESTFAILURE);
rv.setRequestMsg("internet commication failure");
vi.onFailured(rv);
}
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
Log.i("TAG", "onFailure______failure ");
rv.setStatus(StatusFlag.REQUESTFAILURE);
rv.setRequestMsg(error.getMessage());
vi.onFailured(rv);
}
});
}
public void createNotification() {
notification = new Notification(R.mipmap.ic_launcher, mainActivity.getPackageName() + "正在下载",
System.currentTimeMillis());
notification.flags = Notification.FLAG_ONGOING_EVENT;
// 自定义 Notification 的显示
contentView = new RemoteViews(mainActivity.getPackageName(), R.layout.test_notification_item);
contentView.setTextViewText(R.id.notificationTitle, mainActivity.getPackageName() + "正在下载");
contentView.setTextViewText(R.id.notificationPercent, "0%");
contentView.setProgressBar(R.id.notificationProgress, 100, 0, false);
notification.contentView = contentView;
notificationManager = (NotificationManager) mainActivity.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(R.layout.test_notification_item, notification);
}
}
自定义的通知的布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#cccccc"
android:layout_height="match_parent">
<ImageView
android:id="@+id/notificationImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@android:drawable/stat_sys_download"
android:paddingLeft="16dp"/>
<TextView
android:id="@+id/notificationTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_toRightOf="@id/notificationImage"
android:paddingLeft="26dp"
android:textColor="#FFFFFFFF" />
<!-- android:textColor="#FF000000" -->
<TextView
android:id="@+id/notificationPercent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/notificationImage"
android:paddingTop="2dp"
android:textColor="#FFFFFFFF"
android:paddingLeft="16dp"/>
<ProgressBar
android:id="@+id/notificationProgress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/notificationTitle"
android:layout_alignParentRight="true"
android:layout_alignTop="@id/notificationPercent"
android:layout_below="@id/notificationTitle"
android:paddingLeft="26dp"
android:paddingRight="3dp"
android:paddingTop="2dp"
android:indeterminate="false" />
</RelativeLayout>
MainActivity文件中,我们实现我们定义的接口实现接口中的方法,onSuccessd(),onFailured();并在和两个方法中进行处理下载完的数据,经验之谈,不适用接口回调也可以实现数据的获取,比如在封装的类中加入一个标志属性,这个方法用起来不好,如果你直接调用这个属性的get()方法你得到的值会是他的初始值,因为当你使用AsyncHttp时,这是个异步任务,所以当你调用封装的其中一个方法后,就用这个标志属性进行判断是否请求成功时,你得到的值适合这个请求无关的值,他们并不在一个线程中执行,也就是没有先后,所以你得标志属性值是你的初始值,当然你也可以使用timer将获取标志属性的值的方法延后几秒钟,这个方法可行,当时不推荐使用,不可靠,
public class MainActivity extends Activity implements ValueInterface{
public final String save_url = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Louyx/";
String saveUrl=Environment.getExternalStorageDirectory().getAbsolutePath();
private String url="http://192.168.56.1:8080/apk/SoftkeyApp-debug.apk";
private TextView tvMsg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvMsg = (TextView) findViewById(R.id.tv_msg);
method2();
// method3();
}
@Override
protected void onDestroy() {
super.onDestroy();
if(XxxxFile.delFile(new File(save_url))){
Log.i("TAG", "delete file seccess");
}
}
public void method2(){
Log.i("TAG", "method2");
final XxxUtils3 utils = new XxxUtils3(this);
utils.putFile(url, save_url, "SoftkeyApp.apk");
}
public void method3(){
Log.i("TAG","method3");
XxxUtils3 utils3 = new XxxUtils3(this);
utils3.getData("http://192.168.56.1:8080/apk/Texts.txt");
}
@Override
public void onSuccessed(RequestValues str) {
if(str.getStatus()==StatusFlag.REQUESTSUCCESS){
Log.i("TAG", "onSuccessed" + str);
// tvMsg.setText(str.getRequestMsg());
File file = new File(save_url+"/"+"SoftkeyApp.apk");
Log.i("TAG", "aaaaaaa");
try {
if (file.exists()) {
Log.i("TAG", "bbbbbb");
Uri uri = Uri.fromFile(file);
Intent intent2 = new Intent(Intent.ACTION_VIEW);
intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent2.setDataAndType(uri, "application/vnd.android.package-archive");
MainActivity.this.startActivity(intent2);
}
}catch (Exception e){
e.printStackTrace();
Log.i("TAG", "install apk failure");
Toast.makeText(this,"install apk failure",Toast.LENGTH_SHORT).show();
}
}
}
@Override
public void onFailured(RequestValues str) {
switch (str.getStatus()){
case StatusFlag.REQUESTFAILURE:
Log.i("TAG",str.getRequestMsg());
break;
case StatusFlag.CREATEFILEFAILURE:
Log.i("TAG",str.getRequestMsg());
break;
case StatusFlag.FILEOPERATEFAILURE:
Log.i("TAG",str.getRequestMsg());
break;
}
}
}
定义的接口:
public interface ValueInterface {
public void onSuccessed(RequestValues str);
public void onFailured(RequestValues str);
}
mainactivity的布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.louyx.asynchttputils.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<!-- 定义滚动条
sytle滚动条样式:progressBarStyleHorizontal一个长条形
max 滚动条最大值
progress 滚动条当前值
visibility 是否可见
-->
<ProgressBar
android:id="@+id/pb_pro"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/tv_msg"
android:maxHeight="48dp"
android:minHeight="48dp"
android:progress="0"
android:visibility="visible"
android:layout_weight="3"
/>
<TextView
android:paddingLeft="5dp"
android:id="@+id/tv_msg"
android:layout_width="0dp"
android:layout_weight="1"
android:gravity="center"
android:layout_height="match_parent"
android:text="fdsafds"/>
</LinearLayout>
<!-- 定义滚动条
sytle滚动条样式:progressBarStyleLarge一个大圆形样式
-->
<ProgressBar
android:id="@+id/pb_pro2"
style="?android:attr/progressBarStyleLarge"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/pb_pro"
android:progress="0"
android:visibility="visible" />
<!-- 定义一个标题栏的滚动条
-->
<ProgressBar
android:id="@+id/firstBar3"
style="?android:attr/progressBarStyleSmallTitle"
android:layout_width="200dp"
android:layout_height="wrap_content"/>
</LinearLayout>
运行图: