android开发中免不了数据通信,比如写一个web项目,服务端使用的是java ee,android的client端就需要与其交互,比较方便的就是使用HttpClient来交互数据,当然这个apache的 HttpClient是不是andriod的,而是java程序都内置的,在这里给出一个小例子是GET方法的
服务端的servlet程序[java]
package com.gaoxueping;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class Servlet01
*/
@WebServlet(description = "my servlet", urlPatterns = { "/Servlet01" })
public class Servlet01 extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public Servlet01() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = request.getParameter("username");
response.getWriter().println("Welcome to www.gaoxueping.com");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
}
[/java]
android的activity[java]
package com.gaoxueping;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import android.os.Bundle;
import android.os.StrictMode;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
@SuppressLint("NewApi")
public class MainActivity extends Activity {
EditText e1;
Button bt1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// new Thread(Runnable).start();
// if (android.os.Build.VERSION.SDK_INT > 9) {
// StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
// StrictMode.setThreadPolicy(policy);
// }
e1 = (EditText) findViewById(R.id.editText1);
bt1 = (Button) findViewById(R.id.button1);
bt1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String url = "http://192.168.1.67:8080/WebPro01/s1?username=gaoxueping";
HttpClient httpClient = new DefaultHttpClient();
try{
HttpGet httpRequest = new HttpGet(url);
HttpResponse httpResponse = httpClient.execute(httpRequest);
HttpEntity httpEntity = httpResponse.getEntity();
String result = EntityUtils.toString(httpEntity);
new AlertDialog.Builder(MainActivity.this).setMessage(result).create().show();
}catch(Exception e){
e.printStackTrace();
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}[/java]
android的布局文件[xml]
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@+id/textView1"
android:layout_below="@+id/textView1"
android:layout_marginTop="61dp"
android:text="@string/bt1name" />
<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/button1"
android:layout_below="@+id/textView1"
android:layout_marginTop="18dp"
android:ems="10" >
<requestFocus />
</EditText>
</RelativeLayout>[/xml]
同时记得在权限设置文件中加入:[xml]
<!– 授权访问网络 –>
<uses-permission android:name="android.permission.INTERNET" />[/xml]
如果你运行这段程序,其实你会发现不能运行,汇报错误如下:[java]
12-22 12:15:34.938: W/System.err(697): android.os.NetworkOnMainThreadException
12-22 12:15:34.982: W/System.err(697): at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1117)
12-22 12:15:34.982: W/System.err(697): at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:84)
12-22 12:15:34.988: W/System.err(697): at libcore.io.IoBridge.connectErrno(IoBridge.java:127)
12-22 12:15:34.988: W/System.err(697): at libcore.io.IoBridge.connect(IoBridge.java:112)
12-22 12:15:34.988: W/System.err(697): at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:192)
12-22 12:15:34.988: W/System.err(697): at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:459)
12-22 12:15:34.988: W/System.err(697): at java.net.Socket.connect(Socket.java:842)
12-22 12:15:35.000: W/System.err(697): at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:119)
12-22 12:15:35.000: W/System.err(697): at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:144)
12-22 12:15:35.000: W/System.err(697): at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164)
12-22 12:15:35.000: W/System.err(697): at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119)
12-22 12:15:35.008: W/System.err(697): at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360)
12-22 12:15:35.008: W/System.err(697): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555)
12-22 12:15:35.008: W/System.err(697): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487)
12-22 12:15:35.008: W/System.err(697): at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465)
12-22 12:15:35.008: W/System.err(697): at com.gaoxueping.MainActivity$1.onClick(MainActivity.java:41)
12-22 12:15:35.008: W/System.err(697): at android.view.View.performClick(View.java:4084)
12-22 12:15:35.020: W/System.err(697): at android.view.View$PerformClick.run(View.java:16966)
12-22 12:15:35.020: W/System.err(697): at android.os.Handler.handleCallback(Handler.java:615)
12-22 12:15:35.020: W/System.err(697): at android.os.Handler.dispatchMessage(Handler.java:92)
12-22 12:15:35.020: W/System.err(697): at android.os.Looper.loop(Looper.java:137)
12-22 12:15:35.020: W/System.err(697): at android.app.ActivityThread.main(ActivityThread.java:4745)
12-22 12:15:35.040: W/System.err(697): at java.lang.reflect.Method.invokeNative(Native Method)
12-22 12:15:35.040: W/System.err(697): at java.lang.reflect.Method.invoke(Method.java:511)
12-22 12:15:35.040: W/System.err(697): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
12-22 12:15:35.040: W/System.err(697): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
12-22 12:15:35.048: W/System.err(697): at dalvik.system.NativeStart.main(Native Method)
12-22 13:43:29.281: I/Choreographer(697): Skipped 61 frames! The application may be doing too much work on its main thread.[/java]
从第一行的错误我们其实可以知道
在4.0之后在主线程里面执行Http请求都会报这个错,大概是怕Http请求时间太长造成程序假死的情况吧。
解决办法有两个思路,分别是:
第一种方法:直接忽视,强制使用(强烈不推荐,但是修改简单)
在MainActivity文件的setContentView(R.layout.activity_main)下面加上如下代码[java]
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}[/java]
第二种方法:使用Thread、Runnable、Handler (推荐使用)
在Runnable中做HTTP请求,不用阻塞UI线程~[java]
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.share_mblog_view);
new Thread(runnable).start();
}
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle data = msg.getData();
String val = data.getString("value");
Log.i("mylog","请求结果–>" + val);
}
}
Runnable runnable = new Runnable(){
@Override
public void run() {
//
// TODO: http request.
//
Message msg = new Message();
Bundle data = new Bundle();
data.putString("value","请求结果");
msg.setData(data);
handler.sendMessage(msg);
}
}[/java]
下面给出个完整的android多线程,子线程处理http请求返回数据给主线程,主线程操作UI的代码 [java]
package com.example.templete;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity
{
//参数:Message相当于一种信息的载体,可以将子线程的数据传到主线程中,也就是所谓的线程间通信了。。。
private Handler mHandler = new Handler()
{
public void handleMessage(android.os.Message msg)
{//该方法在主线程中执行,不信的话可以log的。。。
String result = (String) msg.obj;//从主线程传来的数据
switch (msg.what)//what用于标记谁传来的信息
{
case 1:
mTextView1.setText(result);
break;
case 2:
mTextView2.setText(result);
break;
default:
break;
}
}
};
private TextView mTextView1;
private TextView mTextView2;
String outdata;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView1 = (TextView) findViewById(R.id.textView1);
mTextView2 = (TextView) findViewById(R.id.textView2);
Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(listener);
Button button2 = (Button) findViewById(R.id.button2);
button2.setOnClickListener(listener);
}
private OnClickListener listener = new OnClickListener()
{
@Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.button1:
new Thread()
{
public void run()
{
// 模拟耗时操作
try
{
// Thread.sleep(1000);
String url = "http://192.168.1.67:8080/WebPro01/s1?username=gaoxueping";
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpRequest = new HttpGet(url);
HttpResponse httpResponse = httpClient.execute(httpRequest);
HttpEntity httpEntity = httpResponse.getEntity();
String result = EntityUtils.toString(httpEntity);
outdata = result;
}
catch (Exception e)
{
e.printStackTrace();
}
String result = outdata;
Message msg = new Message();
msg.what = 1;
msg.obj = result;
// 发送到main线程
mHandler.sendMessage(msg);
// textView.setText(result);
}
}.start();
Log.e("MainActivity", "button1");
break;
case R.id.button2:
new Thread()
{
public void run() {
// 模拟耗时操作
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
String result = "从数据库获取的结果";
Message msg = new Message();
msg.what = 2;
msg.obj = result;
// 发送到main线程
mHandler.sendMessage(msg);
}
}.start();
Log.e("MainActivity", "button2");
break;
default:
break;
}
}
};
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
[/java]
关于handler
Handler
当然推荐的方法是通过一个Handler来处理这些,可以在一个线程的run方法中调用handler对象的postMessage或sendMessage方法来实现,Android程序内部维护着一个消息队列,会轮训处理这些,如果你是Win32程序员可以很好理解这些消息处理,不过相对于Android来说没有提供PreTranslateMessage这些干涉内部的方法。
消息的处理者,handler负责将需要传递的信息封装成Message,通过调用handler对象的obtainMessage()来实现。将消息传递给Looper,这是通过handler对象的sendMessage()来实现的。继而由Looper将Message放入MessageQueue中。当Looper对象看到MessageQueue中含有Message,就将其广播出去。该handler对象收到该消息后,调用相应的handler对象的handleMessage()方法对其进行处理。
Handler主要接受子线程发送的数据,并用此数据配合主线程更新UI.
当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发,比如说,你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。 如果此时需要一个耗时的操作,例如:联网读取数据, 或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,,如果你放在主线程中的话,界面会出现假死现象,如果5秒钟还没有完成的话,,会收到Android系统的一个错误提示 “强制关闭”. 这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,,Android主线程是线程不安全的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的.这个时候,Handler就出现了,来解决这个复杂的问题, 由于Handler运行在主线程中(UI线程中), 它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据) ,把这些消息放入主线程队列中,配合主线程进行更新UI。
Handler一些特点:handler可以分发Message对象和Runnable对象到主线程中,每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),
它有两个作用: (1)安排消息或Runnable在某个主线程中某个地方执行
(2)安排一个动作在不同的线程中执行
Handler中分发消息的一些方法
post(Runnable)
postAtTime(Runnable,long)
postDelayed(Runnable long)
sendEmptyMessage(int)
sendMessage(Message)
sendMessageAtTime(Message,long)
sendMessageDelayed(Message,long)
以上post类方法允许你排列一个Runnable对象到主线程队列中,sendMessage类方法,允许你安排一个带数据的Message对象到队列中,等待更新.
Handler实例
// 子类需要继承Hendler类,并重写handleMessage(Message msg) 方法,用于接受线程数据
// 以下为一个实例,它实现的功能为 :通过线程修改界面Button的内容
[java]
public class MyHandlerActivity extends Activity {
Button button;
MyHandler myHandler;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentview(R.layout.handlertest);
button = (Button) findViewById(R.id.button);
myHandler = new MyHandler();
//当创建一个新的Handler实例时,它会绑定到当前线程和消息的队列中,开始分发数据
// Handler有两个作用, (1) :定时执行Message和Runnalbe对象
// (2):让一个动作,在不同的线程中执行.
//它安排消息,用以下方法
// post(Runnable)
// postAtTime(Runnable,long)
// postDelayed(Runnable,long)
// sendEmptyMessage(int)
// sendMessage(Message);
// sendMessageAtTime(Message,long)
// sendMessageDelayed(Message,long)
//以上方法以 post开头的允许你处理Runnable对象
//sendMessage()允许你处理Message对象(Message里可以包含数据,)
MyThread m = new MyThread();
new Thread(m).start();
}
/**
*接受消息,处理消息 ,此Handler会与当前主线程一块运行
* */
class MyHandler extends Handler {
public MyHandler() {
}
public MyHandler(Looper L) {
super(L);
}
//子类必须重写此方法,接受数据
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
Log.d("MyHandler", "handleMessage……");
super.handleMessage(msg);
//此处可以更新UI
Bundle b = msg.getData();
String color = b.getString("color");
MyHandlerActivity.this.button.append(color);
}
}
class MyThread implements Runnable {
public void run() {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d("thread…….", "mThread……..");
Message msg = new Message();
Bundle b = new Bundle();//存放数据
b.putString("color", "我的");
msg.setData(b);
MyHandlerActivity.this.myHandler.sendMessage(msg); //向Handler发送消息,更新UI
}
}
}
[/java]
点击服务端文件下载
点击android文件下载par1
点击android文件下载par1
点击android文件下载par1