Android學習筆記之HttpClient實現Http請求....


PS:最近光忙着考試了....破組成原理都看吐了....搞的什么也不想干...寫篇博客爽爽吧....貌似明天就考試了...sad...

學習筆記:

1.如何實現Http請求來實現通信....

2.解決Android 2.3 版本以后無法使用Http請求問題....

 

  這里我使用HttpClient來開發Http程序來完成簡單的網絡通信....其實使用HttpUrlConnection也可以實現,不過HttpClient可以完成HttpUrlConnection的所有功能,並且還自己增加了其他的功能,那相比之下就直接使用HttpClient就得了...Http通信熟知的兩種方式,想必大家都清楚,一種是使用GET請求,另一種則是使用POST請求來完成...GET請求可以獲取靜態頁面,也可以把參數放在URL參數后面進行傳遞...POST與GET不同的地方就在於這里,POST請求無法將數據放到字符串的后面...而是放在Http傳遞的數據當中...這些參數會通過cookie或者是session來進行傳遞...POST更加適合傳遞保密的數據信息...比如說用戶的賬戶密碼...這樣使用GET方式就不是很合理了...因此把保密的數據信息放入到Http請求數據中更加的安全...

  那么Android是如何通過Http請求來實現GET或者是POST請求呢?這里簡單的介紹一下...先介紹一下GET方式...如何使用GET請求來獲取數據信息....GET請求需要幾個步驟...

  首先:我們需要建立GET對象...通過創建對象來告訴服務器我們使用的GET請求來獲取數據信息的...因為Http請求是以URL的形式進行來完成數據傳遞的...因此我們需要傳遞一個URL來實例化對象...我這個地址是服務器上的一個jsp文件...通過使用Http請求來獲取JSP界面的數據信息...

String path="http://10.0.2.2:8080/JSP/text.jsp":
HttpGet get=new HttpGet(path);

  然后我們需要使用DefaultHttpClient類中的execute()方法來發送Http GET請求...並返回一個HttpResponse對象,HttpResponse對象的目的是當一個Http連接建立成功之后,我們就可以使用其類中的方法來獲取到服務器的響應信息...

HttpClient client=new DefaultHttpClient();
HttpResponse response=client.execute(get);

  最后我們就可以通過HttpResponse對象來獲取服務器的響應數據信息了...這里我使用了一個getEntity()方法來返回響應信息,然后獲取GET提交的URL后面的數據信息...

if(response.getStatusLine().getStatusCode()==HttpStatuse.SC_OK){
     String result=EntityUtils.toString(resopnse.getEntity());
     tv.setText(result);   
}

   最后我們需要在AndroidManifest.xml文件中配置權限屬性...只需要添加<user-permission android:name="android.permission.INTERNET"/>那么簡單的舉一個小例子來實現Http的GET請求...

  首先我們先寫一個JSP頁面.....這個頁面要在Tomcat上進行發布...當沒有參數值進行傳遞的時候,會顯示Your message are wrong!這個信息...

<%
    String name=request.getParameter("name");
    String password=request.getParameter("password");
    if("DARKER".equals(name) && "4968188".equals(password)){
        out.println("Receive name is:"+name);
        out.println("Receive password is:"+password);%>
    Your message are right!
    <%}else{
        out.println("Receive name is:"+name);
        out.println("Receive password is:"+password); %>
        Your message are wrong!
    <%}%>

  然后有了這個東西,我們就可以通過Http傳遞數據信息來提交數據...然后通過這個界面返回的信息來告知我們服務器響應的信息數據...一個簡單的布局文件...就一個文本框...目的就是為了返回服務器的響應信息...

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/msg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

  如何實現才是一個重要的過程...在實現的過程中會出現一個問題,就是在Android2.3版本以后就不允許在主線程中去使用Http請求了...相信大部分的學習資料上都沒有這個提示問題,但是確實是存在着這樣一個問題的...那么上有政策那么就下有對策...我們可以使用三種方法去解決這個問題...非常的簡單,也很好理解...那么既然我們無法在主線程中去使用Http請求,那么我們可以新開啟一個線程啊...或者是我們可以去使用異步線程類AsyncTask去實現不就完了嗎...還有一種方法就是在主線程中加入某些東西...就是下面的在setContentView()這個函數下面加入的那兩句話...但是這種方法在網上說並不是很推薦...因此本人也沒怎么研究...其他兩種方式先對就很好理解...這三種方式我都進行了列舉...只要使用其中的任意一種方式就可以實現Http的GET請求....

package com.example.httpclient;
/* HttpCilent 通過Get與服務器進行通信...
 * HttpClient比HttpUrlConnection更加的有優勢...前者能做后者所有能做的事情...
 * 那就干脆就使用這種方式吧....
 *
 * 
 * */
import java.io.IOException;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
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.AsyncTask;
import android.os.Bundle;
import android.os.StrictMode;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity {

    /*
     * 由於在Android2.3版本以后就不允許在主線程使用Http請求...
     * 但是我們可以使用其他的方法來解決這個問題...
     * 第一種方法在主線程onCreate()方法中加入StrictMode方法..不過這種方法不被推薦...
     * 第二種使用異步線程AsyncTask<Param,Progress,Result>也可以實現...在異步線程中完成Http請求..
     * 第三種方法單開啟一個線程Runnable()來實現,其實也是延續異步線程的思想...
     * 
     * */
    private TextView tv;
//    private String path="http://10.0.2.2:8080/JSP/get.jsp?name=DARKER&password=49681888";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
//        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog().penaltyDeath().build());
        tv=(TextView) findViewById(R.id.msg);
        new Thread(runnable).start();
//        HttpGet httpRequest=new HttpGet(path);
//        HttpClient httpcilents=new DefaultHttpClient();
//        try {
//            HttpResponse response=httpcilents.execute(httpRequest);
//            if(response.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
//                String result=EntityUtils.toString(response.getEntity());
//                tv.setText(result);
//            }else{
//                tv.setText("請求錯誤");
//            }
//        } catch (ClientProtocolException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        } catch (IOException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
    }
    @SuppressWarnings("unused")
    private class http extends AsyncTask<Integer, Integer, Integer>{

        @Override
        protected Integer doInBackground(Integer... params) {
            // TODO Auto-generated method stub
            String url="http://10.0.2.2:8080/JSP/get.jsp?name=DARKER&password=49681888";
            HttpGet hget=new HttpGet(url);
            HttpClient htclient=new DefaultHttpClient();
            try {
                HttpResponse hresonse=htclient.execute(hget);
                if(hresonse.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
                    String resul=EntityUtils.toString(hresonse.getEntity());
                    tv.setText(resul);
                }else{
                    tv.setText("連接失敗...");
                }
            } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return null;
        }
        
    }

    Runnable runnable=new Runnable() {
        
        String path_1="http://10.0.2.2:8080/JSP/get.jsp?name=DARKER&password=49681888";
        @Override
        public void run() {
            // TODO Auto-generated method stub
            HttpGet get=new HttpGet(path_1);
            HttpClient cilent=new DefaultHttpClient();
            try {
                HttpResponse responses=cilent.execute(get);
                if(responses.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
                    String result_1=EntityUtils.toString(responses.getEntity());
                    tv.setText(result_1);
                }else{
                    tv.setText("無法獲取信息...");
                }
            } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                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;
    }
}

   其實上面代碼使用異步線程類是沒問題的,不過上面的代碼會報錯,由於我的代碼寫錯了位置...這個錯誤其實是在doInBackground()方法中出現的...因為在這個方法中是不能夠更新控件的數據信息的...這個問題我將在下面進行解決....下面是實現Http的POST請求...然后解決剛才說的問題....下面使用了Handler類...簡答的說一下這個類...其實這個類並不是用在這個異步線程類里面的...這個異步線程類內部還有三個沒有實現的方法...就是onPreExecute(),publishProgress(),onProgressUpdate()...這三個方法內部都可以完成控件數據信息的更新,唯獨這個doInBackground()是無法實現的...使用一個AsyncTask類,再使用Handler是完全沒有必要的...其實Handler和AsyncTask是為了實現子線程無法去更新主線程中控件的數據信息而存在的...因為控件對於線程來說是不安全的,因此在子線程中也就無法完成主線程中控件數據信息的更新操作...但是在Android中往往是需要這樣做的...因此出現了這兩個類去解決這個問題...

  首先說一句主要的事,就是使用到了Runnable並不代表一定使用到了多線程...就拿上面那個Runnable類來說,這個runnable雖然重寫了run()方法,並且還在主函數中使用了start進行調用,但是這個線程仍然是屬於主線程Activity的,並不屬於我們單獨開啟了一個新的線程,然后去執行任務...這是必然的,否則一定會報錯...因為在一個新的線程內部是無法去更新主線程中控件的數據信息的...然后在說一下Handler是如何能夠完成在子線程中能夠對主線程中的控件完成對數據的更新...首先Handler通過傳遞Message或者是Runnable對象...一般來說都是Message對數據進行封裝...Handler主要用來與Looper進行溝通..把信息加入到特定的Looper消息隊列中,或者是獲取Looper的信息,然后調用handlemessage方法來對獲取的信息進行操作...然后將Message發送到MessageQueue中,MessageQueue是一個線性隊列,用來保存獲取到的消息數據...當Looper發現MessageQueue中有未處理的信息就將這個信息廣播出去...Looper就是對MessageQueue隊列中然后主線程Handler接收到信息,然后做相應的處理...最后完成更新操作...這就是實現的一個過程...

package com.example.httpclientpost;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;

public class MainActivity extends Activity {

    TextView tv;
    String result;
    @SuppressLint("HandlerLeak")
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg){
            if(msg.what==1){
                tv.setText(result);
            }else{
                tv.setText("無法連接服務器...");
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv=(TextView) findViewById(R.id.show);
        http h=new http();
        h.execute();
    }
    
    class http extends AsyncTask<Integer, Integer, Integer>{

        String url="http://10.0.2.2:8080/JSP/get.jsp";
        @Override
        protected Integer doInBackground(Integer... params) {
            // TODO Auto-generated method stub
            HttpPost post=new HttpPost(url);
            List<NameValuePair> param=new ArrayList<NameValuePair>();
            param.add(new BasicNameValuePair("name", "DARKER"));
            param.add(new BasicNameValuePair("password", "49681888"));
            try {
                HttpEntity entity=new UrlEncodedFormEntity(param,"gb2312");
                post.setEntity(entity);
                HttpClient client=new DefaultHttpClient();
                HttpResponse response=client.execute(post);
                if(response.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
                     result=EntityUtils.toString(response.getEntity());
                     Message msg=new Message();
                     msg.what=1;
                     handler.sendMessage(msg);
                }else{
                    Message msg=new Message();
                    msg.what=0;
                    handler.sendMessage(msg);
                }
            }catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
          
            return null;
        }
        
    }
    @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中使用AsyncTask這個異步線程類其實就行,因為這個異步線程類是結合了handler+Thread才得以實現的,當然我們也可以使用handler去進行處理,個人推薦還是使用這個異步線程類更好...好了有點說跑題了...返回Http的POST請求,Http的POST請求比GET能多了一點東西,它使用NameValuePair以鍵值對的形式對數據進行保存...並且POST請求需要制定字符集...否則數據會出現亂碼現象...剩下的東西基本就類似了...這樣就實現了Http的POST請求....

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM