Android -Webservice结合线程池工具类
一、工具类设计方案
1. jar 依赖包:
Android调用webService的第三方jar包:ksoap2-android-assembly-3.1.0-jar-with-dependencies
2. 工具类设计详细策略:
- 子线程执行:
因为在Android中,对于网络请求只能采用子线程去做,所以在工具类中将调用webservice的部分交给子线程去做。
在代码里面实现,是通过新建Runnable接口,然后提交给线程池去执行:
defaultThreadPool.submit(new Runnable() {});
- 子线程与主线程交互:
我们先思考一个问题,在android里面通过子线程进行网络请求,当子线程执行完毕,是需要将子线程中的结果返回给主线程,然后主线程进行UI渲染等。
存在一个问题:在 java 中子线程执行时分为两种,一种时无返回结果的,如通过实现Runnable接口;另外一种时有返回结果的,通过实现 Callable 接口,然后提交给线程池去执行。
第一种无法返回结果肯定不行,第二中可以返回结果,但是存在另外一个问题,使用Callable获取线程的返回结果,会堵塞调用该线程的另外一个线程,在Android中这种方式,就会阻塞UI主线程,直到子线程执行完毕将结果返回给主线程为止。
进 一 步 思 考 与 结 合 a n d r o i d 本 身 的 机 制 , 确 定 出 子 线 程 与 主 线 程 交 互 可 以 通 过 H a n d l e r 机 制 来 实 现 。 \color{red}进一步思考与结合android本身的机制,确定出子线程与主线程交互可以通过 Handler 机制来实现。 进一步思考与结合android本身的机制,确定出子线程与主线程交互可以通过Handler机制来实现。
详细设计如下:为了不阻塞UI主线程,网络请求的部分在 Runnable 接口中实现,当子线程执行完毕,将结果通过 Handler 来发送给主线程,其中结果参考回调函数的写法,将结果封装在自定义的WebServiceCallBack接口中,主线程从该接口的参数中中获取结果即可。
以下为:Callable的写法,虽然不用,但是可以学习一下
/**
* 带带返回值的线程池,通过 Callable 接口
*/
static void thread2callable() {
// 1. 创建线程池
ExecutorService defaultThreadPool = Executors.newFixedThreadPool(3);
// 2. 创建一个Callable,3秒后返回String类型
Callable myCallable = new Callable() {
@Override
public String call() throws Exception {
Thread.sleep(3000);
System.out.println("calld方法执行了");
return "call方法返回值";
}
};
// 3. 将 Callable 接口提交给任务队列
FutureTask futureTask = new FutureTask<>(myCallable);
// 4. 线程池中进行执行
defaultThreadPool.submit(futureTask);
// 5. 解析返回的结果
try {
String res = (String) futureTask.get();
System.out.println("获取返回值: " + res);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
二、完整代码
package indi.pentiumcm.stock.utils;
import android.os.Handler;
import android.os.Message;
import androidx.annotation.NonNull;
import indi.pentiumcm.stock.application.MyApplication;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.SoapFault;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpResponseException;
import org.ksoap2.transport.HttpTransportSE;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
/**
* @projName: Stock
* @packgeName: indi.pentiumcm.stock.utils
* @className: WebServiceUtils
* @author: pentiumCM
* @email: 842679178@qq.com
* @date: 2020/9/4 21:19
* @describe: WebService 工具类,结合线程使用
*/
public class WebServiceThreadUtil {
/**
* webservice 服务器url
*/
public static final String WEB_SERVE_URL = MyApplication.serverUrl;
/**
* webservice 命名空间
*/
public static final String WEB_SERVE_NAMESPACE = "http://tempuri.org/";
/**
* 超时时间:设置的是 两分钟
*/
public static final int TIME_OUT = 1000 * 60 * 2;
// 含有3个线程的线程池
private static final ExecutorService defaultThreadPool = Executors.newFixedThreadPool(3);
/**
* 请求处理成功的回调标示
*/
private static final int MESSAGE_POST_SUCCESS = 0x1;
/**
* 请求处理失败的回调标示
*/
private static final int MESSAGE_POST_FAIL = 0x2;
/**
* 调用 webService 的接口
*
* @param webserviceMethodName webservice方法名
* @param properties webservice 方法对应的参数
* @param webServiceCallBack 回调接口
* @return
*/
public static void callWebService(final String webserviceMethodName,
HashMap<String, Object> properties,
final WebServiceCallBack webServiceCallBack) {
// 创建HttpTransportSE对象,传递WebService服务器地址
HttpTransportSE httpTransportSE = new HttpTransportSE(WEB_SERVE_URL, TIME_OUT);
// SOAP Action
String soapAction = WEB_SERVE_NAMESPACE + webserviceMethodName;
// 创建SoapObject对象,指定WebService的命名空间和调用方法
SoapObject soapObject = new SoapObject(WEB_SERVE_NAMESPACE, webserviceMethodName);
// SoapObject添加参数:
if (properties != null) {
for (Map.Entry<String, Object> entry : properties.entrySet()) {
String mapKey = entry.getKey();
Object mapValue = entry.getValue();
soapObject.addProperty(mapKey, mapValue);
}
}
// 生成调用WebService方法调用的soap信息,并且指定Soap版本
final SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER12);
//由于是发送请求,所以是设置bodyOut
soapEnvelope.setOutputSoapObject(soapObject);
// 设置是否调用的是.Net开发的WebService
// 如果调用的是.Net的WebService,这里为true,否则为false,不然调用会不成功
soapEnvelope.dotNet = true;
soapEnvelope.setOutputSoapObject(soapObject);
httpTransportSE.debug = true;
// 用于子线程与主线程通信的Handler
final Handler mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
// 将返回值回调到callBack的参数中
webServiceCallBack.callBack((SoapObject) msg.obj);
}
};
// 使用线程池进行网络请求
// 网络请求完的数据使用 handler 返回给原线程
defaultThreadPool.submit(new Runnable() {
@Override
public void run() {
SoapObject resultSoapObject = null;
try {
httpTransportSE.call(soapAction, soapEnvelope);
if (soapEnvelope.getResponse() != null) {
// 获取服务器响应返回的SoapObject
resultSoapObject = (SoapObject) soapEnvelope.bodyIn;
}
} catch (Exception e) {
e.printStackTrace();
/* // 向主线程发送消息成功,返回异常信息
Message msg = Message.obtain();
msg.what = MESSAGE_POST_FAIL;
msg.obj = e.getMessage();
mHandler.sendMessage(msg);*/
} finally {
// 将获取的消息利用Handler发送到主线程
mHandler.sendMessage(mHandler.obtainMessage(0, resultSoapObject));
}
}
});
}
public interface WebServiceCallBack {
void callBack(SoapObject wsResult);
}
}