目录:
一. android使用ksoap2调用webservice
二. 异步调用
三. Android使用ksoap2调用C#中的webservice实现图像上传参考方法
四. 图像传输中Base64编码问题
一. android使用ksoap2调用webservice
这个话题很多文章中做过讨论,这里需要说明的一点,You can't do Network operations on the main thread. Checkout :http://developer.android.com/reference/android/os/AsyncTask.htmlfor painless background threading :) (参考:http://stackoverflow.com/questions/11969071/android-os-networkonmainthreadexception-for-webservice-ksoap),即调用webservice的操作必须是异步执行的(在2.2及之前版本可能不需要)。
android使用ksoap2调用webservice的基本代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
package
com.example.webserviceexample;
import
java.io.IOException;
import
org.ksoap2.SoapEnvelope;
import
org.ksoap2.SoapFault;
import
org.ksoap2.serialization.SoapObject;
import
org.ksoap2.serialization.SoapPrimitive;
import
org.ksoap2.serialization.SoapSerializationEnvelope;
import
org.ksoap2.transport.HttpTransportSE;
import
org.xmlpull.v1.XmlPullParserException;
import
android.app.Activity;
import
android.os.Bundle;
import
android.view.Menu;
import
android.view.View;
import
android.view.View.OnClickListener;
import
android.widget.Button;
import
android.widget.EditText;
import
android.widget.TextView;
public
class
MainActivity
extends
Activity {
final
static
String NAMESPACE =
"http://tempuri.org/"
;
final
static
String METHOD_NAME =
"CelsiusToFahrenheit"
;
final
static
String SOAP_ACTION =
"http://tempuri.org/CelsiusToFahrenheit"
;
final
static
String URL =
"http://www.w3schools.com/webservices/tempconvert.asmx"
;
TextView sonuc;
EditText deger;
Button hesapla;
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
deger = (EditText) findViewById(R.id.deger);
sonuc = (TextView) findViewById(R.id.flag);
hesapla = (Button) findViewById(R.id.hesapla);
hesapla.setOnClickListener(
new
OnClickListener() {
public
void
onClick(View v) {
//request info
SoapObject Request =
new
SoapObject(NAMESPACE, METHOD_NAME);
Request.addProperty(
"Celcius"
,deger.getText().toString());
//envelope
SoapSerializationEnvelope soapEnvelope =
new
SoapSerializationEnvelope(SoapEnvelope.VER11);
soapEnvelope.dotNet =
true
;
//.NET = true, php = false
//putting request to the envelope
soapEnvelope.setOutputSoapObject(Request);
//transferring data
HttpTransportSE aht =
new
HttpTransportSE(URL);
//prepare
//start
try
{
aht.call(SOAP_ACTION, soapEnvelope);
}
catch
(IOException e) {
e.printStackTrace();
}
catch
(XmlPullParserException e)
{
e.printStackTrace();
}
//waiting and getting response.
String result;
try
{
// we are creating SoapPrimitive Object as waiting for simple variable.
result =
"Fahrenheit:"
+ soapEnvelope.getResponse();
//writing the result to the textView
sonuc.setText(result);
}
catch
(SoapFault e) {
e.printStackTrace();
}
}
});
}
@Override
public
boolean
onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return
true
;
}
}
|
二. 异步调用
上述代码中,没有异步调用,是不能正常执行的,会有如下警告:
1
2
|
08-15 11:45:26.294: E/AndroidRuntime(641): FATAL EXCEPTION: main
08-15 11:45:26.294: E/AndroidRuntime(641): android.os.NetworkOnMainThreadException
|
正确的步骤中,需要把操作webservice的代码放入异步执行中,下面是异步执行的一个完整示例(同时可参考:http://stackoverflow.com/questions/8322057/android-os-networkonmainthreadexception-exception-while-trying-to-call-a-webserv):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
import
org.ksoap2.SoapEnvelope;
import
org.ksoap2.serialization.SoapObject;
import
org.ksoap2.serialization.SoapPrimitive;
import
org.ksoap2.serialization.SoapSerializationEnvelope;
import
org.ksoap2.transport.HttpTransportSE;
import
android.app.Activity;
import
android.os.AsyncTask;
import
android.os.Bundle;
import
android.util.Log;
public
class
MainActivity
extends
Activity {
private
String TAG =
"Vik"
;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AsyncCallWS task =
new
AsyncCallWS();
task.execute();
}
private
class
AsyncCallWS
extends
AsyncTask<Void, Void, Void> {
@Override
protected
Void doInVoid... params) {
Log.i(TAG,
"doInBackground"
);
calculate();
return
null
;
}
@Override
protected
void
onPostExecute(Void result) {
Log.i(TAG,
"onPostExecute"
);
}
@Override
protected
void
onPreExecute() {
Log.i(TAG,
"onPreExecute"
);
}
@Override
protected
void
onProgressUpdate(Void... values) {
Log.i(TAG,
"onProgressUpdate"
);
}
}
public
void
calculate()
{
String SOAP_ACTION =
"http://tempuri.org/CelsiusToFahrenheit"
;
String METHOD_NAME =
"CelsiusToFahrenheit"
;
String NAMESPACE =
"http://tempuri.org/"
;
String URL =
"http://www.w3schools.com/webservices/tempconvert.asmx"
;
try
{
SoapObject Request =
new
SoapObject(NAMESPACE, METHOD_NAME);
Request.addProperty(
"Celsius"
,
"32"
);
SoapSerializationEnvelope soapEnvelope =
new
SoapSerializationEnvelope(SoapEnvelope.VER11);
soapEnvelope.dotNet =
true
;
soapEnvelope.setOutputSoapObject(Request);
HttpTransportSE transport=
new
HttpTransportSE(URL);
transport.call(SOAP_ACTION, soapEnvelope);
SoapPrimitive resultString = (SoapPrimitive)soapEnvelope.getResponse();
Log.i(TAG,
"Result Celsius: "
+ resultString);
}
catch
(Exception ex) {
Log.e(TAG,
"Error: "
+ ex.getMessage());
}
SOAP_ACTION =
"http://tempuri.org/FahrenheitToCelsius"
;
METHOD_NAME =
"FahrenheitToCelsius"
;
try
{
SoapObject Request =
new
SoapObject(NAMESPACE, METHOD_NAME);
Request.addProperty(
"Fahrenheit"
,
"100"
);
SoapSerializationEnvelope soapEnvelope =
new
SoapSerializationEnvelope(SoapEnvelope.VER11);
soapEnvelope.dotNet =
true
;
soapEnvelope.setOutputSoapObject(Request);
HttpTransportSE transport=
new
HttpTransportSE(URL);
transport.call(SOAP_ACTION, soapEnvelope);
SoapPrimitive resultString = (SoapPrimitive)soapEnvelope.getResponse();
Log.i(TAG,
"Result Fahrenheit: "
+ resultString);
}
catch
(Exception ex) {
Log.e(TAG,
"Error: "
+ ex.getMessage());
}
}
}
|
三. Android使用ksoap2调用C#中的webservice实现图像上传参考方法
博客园“与时俱进”同时有相关的一篇博文(http://www.cnblogs.com/top5/archive/2012/02/16/2354517.html)可作为参考,全文如下:
最近boss要求做android客户端的图片上传和下载,就是调用服务器的webservice接口,实现从android上传图片到服务器,然后从服务器下载图片到android客户端。
需求下来了,开始动脑筋了呗。
通常,我们调用webservice,就是服务器和客户端(浏览器,android手机端等)之间的通信,其通信一般是传 xml或json格式的字符串。对,就只能是字符串。
我的思路是这样的,从android端用io流读取到要上传的图片,用Base64编码成字节流的字符串,通过调用webservice把该字符串作为参数传到服务器端,服务端解码该字符串,最后保存到相应的路径下。整个上传过程的关键就是 以 字节流的字符串 进行数据传递。下载过程,与上传过程相反,把服务器端和客户端的代码相应的调换。
不罗嗦那么多,上代码。流程是:把android的sdcard上某张图片 上传到 服务器下images 文件夹下。
注:这只是个demo,没有UI界面,文件路径和文件名都已经写死,运行时,相应改一下就行。
1 .读取android sdcard上的图片。
public void testUpload(){
try{
String srcUrl = "/sdcard/"; //路径
String fileName = "aa.jpg"; //文件名
FileInputStream fis = new FileInputStream(srcUrl + fileName);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int count = 0;
while((count = fis.read(buffer)) >= 0){
baos.write(buffer, 0, count);
}
String uploadBuffer = new String(Base64.encode(baos.toByteArray())); //进行Base64编码
String methodName = "uploadImage";
connectWebService(methodName,fileName, uploadBuffer); //调用webservice
Log.i("connectWebService", "start");
fis.close();
}catch(Exception e){
e.printStackTrace();
}
}
connectWebService()方法:
//使用 ksoap2 调用webservice
private boolean connectWebService(String methodName,String fileName, String imageBuffer) {
String namespace = "http://134.192.44.105:8080/SSH2/service/IService"; // 命名空间,即服务器端得接口,注:后缀没加 .wsdl,
//服务器端我是用x-fire实现webservice接口的
String url = "http://134.192.44.105:8080/SSH2/service/IService"; //对应的url
//以下就是 调用过程了,不明白的话 请看相关webservice文档
SoapObject soapObject = new SoapObject(namespace, methodName);
soapObject.addProperty("filename", fileName); //参数1 图片名
soapObject.addProperty("image", imageBuffer); //参数2 图片字符串
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER10);
envelope.dotNet = false;
envelope.setOutputSoapObject(soapObject);
HttpTransportSE httpTranstation = new HttpTransportSE(url);
try {
httpTranstation.call(namespace, envelope);
Object result = envelope.getResponse();
Log.i("connectWebService", result.toString());
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
2. 服务器端的webservice代码 :
public String uploadImage(String filename, String image) {
FileOutputStream fos = null;
try{
String toDir = "C:\\Program Files\\Tomcat 6.0\\webapps\\SSH2\\images"; //存储路径
byte[] buffer = new BASE64Decoder().decodeBuffer(image); //对android传过来的图片字符串进行解码
File destDir = new File(toDir);
if(!destDir.exists()) destDir.mkdir();
fos = new FileOutputStream(new File(destDir,filename)); //保存图片
fos.write(buffer);
fos.flush();
fos.close();
return "上传图片成功!" + "图片路径为:" + toDir;
}catch (Exception e){
e.printStackTrace();
}
return "上传图片失败!";
}
对android 端进行 单元测试调用testUpload()方法,如果你看到绿条的话,说明调用成功!在服务器下,就可以看到你上传的图片了。。。。
当然,这个demo很简陋,没有漂亮UI什么的,但是这是 android端调用webservice进行上传图片的过程。从服务器下载到android端,道理亦然。欢迎大家交流学习。。。。
ljd_198641给出了Android使用ksoap2调用C#中的webservice函数方法(参考:http://blog.csdn.net/ljd_1986413/article/details/6928051),全文如下:
一:webService简介
那么什么是webService呢?,它是一种基于SAOP协议的远程调用标准,通过webservice可以将不同操作系统平台,不同语言,不同技术整合到一起。
二:在AdroidManifest.xml中加入权限
<!-- 访问网络的权限 -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
三:导入ksoap2包
首先下载KSOAP包:ksoap2-android-assembly-2.5.2-jar-with-dependencies.jar包 复制到工程下的lib文件件里面
然后在android项目:右键->build path(构建路径)->configure build path(添加外部归档)--选择ksoap2
四:编写android可客户端代码
导入包库:
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
函数方法:
try {
final String SERVER_URL = "http://124.205.154.198:8081/Service.asmx";
String nameSpace = "http://tempuri.org/";//命名空间
String methodName = "Sum";//方法名
String soapAction = "http://tempuri.org/Sum";//HelloWorld 命名空间/方法名
//创建SoapObject实例
SoapObject request = new SoapObject(nameSpace, methodName);
request.addProperty("a", "g"); //这个是传递参数的 当然了不要参数就不必写这个了啊
//request.addProperty("passonString", "Rajapandian"); //这个是传递参数的
//生成调用web service方法的soap请求消息
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true; //设置.net web service
envelope.setOutputSoapObject(request);//发送请求
HttpTransportSE androidHttpTransport = new HttpTransportSE(SERVER_URL);
androidHttpTransport.call(soapAction, envelope);
Object result = (Object) envelope.getResponse();
//textView.setText(e.getMessage());
textView.setText(result.toString());
//textView.setText("7");
new AlertDialog.Builder(this).setTitle("Hint").setMessage(result.toString()).setPositiveButton("OK", null).show();
}
catch (Exception e)
{
System.out.println(e.getMessage());
textView.setText(e.getMessage());
new AlertDialog.Builder(this).setTitle("Hint").setMessage(e.getMessage()).setPositiveButton("OK", null).show();
}
五:webService方法
[WebMethod]
public string Sum(string a)
{
string c =a+"hello android";
return c;
}
四. 图像传输中Base64编码问题
在android java与c#进行图像传输时涉及到 Base64编解码,涉及到的知识点如下(参考:http://www.cnblogs.com/chenqingwei/archive/2010/06/28/1766689.html):
一. Base64的编码规则
Base64编码的思想是是采用64个基本的ASCII码字符对数据进行重新编 码。它将需要编码的数据拆分成字节数组。以3个字节为一组。按顺序排列24 位数据,再把这24位数据分成4组,即每组6位。再在每组的的最高位前补两个0凑足一个字节。这样就把一个3字节为一组的数据重新编码成了4个字节。当所 要编码的数据的字节数不是3的整倍数,也就是说在分组时最后一组不够3个字节。这时在最后一组填充1到2个0字节。并在最后编码完成后在结尾添加1到2个 “=”。
例:将对ABC进行BASE64编码:
1、首先取ABC对应的ASCII码值。A(65)B(66)C(67);
2、再取二进制值A(01000001)B(01000010)C(01000011);
3、然后把这三个字节的二进制码接起来(010000010100001001000011);
4、 再以6位为单位分成4个数据块,并在最高位填充两个0后形成4个字节的编码后的值,(00010000)(00010100)(00001001)(00000011),其中蓝色部分为真实数据;
5、再把这四个字节数据转化成10进制数得(16)(20)(9)(3);
6、最后根据BASE64给出的64个基本字符表,查出对应的ASCII码字符(Q)(U)(J)(D),这里的值实际就是数据在字符表中的索引。
注:BASE64字符 表:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
二.解码 规则
解码过程就是把4个字节再还原成3个字节再根据不同的数据形式把字节数组重新整理 成数据。
三. C#中的实现
编码:
byte[] bytes = Encoding.Default.GetBytes("要转换的字符");
string str = Convert.ToBase64String(bytes);
解 码:
byte[] outputb = Convert.FromBase64String(str);
string orgStr = Encoding.Default.GetString(outputb);
C#图片的Base64编码和解码
图片的Base64编码:
System.IO.MemoryStream m =new System.IO.MemoryStream();
System.Drawing.Bitmap bp =new System.Drawing.Bitmap(@“c:\demo.GIF”);
bp.Save(m, System.Drawing.Imaging.ImageFormat.Gif);
byte[]b= m.GetBuffer();
string base64string=Convert.ToBase64String(b);
Base64字符串解码:
byte[] bt = Convert.FromBase64String(base64string);
System.IO.MemoryStream stream =new System.IO.MemoryStream(bt);
Bitmap bitmap =new Bitmap(stream);
pictureBox1.Image = bitmap;