个人是在看郭神的第一行代码时知道的可以自己做一个HttpUtil类来方便Http的通信,只需要直接用工具类里的方法进行获得Response即可了。
这里写出我自己在制作HttpUtil类时用到的不同的方法(布局的话都是一个EditText,一个按钮一个文本框,没什么特别的就不贴出来了),本文偏向于使用AsyncTask进行异步调用,先放一下效果吧。
这里也因为速度太快了ProgressBar几乎看不到了...以下就是做法了。
1.HttpURLConnection+接口回调(书上的做法,也就是我这里写的第一种方法,用接口回调的方法进行Ui的变换):
HttpCallBackListener接口:
public interface HttpCallBackListener{
void onFinish(String response);
void onError(Exception e);
}
HttpUtil.java工具类:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
class HttpUtil {
static void sendHttpRequest(final String address, final HttpCallBackListener listener){
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection conn = null;
BufferedReader br = null;
try {
URL url = new URL(address);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(8000);
conn.setReadTimeout(8000);
InputStream in = conn.getInputStream();
br = new BufferedReader(new InputStreamReader(in));
String line;
StringBuffer response = new StringBuffer();
while((line = br.readLine())!=null){
response.append(line);
}
if(listener != null){
listener.onFinish(response.toString());
}
} catch (Exception e) {
if(listener != null){
listener.onError(e);
}
}finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (conn != null) {
conn.disconnect();
}
}
}
}).start();
}
}
MainActivity.java:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
EditText et_request;
Button btn_request;
TextView tv_response;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//各控件的初始化
init();
}
private void init() {
et_request = findViewById(R.id.et_request);
btn_request = findViewById(R.id.btn_request);
tv_response = findViewById(R.id.tv_response);
btn_request.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_request :
sendRequest();
}
}
private void sendRequest() {
HttpUtil.sendHttpRequest(et_request.getText().toString(), new HttpCallBackListener() {
@Override
public void onFinish(String response) {
tv_response.setText(response);
}
@Override
public void onError(Exception e) {
Log.e("onError: ", e.toString());
}
});
}
}
虽然郭神书上就是用的这个方法,但是这个方法会抛出错误异常:
在真机测试时也会卡住好一会儿,很简单也很直白的提示了,跳过了96帧,有可能在主线程做了较为耗时的操作,但是这些操作又不至于到使程序达到ANR的地步。
这是实际上仍然在主线程中进行了耗时工作,可能是因为百度主页的内容太多了,但是更重要的是这种耗时操作不应该放置到主线程中进行,所以我也用runOnUiThread的方式对sendRequest()做了一点点修改:
private void sendRequest() {
HttpUtil.sendHttpRequest(et_request.getText().toString(), new HttpCallBackListener() {
@Override
public void onFinish(final String response) {
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_response.setText(response);
}
});
}
@Override
public void onError(Exception e) {
Log.e("onError: ", e.toString());
}
});
}
实际上就是把操作放进了runOnUiThread方法里,让他在Ui线程中进行耗时操作,这样就避免了ANR错误的风险,也不会报错。这种接口回调的方法其实还是用Handler或者别的来处理比较好啊,不过用AsyncTask的话就基本不用接口回调这么麻烦了。
2.HttpURLConnection+AsyncTask的方式
HttpUtil:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
class HttpUtil {
static String sendHttpRequest(String address){
HttpURLConnection conn = null;
BufferedReader br = null;
StringBuffer response = null;
try {
URL url = new URL(address);
conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(8000);
conn.setReadTimeout(8000);
InputStream in = conn.getInputStream();
br = new BufferedReader(new InputStreamReader(in));
String line;
response = new StringBuffer();
while((line = br.readLine())!=null){
response.append(line);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (conn != null) {
conn.disconnect();
}
}
return response.toString();
}
}
MainActivity:
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
EditText et_request;
Button btn_request;
TextView tv_response;
ProgressBar pb_request;
//自定义的AsyncTask类
class MyAsyncTask extends AsyncTask<Void, Void, String>{
@Override
protected void onPreExecute() {
//在进行http访问前给进度条可视化
pb_request.setVisibility(View.VISIBLE);
}
@Override
protected String doInBackground(Void... voids) {
return HttpUtil.sendHttpRequest(et_request.getText().toString());
}
@Override
protected void onPostExecute(String s) {
//获得response后先隐藏进度条再在Textview中显示response信息
pb_request.setVisibility(View.GONE);
tv_response.setText(s);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//各控件的初始化
init();
}
private void init() {
et_request = findViewById(R.id.et_request);
btn_request = findViewById(R.id.btn_request);
tv_response = findViewById(R.id.tv_response);
pb_request = findViewById(R.id.pb_request);
btn_request.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_request :
new MyAsyncTask().execute();
}
}
}
有了AsyncTask的包装后,所有的耗时操作只要在doInBackground做就完事了!虽然还是要在Main活动中创建AsyncTask类来进行,但其实操作起来还是蛮简单的,而且还有可以便于做进度条显示隐藏,十分的人性化。
按道理来说既然AsyncTask可以的话Handler也可以这样做的,不过没试过也暂时不太想尝试因为AsyncTask包装起来用着就很舒服...
以上两种都是用HttpURLConnection来进行Http访问的,如果把他们换成Okhttp的话说不定会更加方便,但是郭神书上用Okhttp实际上也是用的okhttp中自带的callback来进行接口回调,在回调中依然是不能进行UI更改操作的,于是我沿用第二种方法稍微改变用okhttp进行通信,便得到更方便的用法:
3.AsyncTask+Okhttp的方式
首先要记得在APP声明依赖:
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
OkHttpUtil:
import java.io.IOException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class OkHttpUtil {
public static String sendOkHttpRequest(String address){
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(address).build();
try {
Response response = client.newCall(request).execute();
String data = response.body().string();
return data;
} catch (IOException e) {
return e.toString();
}
}
}
MainActivity:
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
EditText et_request;
Button btn_request;
TextView tv_response;
ProgressBar pb_request;
class MyAsyncTask extends AsyncTask<Void, Void, String> {
@Override
protected void onPreExecute() {
pb_request.setVisibility(View.VISIBLE);
}
@Override
protected String doInBackground(Void... voids) {
return OkHttpUtil.sendOkHttpRequest(et_request.getText().toString());
}
@Override
protected void onPostExecute(String s) {
pb_request.setVisibility(View.GONE);
tv_response.setText(s);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//各控件的初始化
init();
}
private void init() {
et_request = findViewById(R.id.et_request);
btn_request = findViewById(R.id.btn_request);
tv_response = findViewById(R.id.tv_response);
pb_request = findViewById(R.id.pb_request);
btn_request.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_request :
new MyAsyncTask().execute();
}
}
}
这样既能方便快捷的进行http访问取回数据又能方便的进行Ui操作啦。我个人是比较偏向用这种方法的。
本文偏向于使用AsyncTask进行异步调用因为是真的太方便了,实际上
1) 自开线程new Thread;2) runOnUIThread; 3) post方法
都是可以解决问题的,只是在这里就不详细的写了。
第一次写博客,有错误或者不足之处希望能提出来,请多多指教啦。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)