您的位置:首页 > 产品设计 > UI/UE

android使用ExecutorService来处理子线程与UI线程的通讯问题

2016-07-12 14:26 591 查看

android使用ExecutorService来处理子线程与UI线程的通讯问题

写在前面

对于android,为了不阻塞主线程UI的绘制,主线程中不允许有耗时操作,例如网络请求等。如果遇到网络请求,就需要开启子线程去处理请求,子线程得到结果后,再通知主线程更新UI,这就涉及到了android的异步线程处理机制Handler,很多大神对这一块都讲得很透彻了,本文不多赘述。

最近遇到一个需求,需要把子线程定义到方法中,子线程的结果需要作为方法返回值return出来。这样,handler机制实现起来就比较麻烦了。查了一些资料,终于得到了一种解决办法,就是利用ExecutorService来处理子线程和主线程之间的通讯,实现起来比较简单,调用代码很简洁。

废话不多说了,下边写一个demo看看简要的实现过程:

Demo

主要涉及到3个java类,ExecutorService,Callable,Future

ExecutorService是线程池或者叫任务执行者,用来管理分配线程执行任务

Callable<>是一个接口,类似于 Runnable,只有一个有返回值的方法call(),返回的是call的处理结果,泛型是指返回结果的类型

Future是要执行的任务对象,用来具体执行callable中的任务

xml界面

界面很简单,一个button,一个textview

<?xml version="1.0" encoding="utf-8"?>
<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">

<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@android:color/white"
android:text="Hello World!"
android:id="@+id/result"/>

<Button
android:layout_width="match_parent"
android:layout_height="40dp"
android:text="获取网络数据"
android:background="@android:color/holo_blue_light"
android:textColor="@android:color/white"
android:id="@+id/getData"/>

</LinearLayout>


定一个类,实现callable接口,并且重写call方法

call方法中写子线程要执行的动作

public class GetResult implements Callable<String>{

//重写的call方法
@Override
public String call() throws Exception {
//这里我们做一个post请求
return HttpPost.getRequestData(map,url);
}
}


调用callable过程

//创建线程池
ExecutorService pool = Executors.newCachedThreadPool();
//通过submit得到具体执行 call方法的Future任务处理对象
Future f1 = pool.submit(new GetResult());
//调用get()进行任务处理,并得到处理结果
String r=(String)f1.get();


为了方便调用,我们将GetResult类完善一下

定义一个static方法,来获取post请求结果,以便日后调用

public class GetResult implements Callable<String>{

//post请求的参数
private Map<String,String> map=new HashMap<>();
//post请求的接口地址
private String url;

//创建static线程池
//Executors还有多种new线程池的方法,可以参看API根据需要来用
private static ExecutorService pool = Executors.newCachedThreadPool();

//私有构造方法,初始化参数
private GetResult(Map<String,String> map,String url){
this.map=map;
this.url=url;
}

//重写的call方法
@Override
public String call() throws Exception {
return HttpPost.getRequestData(map,url);
}

//静态方法,用于处理post请求,并返回处理结果
public static String getResult(Map<String, String> map, String url)  {
GetResult getResult=new GetResult(map,url);
Future f1 = pool
4000
.submit(getResult);
String r=null;
try {
r= (String)(f1.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return r;
}
}


Activity调用

public class MainActivity extends Activity{

private TextView result;
private Button getData;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//初始化UI
result=(TextView) findViewById(R.id.result);
getData=(Button) findViewById(R.id.getData);

//参数map
Map<String,String> map=new HashMap<>();
map.put("menu","秘制红烧肉");
map.put("key","************************");

//接口url
String url="http://apis.juhe.cn/cook/query.php";

//设置点击事件,点击获取网络数据
getData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

//调用自定义方法,得到网络请求数据,并更新UI界面,是不是很简洁
String r=GetResult.getResult(map,url);
result.setText(r);
}
});
}
}


结果截图:

至此,调用就结束了,看看返回结果,是json字符串,由于没有注册app到该接口网站,所以服务器返回值说我的应用审核超时,但是至少说明我们请求网络数据的动作是OK的,这就达到目的了



总结

使用线程池来处理子线程与主线程之间的通讯,可以使主线程的调用代码简洁明了,也可以定义本地接口,方便第三方调用得到返回值
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 线程 通讯