Java的接口回掉机制是个好东西,无论是线程之间的数据传递还是Activity与Fragment之间的数据传递都可能会用到接口回掉,于是做了一个关于线程之间的接口回掉的小demo,帮助我们简单理解一下接口回掉机制。
github项目源码 https://github.com/MQLX1004/Myhub/tree/master/NetworkTest
demo的大体意思就是从一个网址中获取信息,然后显示到TextView中
网络请求部分需要开启一个子线程,更改UI部分需要在主线程中进行,这样就产生了线程之间如何传递信息的问题,有些人可能会说使用Handler传递一个Message就可以,但是如果我们另外写一个类,这个类专门处理网络请求,就不能使用Handler传递Message了。这时候最好的解决方法就是使用接口回掉。
首先看看我们的界面设计的,界面很简单,就是一个Button一个TextView,点击Button的时候就会开启子线程发送网络请求,然后在TextView中显示请求结果
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/button" android:text="@string/app_name" android:layout_width="match_parent" android:layout_height="50dp"/> <TextView android:id="@+id/textView" android:hint="@string/app_name" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>既然是接口回掉机制就得有一个接口,我们先看看接口是如何写的吧,随后使用的时候就知道它是怎么用的了。
接口中有两个方法,onFinish方法中的参数为请求URL成功后返回的数据。
onError方法中的参数为请求URL失败后返回的错误信息。
public interface HttpCallback { //获取成功调用 void onFinish(String response); //获取失败调用 void onError(Exception e); }然后看一下专门处理网络请求的类,该类只有一个方法,该方法设置为静态方法,这样以后发送网络请求的时候可以直接通过类名调用该方法,方法有两个参数,一个是要请求的URL,一个是刚刚定义的接口。这个接口在调用此方法时已经被重写了,稍后会见到此接口的重写。
public class HttpUtil { public static void sendHttpRequest(final String address,final HttpCallback listener) { new Thread(new Runnable() {//开启子线程 @Override public void run() { HttpURLConnection connection = null; try { URL url = new URL(address); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET");//设置请求方式 connection.setConnectTimeout(8000);//设置链接超时时间 connection.setReadTimeout(8000);//设置读取超时时间 connection.setDoInput(true); connection.setDoOutput(true); InputStream in = connection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line); } listener.onFinish(response.toString());//接口回掉 } catch (Exception e) { e.printStackTrace(); listener.onError(e);//接口回掉 } finally { if (connection != null) { connection.disconnect();//关闭连接 } } } }).start(); } }现在我们的接口也有了,专门处理网络请求的类也有了,只剩下进行网络请求的类了,在这里这个类为MainActivity.java 我们需要在这个类中调用刚刚那个静态类,并重写我们的接口,在onFinish方法中写请求成功后对返回信息的处理逻辑,在onError方法中写请求失败后对返回错误的处理逻辑。
这里也会用到Handler来传递Message,我们这里将发起网络请求的代码独立到一个类中,降低了代码的耦合度,也会使网络请求更加简便。
import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends AppCompatActivity { public static final int SHOW=0; private Button mButton; private TextView mTextView; private Handler mHandler=new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case SHOW: String respone=(String)msg.obj; mTextView.setText(respone); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton=(Button)findViewById(R.id.button); mTextView=(TextView)findViewById(R.id.textView); mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { sendrequset();//点击Button后发起网络请求 } }); } private void sendrequset(){ HttpUtil.sendHttpRequest("http://10.0.2.2:8080/android/Json.json", new HttpCallback() {//调用网络请求静态类并重写接口中的方法 @Override public void onFinish(String response) { Message message=new Message(); message.what=SHOW; message.obj=response; mHandler.sendMessage(message); } @Override public void onError(Exception e) { e.printStackTrace(); Message message=new Message(); message.what=SHOW; message.obj="获取失败"; mHandler.sendMessage(message); } }); } }
这样整个代码跑起来的大体流程就是:当点击Button后发起网络请求,调用网络请求静态方法,往该方法中传入两个参数,一个是要请求的URL,一个是接口重写后的一个对象,当网络请求成功时调用这个对象的onFinish方法,当网络请求失败时调用这个对象中的onError方法。
如果想要传输图片,只需要在获取InputStream之后转换为Bitmap即可,这样写:
InputStream in = connection.getInputStream(); Bitmap bitmap= BitmapFactory.decodeStream(in);然后改一下接口的onFinish方法中的参数类型,将Stirng改成Bitmap类型,再改一下重写onFinish中的处理逻辑代码就可以了。
public interface HttpCallback { //获取成功调用 void onFinish(Bitmap response); //获取失败调用 void onError(Exception e); }
@Override public void onFinish(Bitmap response) { Message message=new Message(); message.what=SHOW; message.obj=response; mHandler.sendMessage(message); }然后改一下Handler中的处理代码:
private Handler mHandler=new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what){ case SHOW: Bitmap respone=(Bitmap) msg.obj; //mTextView.setText(respone); mImageView.setImageBitmap(respone); } } };这样就完成了图片的传输。