android 通过 HttpClient与服务端交互

  • 内容
  • 评论
  • 相关

android开发中免不了数据通信,比如写一个web项目,服务端使用的是java ee,android的client端就需要与其交互,比较方便的就是使用HttpClient来交互数据,当然这个apache的 HttpClient是不是andriod的,而是java程序都内置的,在这里给出一个小例子是GET方法的
服务端的servlet程序


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
	}

}

android的activity

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;
	}

}

android的布局文件

<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>

同时记得在权限设置文件中加入:

	<!-- 授权访问网络 -->
	<uses-permission android:name="android.permission.INTERNET" />

如果你运行这段程序,其实你会发现不能运行,汇报错误如下:

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.

从第一行的错误我们其实可以知道
在4.0之后在主线程里面执行Http请求都会报这个错,大概是怕Http请求时间太长造成程序假死的情况吧。
解决办法有两个思路,分别是:
第一种方法:直接忽视,强制使用(强烈不推荐,但是修改简单)
在MainActivity文件的setContentView(R.layout.activity_main)下面加上如下代码

if (android.os.Build.VERSION.SDK_INT > 9) {
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);
}

第二种方法:使用Thread、Runnable、Handler (推荐使用)
在Runnable中做HTTP请求,不用阻塞UI线程~

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);
    }
}

下面给出个完整的android多线程,子线程处理http请求返回数据给主线程,主线程操作UI的代码

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;
    }
}

关于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的内容

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

        }

    }
}

点击服务端文件下载
点击android文件下载par1
点击android文件下载par1
点击android文件下载par1

评论

0条评论

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注