Android 如何使用 GET & POST 取得資料

Get & Post

對於寫網頁程式的人來說應該是不陌生,在網頁表單中,要送出資料時就會選擇要用Get的方式還是Post的方式。常見的Get方式是在網址後面加上查詢字串,像是
http://www.myweb.com/product?p=1&a=1&b=2
之類的,第一個用問號(?),之後每個都用(&)。

在Android中一樣可以用Get及Post去取得伺服器給予的資料。

在 Android 中使用 Get 及 Post 的幾個提示

  • 使用 org.apache.http 套件(也可以用別的)
  • Androidmanifest.xml 中要加入存取網路的授權
  • 清楚知道要使用 Get 還是 Post
  • 如果抓網路資料時間太久,建議把它放到背景執行並加上 Loading 提示

Get 的使用步驟

首先你要建立一個 HttpClient 物件:
HttpClient client = new DefaultHttpClient();
接著建立 HttpGet 物件並傳入網址:
HttpGet get = new HttpGet(_url);
當 HttpClient 執行 Get 任務後,會傳回 HttpResponse:
HttpResponse response = client.execute(get);
接下來就可以取得資料實體:
HttpEntity resEntity = response.getEntity();
你可以把它轉成字串來使用:
result = EntityUtils.toString(resEntity);
以上就是Get的基本操作。

Post 的使用步驟

一樣先建立 HttpClient 物件:
HttpClient client = new DefaultHttpClient();
接著建立 HttpPost 物件並傳入網址:
HttpPost post = new HttpPost(_url);
如果有參數的話,可以這樣加入:
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair(_queryKey, _queryValue));
UrlEncodedFormEntity ent = new UrlEncodedFormEntity(params, HTTP.UTF_8);
post.setEntity(ent);
執行後一樣會傳回 HttpResponse:
HttpResponse responsePOST = client.execute(post);
取得資料實體後可以轉成字串來用:
HttpEntity resEntity = responsePOST.getEntity();
result = EntityUtils.toString(resEntity);
以上是 Post 的操作方式。在參數的部份,接下來的範例只能加入一對(key-value),若有需要多組參數的話,要改成陣列的方式。

範例程式碼

package com.tonycube.demo;

import java.util.ArrayList;
import java.util.List;

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

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class GetPostDemoActivity extends Activity {
    
    private TextView txtResult = null;
    private Button btnLoad = null;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        initView();
    }
    
    
    private void loadPage() {
        String html = getHtmlByGet("http://zh.wikipedia.org/wiki/Wiki");
        txtResult.setText(html);
    }


    private void initView() {
        txtResult = (TextView) findViewById(R.id.txtResult);
        btnLoad = (Button) findViewById(R.id.btnLoad);
        btnLoad.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View v) {
                loadPage();
            }
            
        });
    }




    public String getHtmlByPost(String _url, String _queryKey, String _queryValue){    
        
        String result = "";
        
        try {
            HttpClient client = new DefaultHttpClient();
                        
            HttpPost post = new HttpPost(_url);
            
            //參數
            if (_queryKey != ""){
                List<NameValuePair> params = new ArrayList<NameValuePair>();
                params.add(new BasicNameValuePair(_queryKey, _queryValue));
                UrlEncodedFormEntity ent = new UrlEncodedFormEntity(params, HTTP.UTF_8);
                post.setEntity(ent);
            }
            
            HttpResponse responsePOST = client.execute(post); 
            
            HttpEntity resEntity = responsePOST.getEntity();
            
            if (resEntity != null) {    
                result = EntityUtils.toString(resEntity);
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
     client.getConnectionManager().shutdown();
 }
    
            
        return result;
    }
    

    public String getHtmlByGet(String _url){    
        
        String result = "";
        
        try {
            HttpClient client = new DefaultHttpClient();
                        
            HttpGet get = new HttpGet(_url);
            
            HttpResponse response = client.execute(get); 

            HttpEntity resEntity = response.getEntity();
            
            if (resEntity != null) {    
                result = EntityUtils.toString(resEntity);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
     client.getConnectionManager().shutdown();
 }
    
            
        return result;
        
    }
}

在 Androidmanifest.xml 加入網路存取權限

<uses-permission android:name="android.permission.INTERNET"/>

-- (2012/10/19 補充) --
在連線結束後要斷線,在 try..catch 最後增加 finally 來斷線。
finally {
   client.getConnectionManager().shutdown();
}

-- (2013/7/1 補充) --
Android 在 API 11 (3.0.x) 之後增加了一個 NetworkOnMainThreadException 網路在主執行緒的例外。這個例外是當程式試圖在主執行緒執行網路功能時丟出,意思就是在 SDK 3.0.x 之後的應用程式,不能把含有網路的相關功能寫在主執行緒,用意是,當執行網路功能時,例如下載資料,可能會發生不能預期的情況,導致下載時間過長,這時整個應用程式會被 HOLD 住,當超過一定時間後就會當掉閃退(ANR - Application Not Responding, 應用程式無回應),為了避免這種情況發生,Android 就強制不能再這麼做了。

解法很簡單,就是將網路功能從主執行緒中移開,我們可以另開一條新的執行緒讓它跑,怎麼做?可以自己寫 Thread,你可以參考這篇教學,或是使用 Android 提供的非同步功能 AsyncTask,我有寫一篇教學在這,用法很簡單,建立一個內隱類別去繼承 AsyncTask,然後將含有網路功能(或可能長時間執行)的程式放在 doInBackground 方法內就好了。例如這邊就可以把 loadPage() 放進去,這樣就可以達成非同步執行,並且不會讓主執行緒被卡住。

感謝 laject 的建議。
-- (2013/10/10 補充2) --
StrictMode (嚴格模式) 在 API 中的說明是,只能用來測試程式的哪個部份會造成長時間的執行,所以並不能用在要發佈的程式上,只能用來測試時使用。
本文網址:https://blog.tonycube.com/2011/11/androidget-post.html
Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀

97 則留言

  1. 請問小弟我只要抓取網頁body裡的資料

    該如何改正?

    回覆刪除
    回覆
    1. 要利用 xml/html parser 去解析出您要的資料,

      可以試試看 htmlcleaner
      http://htmlcleaner.sourceforge.net/
      它可以把 html 字串轉換成 DOM 然後去取您要的節點。

      但是一般來說,在手機上執行 parser 的執行效率並不是太好。

      刪除
  2. 版大您好

    小弟參考您的原始碼去測試

    在版大的程式碼是顯示網頁html

    小弟想只單獨擷取網頁body裡的內容

    剛剛小弟有參考您給的網頁

    但小弟實在不解

    可否請版大詳細解說一下

    回覆刪除
    回覆
    1. 假設你取得的html內容如下:
      String html = "〈html〉〈head〉〈title〉TITLE〈/title〉〈/head〉〈body〉BODY 〈/br〉 line 2 〈/br〉 line 3〈/body〉〈/html〉";

      那如下的程式碼可以取得〈body〉內的純文字
      private static void getData(){
      TagNode tagNode;

      try {
      tagNode = new HtmlCleaner().clean(html);
      TagNode[] nodeBody = tagNode.getElementsByName("body", true);
      String body = nodeBody[0].getText().toString();
      System.out.println(body);

      } catch (Exception e) {
      e.printStackTrace();
      }
      }

      結果會是 BODY line 2 line 3

      我不知道你body的內容是什麼,這個方法會取得純文字的內容。

      刪除
    2. 請問private static void getData 這一段要放在那個位置啊?

      刪除
    3. getData()是method,放在類別裡面,
      你應該拿裡面的程式碼來修改就好,
      ===============================
      TagNode tagNode;

      try {
      tagNode = new HtmlCleaner().clean(html);
      TagNode[] nodeBody = tagNode.getElementsByName("body", true);
      String body = nodeBody[0].getText().toString();
      System.out.println(body);

      } catch (Exception e) {
      e.printStackTrace();
      }
      ===============================

      刪除
    4. Tony大,一樣要抓取body,但是在API6的版本沒有找到 TagNode , HtmlCleaner的參數,有哪一個參數可以代替,另外小弟將不知道您上面的程式碼要放到哪一類別裡面,麻煩大大解說一下

      刪除
    5. 你要另外裝 HtmlCleaner 的jar檔(http://htmlcleaner.sourceforge.net/download.php),如果是AndroidStudio,要設定gradle(http://mvnrepository.com/artifact/net.sourceforge.htmlcleaner/htmlcleaner/2.15)

      HtmlCleaner 的用法可以參考這篇 http://blog.tonycube.com/2012/10/androidhtml-parserhtmlcleaner.html


      刪除
  3. 我是想抓http://www.etnet.com.hk/mobile/tc/quote.php?code=1 這個網頁中的報價資料, 資料就在 " 資料就在這裡 ". 我用JAVA的REGEX可以解析出我要的資料, 可是ANDROID上就不懂了, 我用了你上面貼的碼, 再加上REGEX, 可是抓不出我要的內容, 只可以REPLACE, PATTERN跟MATCHER 這裡沒有起作用, 可以幫忙看一下嗎? 代碼如下:


    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    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.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.EditText;
    public class GetPrice3 extends Activity {
    private EditText EditResult = null;
    private Button btnLoad = null;
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.get_price3);
    initView();
    }
    private void loadPage() {
    String html = getHtmlByGet("http://www.etnet.com.hk/mobile/tc/quote.php?code=1");
    EditResult.setText(html);
    }
    private void initView() {
    EditResult = (EditText) findViewById(R.id.editResult);
    btnLoad = (Button) findViewById(R.id.btnLoad);
    btnLoad.setOnClickListener(new OnClickListener(){
    // @Override
    public void onClick(View v){
    loadPage();
    }

    });
    }
    public String getHtmlByGet(String _url){

    String result = "";

    try {
    HttpClient client = new DefaultHttpClient();

    HttpGet get = new HttpGet(_url);

    HttpResponse response = client.execute(get);

    HttpEntity resEntity = response.getEntity();

    if (resEntity != null) {

    result = EntityUtils.toString(resEntity);
    //以下內容不起作用
    Pattern pattern = Pattern.compile("*?.*?",
    Pattern.CASE_INSENSITIVE);
    Matcher matcher=pattern.matcher(result.toString());
    String tmp="";
    while(matcher.find()){
    tmp=matcher.group();
    }
    tmp=tmp.replaceAll("<{1}[^>]{1,}>{1}","#").trim();
    tmp=tmp.replaceAll("\\p{Space}{1,}", "");
    //以下的REPLACE ALL有用
    result=result.replaceAll("<{1}[^>]{1,}>{1}","").trim();
    result=result.replaceAll("\\p{Space}{1,}", "").trim();
    result=result.replaceAll("[a-zA-Z]", "").trim();
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    return result;
    }
    }

    回覆刪除
    回覆
    1. 我寫了一個可以執行的範例,文章在這
      http://blog.tonycube.com/2012/10/androidhtml-parserhtmlcleaner.html#more

      最後面有範例檔可以下載,基本上,使用這個工具,你只要去研究 html 的 tag
      就好了,想辦法找到你要的資料的 tag 將它取出就能拿到你要的資料了。

      ====小提醒===
      這樣的執行效能並不好,最好是用單機的Java程式去取得資料後存成JSON讓Android App 去取已經解好的資料。Good luck~~ :)

      刪除
    2. Tony:

      1> 這些天出國剛回來, 剛剛下載來試試看!

      2> 你是說把資料下載了, 再用JSON去解析比較好?
      我是擔心, 又下載, 又儲存, 又刪除, 又再下載..... 會不會反而不好?

      謝謝!!

      BEBEYIM

      刪除
    3. 解JSON的資料比Parser整個網頁取資料會快很多,

      原本的架構:
      etnet -> Android App(1.下載html, 2.解析html, 3.顯示)

      建議的架構:
      etnet -> Server(自己架的伺服器:1.下載html, 2.解析html, 3.儲存成JSON) -> Android App(1.下載JSON, 2.解析JSON, 3.顯示)

      你想想看,你每抓一個"公司"的資料,都是不同的網頁,所以每次都要重新連線、解析,才能顯示資料,而連線及解析都很耗時。若換成下載JSON檔(或文字串),由於少了許多不必要的html,所以檔案小,下載快速,而且取資料的速度比Parser快,對於App來說少了很多負擔。基本上做的事情都一樣,只是多加了中間層去預先把耗時的部份處理掉而已。

      不過還是有缺點:
      1.要自己架伺服器去做資料整理
      2.對於需要"即時性"的資料可能會產生延遲

      以上只是建議,你還是可以先以原本做法去做,若之後覺得有必要改善顯示速度的問題,再考慮我提供的建議即可。 :)

      刪除
    4. 1> 我下載了你的範例, import進去eclipse試了一下, 模擬器出來的是抓不到數值, 都是NULL!!

      2> 我是在學習, 什麼情況都試試看, 所以先把原本架構做好了,能用了, 再來做你建議的架構.

      刪除
    5. 真怪,不過我這個範例時有點趕,不知哪裡有問題,你可能要自己除錯看看,但我這邊執行是ok就是了。

      嗯,瞭解。

      刪除
  4. html的標示資料貼不出來!! 你可以給我E-MAIL嗎? 我E-MAIL給你看一下!!

    回覆刪除
  5. tony:

    我下載了你的範例, import進去eclipse試了一下, 模擬器出來的是抓不到數值, 都是NULL!!

    回覆刪除
  6. 你好!我要怎麼下載網頁裡的xml然後做解析呢?

    回覆刪除
  7. 不懂"網頁裡的xml"是什麼,是指網頁本身的HTML嗎?

    這篇文章就是在說怎麼下載網頁,而另一篇
    http://blog.tonycube.com/2012/10/androidhtml-parserhtmlcleaner.html#more
    是在說怎麼解析xml/html。

    回覆刪除
  8. 不好意思...我在學怎麼抓網頁post出來的資料
    下方是練習的網址
    http://parkweb.traffic.ntpc.gov.tw/pda02.asp

    請問List params = new ArrayList();
    params.add(new BasicNameValuePair(_queryKey, _queryValue));
    UrlEncodedFormEntity ent = new UrlEncodedFormEntity(params, HTTP.UTF_8);
    post.setEntity(ent);
    這地方是要怎麼運用??抱歉..我看不懂

    回覆刪除
    回覆
    1. _queryKey是表單欄位的名稱,例如:carid
      _queryValue是該欄位的值,例如:AB1234
      POST是送出資料給Server,
      Server會回傳你的請求所要的資料,
      這個網頁看來是會回傳HTML,
      必須自己去解出想要的資料

      刪除
  9. 老師 你有這個的專案黨可以寄給我嗎?
    信箱zxccxzzxc162001@hotmail.com
    感謝老師!!

    回覆刪除
    回覆
    1. 這很久前寫的,找不到了,範例程式碼就是全部的內容了,
      實際上我已經把要寫的程式都包在getHtmlByPost及getHtmlByGet裡面,
      你只要呼叫這兩個方法,丟網址進去,就會回傳html資料了,
      loadPage()裡面就是示範怎麼用。

      刪除
  10. Tony師您好
    感謝您能夠提供原始碼讓眾多學子在網路上學習:)

    其實現在很多老師都讓學生試著寫android,但是卻沒有正式的課程
    異常辛苦啊...特別是作為畢業專題,學生我也是很努力地在學習中。

    這次會留言主要是想分享一下東西
    關於在這個程式碼中的小問題

    catch (Exception e) {
    e.printStackTrace();}
    這部分會抓到android.os.NetworkOnMainThreadException 這個錯誤
    這個主要是在android4.0之後版本的錯誤

    相關可以看以下網址
    http://bibby1101.pixnet.net/blog/post/47753182-%E3%80%8Aandroid%E3%80%8Bandroid.os.networkonmainthreadexception-%E9%8C%AF%E8%AA%A4

    如果Tony師方便的話,還請您可以將這個資訊加進去這篇文上
    使更多學子在未來學習上更加的方便。

    如有錯誤還請更正,感謝Tony師。

    回覆刪除
    回覆
    1. 好的,感謝您的建議,已在文章最後新增補充。

      PS.叫我Tony就好,我不是老師,這裡的文章只是我的筆記而以 :)

      刪除
    2. 感謝Tony,我自己也在這個blog學習到很多知識,
      萬分的慶幸自己能夠找到如此棒的blog,
      同時也感謝Tony能夠分享出這些筆記。

      刪除
    3. 不客氣,能幫到大家我很開心 :)

      刪除
  11. Tony老師好
    請問
    如果使用的是getHtmlByPost
    必須要傳入
    String _url
    String _queryKey
    String _queryValue
    3個參數
    後面2個
    應該要怎麼下呢
    我不太曉得 _queryKey 和 _queryValue 指的是什麼
    煩請老師幫我解惑

    thx~~~

    回覆刪除
    回覆
    1. 假設你有一個文字輸入框
      〈input type="text" name="username"〉
      使用者在輸入框內輸入"Tony"

      _queryKey = username
      _queryValue = Tony

      等同於使用GET時,網址後面會是 http://www.abc.com?username=Tony 一樣

      刪除
  12. Tony老師好
    不好意思再請教您一個問題

    我現在改用 getHtmlByPost(String_url,String_queryKey,String_queryValue)
    這個方法
    也傳入了該傳入的參數
    結果我發現按下按鈕後呼叫這個方法時
    似乎有一些地方沒有執行完
    於是我就在方法內的2行2行中間
    加上一些簡單的測試程式碼
    以追蹤程式沒有執行完的地方
    結果發現
    是在 HttpResponse responsePOST = client.execute(post); 這一行
    出了問題
    因為這一行之後的測試程式碼都沒有被執行
    但我試了好久
    也查看了 api
    遲遲無法解決這個問題
    不知道老師知不知道問題出在哪??

    回覆刪除
    回覆
    1. 要看一下DDMS有沒有顯示什麼錯誤,
      如果你用的API在11之後,記得不能在主執行緒中執行,文章後面的補充有說明。

      建議你可以分開測,
      在 getHtmlByPost(String _url,String _queryKey,String _queryValue)中,

      _url 傳入 "http://www.google.com",
      _queryKey 傳入 "" 空字串,
      _queryValue 一樣 "" 空字串.

      這是最單純的測試,如果一樣沒有回傳資料,那問題就不是在 key/value 上,
      網址也沒問題,所以很可能出在App的其他問題上,例如網路不能連,或是主執行緒的問題等等,記得看DDMS上面的訊息。

      刪除
  13. Tony老師好:
    請教您幾個問題
    如果我是單純從網頁端抓取資料URL,回傳至手機端
    請問可以省略中間那一段 直接改成下列這段嗎?

    package com.example.aa130929;

    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.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.TextView;


    public class MainActivity extends Activity
    {
    private TextView txtResult = null;
    private Button btnLoad = null;

    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    txtResult = (TextView) findViewById(R.id.txtResult);
    btnLoad = (Button) findViewById(R.id.btnLoad);
    btnLoad.setOnClickListener(new OnClickListener(){
    public void onClick(View v) {
    loadPage();
    }
    });
    }

    private void loadPage() {
    String html = getHtmlByGet("http://tw.bid.yahoo.com/");
    txtResult.setText(html);
    }

    public String getHtmlByGet(String _url){
    String result = "";
    try {
    HttpClient client = new DefaultHttpClient();
    HttpGet get = new HttpGet(_url);
    HttpResponse response = client.execute(get);
    HttpEntity resEntity = response.getEntity();
    if (resEntity != null){
    result = EntityUtils.toString(resEntity);
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    return result;
    }
    }

    回覆刪除
    回覆
    1. 你是指省略 getHtmlByPost 這個方法嗎? 如果沒用到,當然可以不用寫。

      刪除
  14. Tony老師您好
    看了您的文章後學會了POST&GET
    可是最近遇到一個問題,我想要寫一個可以查詢資料的頁面 並顯示查詢的資料
    手機端 輸入資料 點擊查詢
    -> PHP 接收到手機要查詢的資料 對資料庫進行篩選跟查詢
    -> MySQL
    目前我用POST傳送了資料到PHP,PHP也能順利的查詢及篩選到我要的資料,也在PHP上測試顯示成功且資料正確。
    但我想不到怎麼讓它在手機上顯示
    不知道能否請Tony老師指導一下

    回覆刪除
    回覆
    1. 你在 PHP 那邊使用 echo 把資料送出,
      Android 這邊使用 getHtmlByPost 或 getHtmlByGet 都可以,
      成功的話就會收到 echo 所送出的資料"字串",
      這個字串就是你需要的資料,
      看你要怎麼顯示這個字串。

      如果你回傳的資料很多,可以存成 JSON 格式,在 Android 中解析它,
      然後依需求顯示。

      刪除
    2. 感謝Tony老師
      嘗試了一下JSON 可是一點下查詢 app就會被停止
      這是錯誤碼
      E/AndroidRuntime(1133): FATAL EXCEPTION: Thread-9
      E/AndroidRuntime(1133): java.lang.NullPointerException
      E/AndroidRuntime(1133):at wisdom_kitchen.com.Reserve_Check$1.run(Reserve_Check.java:124)
      E/AndroidRuntime(1133): at java.lang.Thread.run(Thread.java:1019)
      並附上程式碼 麻煩Tony老師幫我看看
      --JSONParser--

      public class JSONParser {

      static InputStream is = null;
      static JSONObject jObj = null;
      static String json = "";

      // constructor
      public JSONParser() {

      }

      // function get json from url
      // by making HTTP POST or GET mehtod
      public JSONObject makeHttpRequest(String url, String method,
      List params) {

      // Making HTTP request
      try {

      // check for request method
      if (method == "POST") {
      // request method is POST
      // defaultHttpClient
      DefaultHttpClient httpClient = new DefaultHttpClient();
      HttpPost httpPost = new HttpPost(url);
      httpPost.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));

      HttpResponse httpResponse = httpClient.execute(httpPost);
      HttpEntity httpEntity = httpResponse.getEntity();
      is = httpEntity.getContent();

      } else if (method == "GET") {
      // request method is GET
      DefaultHttpClient httpClient = new DefaultHttpClient();
      String paramString = URLEncodedUtils.format(params, "utf-8");
      url += "?" + paramString;
      HttpGet httpGet = new HttpGet(url);

      HttpResponse httpResponse = httpClient.execute(httpGet);
      HttpEntity httpEntity = httpResponse.getEntity();
      is = httpEntity.getContent();
      }

      } catch (UnsupportedEncodingException e) {
      e.printStackTrace();
      } catch (ClientProtocolException e) {
      e.printStackTrace();
      } catch (IOException e) {
      e.printStackTrace();
      }

      try {
      BufferedReader reader = new BufferedReader(new InputStreamReader(
      is, "utf-8"), 8);
      StringBuilder sb = new StringBuilder();
      String line = null;
      while ((line = reader.readLine()) != null) {
      sb.append(line + "\n");
      }
      is.close();
      json = sb.toString();
      } catch (Exception e) {
      Log.e("Buffer Error", "Error converting result " + e.toString());
      }

      // try parse the string to a JSON object
      try {
      jObj = new JSONObject(json);
      } catch (JSONException e) {
      Log.e("JSON Parser", "Error parsing data " + e.toString());
      }

      // return JSON String
      return jObj;

      }
      }

      刪除
    3. 作者已經移除這則留言。

      刪除
    4. --php--

      // array for JSON response
      mb_internal_encoding('utf-8');
      $response = array();

      // include db connect class
      require_once dirname(__FILE__) . '/db_connect.php';

      // connecting to db
      $db = new DB_CONNECT();

      if (isset ($_GET["name"]) && isset ($_GET["phone"])) {

      $name=$_GET["name"];
      $phone=$_GET["phone"];

      // get a data from reserve table
      $result = mysql_query("SELECT * FROM reserve WHERE (reserve_name = '$name') and (reserve_phone = '$phone')");

      if (!empty($result)) {
      // check for empty result
      if (mysql_num_rows($result) > 0) {

      $result = mysql_fetch_array($result);

      $search = array();
      $search["reserve_name"] = $result["reserve_name"];
      $search["reserve_phone"] = $result["reserve_phone"];

      // success
      $response["success"] = 1;

      // user node
      $response["search"] = array();

      array_push($response["search"], $search);

      // echoing JSON response
      echo json_encode($response);

      } else {
      $response["success"] = 0;
      $response["message"] = "No data found";

      // echo no users JSON
      echo json_encode($response);
      }
      } else {
      $response["success"] = 0;
      $response["message"] = "No data found";

      // echo no users JSON
      echo json_encode($response);
      }
      } else {
      // required field is missing
      $response["success"] = 0;
      $response["message"] = "Required field(s) is missing";

      // echoing JSON response
      echo json_encode($response);
      }


      --這在onCreate內--

      /* 進行訂位查詢 因版本關係 網路方面的皆不可在OnCreate進行 故新開一個執行緒進行 */
      reserve_search = (Button) findViewById(R.id.reserve_search);
      reserve_search.setOnClickListener(new Button.OnClickListener() {
      @Override
      public void onClick(View v) {
      Thread reserve_search = new Thread(search);
      reserve_search.start();
      }
      });

      --這在onCreate外--

      private Runnable search = new Runnable() {
      public void run() {
      int success;
      try {
      // Building Parameters
      List params = new ArrayList();
      params.add(new BasicNameValuePair("name",reserve_search_name.getText().toString()));
      params.add(new BasicNameValuePair("phone",reserve_search_phone.getText().toString()));

      JSONObject json = jsonParser.makeHttpRequest(uriAPI,"GET",params);

      success = json.getInt(TAG_SUCCESS);
      if (success == 1) {
      JSONArray search_result_OBJ = json.getJSONArray(TAG_SEARCH);
      JSONObject search_result = search_result_OBJ.getJSONObject(0);

      txtName = (TextView) findViewById(R.id.search_result_name);
      txtPhone = (TextView) findViewById(R.id.search_result_phone);

      txtName.setText(search_result.getString("reserve_name"));
      txtPhone.setText(search_result.getString("reserve_phone"));

      } else {
      txtName.setText("查無資料");
      }
      } catch (JSONException e) {
      e.printStackTrace();
      }
      }
      };

      刪除
    5. 問題指出 Reserve_Check.java:124 行發生空指標的錯誤,
      我不知道你 124 行前後是什麼,那裡是發生錯誤原因。

      另外,在執行緒中指定 TextView 的值通常也會出錯,
      可以參考
      http://stackoverflow.com/questions/6049882/how-to-textview-settext-from-thread

      刪除
    6. 感謝Tony老師
      後來一直修改 一開始是空指標的錯誤
      是因為我忘記替TextView用findViewById

      繼續下去所發生的錯誤是無法在子線程進行UI的更動
      (Thread裡面做setText)
      然後參考了老師給的資料
      做了

      private Handler mHandler = new MyHandler();

      static class MyHandler extends Handler {
      @Override
      public void handleMessage(Message msg) {
      switch (msg.what) {
      case 1: {
      txtName.setText(search_result.getString("reserve_name"));
      txtPhone.setText(search_result.getString("reserve_phone"));
      break;
      }
      case 2: {
      txtName.setText("查無資料");
      break;
      }
      }
      }
      };

      然後在Runnable search裡面的if 做訊息的傳遞
      可是有一點問題
      因為JSON的Object只能在裡面用
      我該怎麼把他傳出去呢?

      if (success == 1) {
      // successfully received product details
      JSONArray search_result_OBJ = json.getJSONArray(TAG_SEARCH); // JSON
      // Array

      // get first product object from JSON Array
      JSONObject search_result = search_result_OBJ
      .getJSONObject(0);

      mHandler.obtainMessage(1, search_result);

      } else {
      Message msg = new Message();
      msg.what = 2;
      mHandler.sendMessage(msg);
      }

      感謝Tony老師

      刪除
    7. Message 的屬性obj 可以儲存任意類型的物件,可以試看看
      http://developer.android.com/reference/android/os/Message.html#obj

      我覺得你這樣的寫法好複雜,以後應該會很難維護吧?! 你有試過 AsyncTask 嗎? 可以參考這篇 http://blog.tonycube.com/2011/08/asynctask.html

      基本上兩種都是在處理多執行緒的問題,像你這種簡單的功能,用 AsyncTask 就很夠用,這是 Android 內建也推薦的做法,除非有長時間或複雜的處理,才需要用到自己寫執行緒。

      刪除
    8. 謝謝Tony老師提供的資料
      我有嘗試用了一下AsyncTask
      可是問題還是出在那個JSONObject上
      我先在外面宣告一個 然後再把JSON這邊的存進去
      TextView在去顯示外面宣告的
      但TextView那邊還是一直顯示找不到它 不知道它是什麼

      不好意思能請你多解說一下那個Message 的屬性obj嗎
      感覺一知半解
      麻煩你了 謝謝

      刪除
    9. case 1: {
      JSONObject search_result = (JSONObject)msg.obj;//<---加這行
      txtName.setText(search_result.getString("reserve_name"));

      刪除
    10. 感謝Tony老師
      不過系統還有叫我多加Try...catch包起來

      case 1: {

      JSONObject search_result = (JSONObject) msg.obj;
      try {
      txtName.setText(search_result.getString("reserve_name")
      .toString());
      txtPhone.setText(search_result.getString("reserve_phone")
      .toString());
      } catch (JSONException e) {
      e.printStackTrace();
      }

      break;
      }
      運作後沒有發生錯誤 也從LOG中確實看到是有查詢到我要的資料
      可是TextView卻沒有顯示出來..是撈空了嗎

      另外感謝你提供AsyncTask的資料
      我回頭發現之前一些抓圖(bitmap),thread 會有outofmemory 還有好像是線程太混亂的錯誤

      刪除
    11. 如果查看 search_result.toString() 有列出資料,
      那 search_result.getString("reserve_name") 就應該會有資料才對,
      只是為什麼後面還再加 .toString(),
      如果確認是有資料的,
      那就要查一下 txtName View 是不是有問題。

      刪除
  15. Tony老師你好
    我嘗試了一下 發現是它沒有跑進去case 1 耶
    private Handler mHandler = new MyHandler();

    static class MyHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
    switch (msg.what) {
    case 1: {
    JSONObject search_result = (JSONObject) msg.obj;
    try {
    txtName.setText(search_result.getString("reserve_name"));
    txtPhone.setText(search_result.getString("reserve_phone"));

    } catch (JSONException e) {
    e.printStackTrace();
    }
    break;
    }
    case 2: {
    txtName.setText("查無資料");
    break;
    }
    }
    }
    };
    ---------------------
    private Runnable search = new Runnable() {
    public void run() {
    // Check for success tag
    int success;

    try {

    // Building Parameters
    List params = new ArrayList();
    params.add(new BasicNameValuePair("name", reserve_search_name
    .getText().toString()));
    params.add(new BasicNameValuePair("phone", reserve_search_phone
    .getText().toString()));

    // getting product details by making HTTP request
    // Note that product details url will use GET request
    JSONObject json = jsonParser.makeHttpRequest(uriAPI, "GET",
    params);

    // check your log for json response
    Log.d("Single Search Details", json.toString());

    // json success tag
    success = json.getInt(TAG_SUCCESS);
    if (success == 1) {
    // successfully received product details
    JSONArray search_result_OBJ = json.getJSONArray(TAG_SEARCH); // JSON
    // Array

    // get first product object from JSON Array
    JSONObject search_result = search_result_OBJ
    .getJSONObject(0);

    mHandler.obtainMessage(1, search_result);
    } else {

    Message msg = new Message();
    msg.what = 2;
    mHandler.sendMessage(msg);
    }
    } catch (JSONException e) {
    e.printStackTrace();
    }
    }
    };
    用LOG那邊顯示查到的
    Single Search Details(969):
    {"search":[{"reserve_phone":"1234","reserve_name":"jacky"}],"success":1}

    我把case1裡面的txtName改成顯示"1" 也沒有反應 所以應該是沒有進到case1
    可是如果是txtName View有問題的話 但我case 2 查無資料 是正常運作的

    回覆刪除
    回覆
    1. if (success == 1) {
      // successfully received product details
      JSONArray search_result_OBJ = json.getJSONArray(TAG_SEARCH); // JSON
      // Array

      // get first product object from JSON Array
      JSONObject search_result = search_result_OBJ
      .getJSONObject(0);

      ////////////////////////////////////////////////////////////////
      //mHandler.obtainMessage(1, search_result);
      //改成以下4行
      Message msg = new Message();
      msg.what = 1;
      msg.obj = search_result;
      mHandler.sendMessage(msg);
      }

      刪除
  16. 程式可以順利跑出來了 感謝Tony老師
    那為甚麼 mHandler.obtainMessage(1, search_result);會跑不進去case1呢?

    回覆刪除
    回覆
    1. 你查一下 obtain 的意思,它是"獲得",
      obtainMessage 會回傳 Message ,
      所以它是用來取得 Message ,
      而不是用來送出 Message 。

      刪除
  17. 作者已經移除這則留言。

    回覆刪除
  18. Tony老師你好
    我目前想要登入學校網頁抓取學分資料 以供計算畢業條件
    目前我已成功post參數(帳號密碼)給login.php並取得登入後的頁面原始碼
    但我接著使用GET 去跳轉到學分的頁分 他回傳過來的是 為登入過的狀態
    請問該如何持有登入後的COOCKIE 去跳轉到所需資料的頁面


    回覆刪除
    回覆
    1. 找到這一篇
      http://stackoverflow.com/questions/8133329/http-cookie-store-in-android

      解答的做法是,利用 response.getHeaders("cookie") 取得 cookie,
      然後在下次的連線中,把這個取得的 cookie 加上去,
      你試試看吧~~

      刪除
    2. 謝謝你的回答
      目前我的做法是用同一個 client 先做post 在做 get
      晚點試試看這個解法

      刪除
  19. Tony老師~
    我在國光客運的訂票頁面
    我是Post 身分證還有電話而已
    https://order.kingbus.com.tw/ORD/ORD_M_1510_OrderGo.aspx

    key "ctl00_ContentPlaceHolder1_txtCustomer_ID"
    key "ctl00_ContentPlaceHolder1_txtPhone"

    但回傳資料只有看到 "不是正確的數字" 其他都是HTML的語言

    回覆刪除
    回覆
    1. 當你輸入表單中的欄位(身份證及電話),按"下一步"後,
      資料送到伺服器,處理後會回傳結果頁面,
      這個頁面是HTML,讓瀏覽器來解析後顯示畫面,

      所以理所當然的,你收到的回傳資料會是一頁HTML原始碼"文字",
      而不你所希望的只有回傳"資料",
      因此你只能去解析這個HTML頁面,找到你想要的資料。

      刪除
    2. 謝謝,已經嘗試出來

      刪除
  20. 版主您好
    請問我可以裡用post的方法
    將我的將緯度座標
    加入到網址 "?" 後面的參數嗎?
    像是:
    https://www.google.com.tw/search?x=100&y=100

    回覆刪除
    回覆
    1. 可以,但是回傳的會是整個HTML網頁,而不是單純的資料。

      如果你單純只是要顯示結果,可以用 Intent.ACTION_WEB_SEARCH
      讓內建的 App 去顯示它,請參考這篇 http://stackoverflow.com/questions/19492869/adding-google-search-api-to-android-app

      不然可能就要使用 Google search api 去做。

      刪除
  21. Tony老師好!
    看完您這篇文章收穫很多
    目前我想試試用asynctask傳值給php
    雖然看過您介紹asynctask另外一篇文章
    但仍不太清出如何實作
    請問是像下面貼得這樣嗎?
    初學者向您請教一下><

    public class MainActivity extends Activity {

    private TextView mText1= (TextView) findViewById(R.id.mText1);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    new LoadingDataAsyncTask().onPostExecute(null);

    }

    void httppost()
    {
    String uriAPI = "http://192.168.43.44/pass.php";

    HttpPost httpRequest = new HttpPost(uriAPI);

    List params = new ArrayList ();
    params.add(new BasicNameValuePair("num1","5566"));
    try
    {
    httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));

    HttpResponse httpResponse = new DefaultHttpClient().execute(httpRequest);

    if(httpResponse.getStatusLine().getStatusCode() == 200)
    {
    String strResult = EntityUtils.toString(httpResponse.getEntity());
    mText1.setText(strResult);
    }
    else
    {
    mText1.setText("Error Response: "+httpResponse.getStatusLine().toString());
    }
    }
    catch (ClientProtocolException e)
    {
    mText1.setText(e.getMessage().toString());
    e.printStackTrace();
    }
    catch (IOException e)
    {
    mText1.setText(e.getMessage().toString());
    e.printStackTrace();
    }
    catch (Exception e)
    {
    mText1.setText(e.getMessage().toString());
    e.printStackTrace();
    }


    }
    class LoadingDataAsyncTask extends AsyncTask{

    @Override
    protected Integer doInBackground(String... param) {
    httppost();
    return null;
    }

    @Override
    protected void onPostExecute(Integer result) {
    super.onPostExecute(result);

    }

    @Override
    protected void onProgressUpdate(Integer... values) {
    super.onProgressUpdate(values);
    }

    @Override
    protected void onPreExecute() {
    super.onPreExecute();
    }

    }

    回覆刪除
    回覆
    1. 你的 httppost() 裡面不能有任何存取 view 的程式碼,
      因為它放在 doInBackground() 裡面,這裡是不能存取任何 view 的,
      也就是 httppost() 會取得資料,也許是字串,
      然後回傳給 onPostExecute() 接收,
      在 onPostExecute() 裡面才能對 view 做存取,
      也就是你的 mText1.setText(strResult); 要寫在這裡。

      如果你的 httppost() 是取得字串的話,
      要改成
      class LoadingDataAsyncTask extends AsyncTask<String, Integer, String>{

      泛型參數 <String, Integer, String>
      分別對應到
      doInBackground(String... param) <== 第1個參數

      onProgressUpdate(Integer... values) <== 第2個參數,如果不顯示進度,就不理它

      onPostExecute(String result) <== 第3個參數,這裡會和
      protected String doInBackground() 的回傳型態一樣是String,
      因為是 doInBackground 將結果回傳給 onPostExecute 去接收。

      刪除
    2. 謝謝Tony老師的指正與教導~
      我訂正了程式碼後程式有執行
      但值沒有成功傳到伺服器的php裡
      可以麻煩Tony老師再指導哪一部分還需要做修正呢??
      真的非常感謝您!

      public class MainActivity extends ActionBarActivity {

      @Override
      protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      new LoadingDataAsyncTask().onPostExecute(null);

      }

      class LoadingDataAsyncTask extends AsyncTask{

      @Override
      protected String doInBackground(String... param) {
      String uriAPI = "http://192.168.18.5/pass.php";
      String res=" ";

      HttpClient client = new DefaultHttpClient();
      HttpPost httpRequest = new HttpPost(uriAPI);

      List params = new ArrayList ();
      params.add(new BasicNameValuePair("num1","5566"));
      try
      {
      httpRequest.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));

      HttpResponse httpResponse = client.execute(httpRequest);
      if(httpResponse.getStatusLine().getStatusCode() == 200)
      {
      res = EntityUtils.toString(httpResponse.getEntity());

      }
      else
      {
      res= httpResponse.getStatusLine().toString();
      }

      }
      catch (ClientProtocolException e)
      {
      res=e.getMessage().toString();
      e.printStackTrace();
      }
      catch (IOException e)
      {
      res=e.getMessage().toString();
      e.printStackTrace();
      }
      catch (Exception e)
      {
      res=e.getMessage().toString();
      e.printStackTrace();
      } finally {
      client.getConnectionManager().shutdown();
      }

      return res;
      }

      protected void onPostExecute(String res) {
      super.onPostExecute(res);

      }

      @Override
      protected void onProgressUpdate(Integer... values) {
      super.onProgressUpdate(values);
      }

      @Override
      protected void onPreExecute() {
      super.onPreExecute();
      }

      }
      }

      刪除
    3. 你的 PHP 如果寫 $_POST["num1"],應該會取得"5566",然後看你要回傳什麼給 App。

      另外,你的 onPostExecute(String res) 沒有處理取得的資料,
      例如 mText1.setText(res);
      所以你的程式執行完,什麼事都不會發生。

      刪除
    4. 謝謝Tony老師的指導~
      我會再做修改的!

      刪除
  22. 假如我在安卓端 name=aaa 然後再server端做運算得到hello aaa 並在android端顯示出此結果 那我該怎麼寫呀 謝謝大大

    回覆刪除
    回覆
    1. 假設你的server上有個 sayhello.php 的頁面,
      它的 $_POST 或 $_GET 會收到 android app 連到這個網頁送過來的資料 key=name, value=aaa (POST方法),或 sayhello.php?name=aaa (GET方法),
      sayhello.php 處理完後 echo 資料,
      這樣你的 android app 的 HttpPost 或 HttpGet 就會收到 response,就可以把該資料顯示出來。

      刪除
    2. 作者已經移除這則留言。

      刪除
  23. 請問一下 如何用讓android 運用get和post的方法 從php的網頁上 按下button 將php網頁上的圖片抓下來並放在 imageview上 謝

    回覆刪除
    回覆
    1. 所以用get 和 post 不能從php上抓圖片嗎?
      假如可以 是要怎麼用!!!
      那假如不可以 有什麼方法可以從php抓圖片到android嗎?

      刪除
    2. 要下載圖片可以參考 http://www.androidbegin.com/tutorial/android-download-image-from-url/
      主要只有三行
      InputStream input = new java.net.URL(imageURL).openStream();
      Bitmap bitmap = BitmapFactory.decodeStream(input);
      imgView.setImageBitmap(bitmap );

      PS.加標點符號和斷行是對觀看者的尊重。

      刪除
  24. Tony你好,我目前在製作專題上有點問題想指教一下
    目前已經做到可以上傳資料到mysql了,但圖檔我傳到另外一個硬碟去了,因為權限問題開不了

    現在想要做的是抓取單筆資料核對圖片 一起印出來,像是一個image 下面 textbox這樣
    目前有想到是利用mysql自動編號 1開始+1的那種
    例如資料表新增了一筆資料 Member_No = 20 圖檔名也是20 要如何去做比對後 印出正確的圖加文到android上面

    不好意思 問了這麼長的問題

    回覆刪除
    回覆
    1. 你要解決的問題應該是取得某筆資料的同時,也取得它對應的圖片這樣吧,
      使用資料庫的自動編號不是個好方法,因為你必須先新增一筆資料後,才能(還要)去取得這筆資料的ID。

      最簡單作法,在資料表中加一個欄位儲存圖檔名稱,這樣當你取得該欄位的同時,也有圖檔名稱了,
      這時候去下載圖片就不是問題。

      圖檔名稱有很多方法可以指定,例如,可以取你要顯示在 textbox 中的文字來當檔名,但可能不是那麼好;
      你也可以用 timestamp,就是現在時間的毫秒值,或轉成時間格式 20150805194500 年月日時分秒這樣,唯一要注意的是,如果是用迴圈新增資料,有可能會重覆;也可以使用 hash code 等等。

      刪除
    2. 謝謝TONY老師的指導,後來php用了TIME()的方式去產生不同名並上傳到了資料表欄位了

      現在的階段是可以從Android撈我要的資料表欄位出來了,想請問一下要怎麼在撈資料的過程中把圖也撈出來

      例如我撈了Member_no =10的所有資料欄位資料,圖檔檔名的資料也撈了出來。
      那我要如何在這當中去寫讀取這個圖檔出來會比較好呢?
      我撈的資料是一次撈多筆,用的語法如下
      for(int i = 0; i < jsonArray.length(); i++)
      {
      ...把撈出來的資料settext印到 android上
      }
      再次感謝老師指導,上次看了回覆後在上網查了一些使用方式就解決了這個問題。

      刪除
    3. 下載圖檔參考這篇(http://stackoverflow.com/questions/5776851/load-image-from-url)
      如果載入的資料太多,可能要用非同步的方式下載圖檔,或是在需要顯示圖檔時才去抓圖並暫存,
      而不要一開始就把圖集中一次下載。

      刪除
    4. 作者已經移除這則留言。

      刪除
  25. 您好,想請問Tony老師一些問題,小弟是Android新手,會一些皮毛,現在公司要我寫一個Android App可以抓取server端的資料,比如會員登入後,可以查詢訂單...等資料,server端,是用PHP跟MySQL建起來的,我想問的是,App 跟 server端的溝通是用哪種方法,聽說會用到web api、xml,所以想請大大
    是否能給我一個方向呢!?感激不盡!!

    回覆刪除
    回覆
    1. 看公司的web api格式是什麼,
      例如這是 youtube 的 web api 格式
      GET https://www.googleapis.com/youtube/v3/search?key={YOUR_API_KEY}

      表示你要用 GET 的方法來取資料,後面這段網址就是資料網址,
      回傳的資料可能是 JSON 或 XML,要先知道這個回傳資料的格式你才能用對的方式去解讀它。

      以你的例子來說,可能是用 GET 方法連到
      https://www.mycompany.com/orderlist
      然後它回傳 XML,在App中去解讀並呈現資料。

      刪除
    2. Tony老師您好,好像似乎就像您說的,似乎要用XML來做,然後取資料吐在APP上面。
      謝謝您!

      刪除
    3. Tony老師您好,我想把arduino讀取到的數值傳送到網頁上並顯示出來,我的數值是會變動的所以我希望網頁上的數值跟著變動,這部分的網頁怎麼寫??

      刪除
    4. 我沒寫過Arduino,不知道這是不是你要的,這篇
      https://www.arduino.cc/en/Tutorial/WebServer
      它會建立一個簡易的網頁伺服器,並且輸出網頁內容,
      你應該可以把資料放在裡面輸出,該範例設定每5秒refresh一次,
      可以改成你需要的頻率。

      刪除
  26. Tony老師您好,想請教幾個問題,目前在寫一個結合智慧手環的APP,他們所提供的認證方式是用OAuth 2.0,並且要求必需是"https://"開頭的callback_url,我目前進行到的階段是能夠取得auth_code,然後要拿auth_code去要access_token的時候所回傳的JSON卻是null,這有可能是什麼地方出目題,或是https有加密的需求呢?

    回覆刪除
    回覆
    1. 一定要用 https 啊,不然整個過程就白做工了。
      你的流程沒問題,所以要看看拿 auth_code 去要求 token 這段出了什麼問題,
      可能要看對方的使用說明,應該會有需要什麼參數之類的。

      刪除
    2. 他所必需給定的參數有加上去,我要接post出去的response時就出現了System.err javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x71c2b008: Failure in SSL library, usually a protocol error等23個,我在google也找不到這個錯誤碼的相關資訊,不知道tony老師是否了解這方面的問題呢?

      刪除
    3. 這篇有相同的錯誤,不過錯誤代碼不同,可以看看
      http://stackoverflow.com/questions/29916962/javax-net-ssl-sslhandshakeexception-javax-net-ssl-sslprotocolexception-ssl-han

      另外這篇可能也有幫助
      http://raptordigital.blogspot.tw/2014/07/android-and-ssl-httpclient.html

      刪除
  27. TONY老師您好,最近想要自己寫一個APP
    APP內容是想要連接網頁,可與該網頁的表單進行互動
    例如:http://statistics.most.gov.tw/was2/award/AsAwardMultiQuery.aspx 該網頁的查詢系統
    想請問一下要怎麼著手

    回覆刪除
    回覆
    1. 我隨便執行了一個查詢,它的網址如下:
      http://statistics.most.gov.tw/was2/award/AsAwardMultiQuery.aspx?year=105&code=QS16&organ=A,FA01,FA01A000&name=
      後面那串
      ?year=105
      &code=QS16
      &organ=A,FA01,FA01A000
      &name=

      就是我選擇的表單欄位的值,你要自己在 App 中把這些值串成網址,然後用 GET 送出,它就會回傳結果,但結果是一整個網頁的HTML,所以你還要解析資料排版什麼的,
      以上的執行效率太差,程式也很鎖碎複雜。

      建議去找看看它有沒有提供 Open Data 可用,不然你要做的這件事工程浩大,而且不太合乎效率。

      刪除
    2. 謝謝老師回覆
      我有一個疑問是,這個asp網頁是採用post方法
      用get也可以嗎?

      刪除
    3. 目前我的想法是
      使用httpurlconnection連到該網頁
      input網頁原始碼
      使用JSOUP解析想要的資料
      但是不知道要怎麼跟網頁溝通....

      刪除
    4. 不確定,你可以試看看,反正它一定有資料回傳,你可以先把回傳的資料印出來,就知道有沒有想要取得的資料,而且你也要先看過網頁原始碼才能去解析資料。

      刪除
    5. 不知道TONY老師有沒有用過Volley

      刪除
  28. Tony版主你好, 看了你的文章之後, 對於POST有了比較清楚的認知了.
    但是現在一直有個問題困擾著我, 就是我想要中油的網站下搜尋, 但一直都沒有拿到對的Response.
    我的header 跟詢問參數如下, 想請Tony幫我看一下, 是不是有什麼地方沒有正確填寫

    HttpClient client = new DefaultHttpClient();
    String Agent = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Mobile Safari/537.36";

    HttpPost post = new HttpPost(_url);
    post.addHeader("Content-Type", "application/x-www-form-urlencoded");
    post.addHeader("User-Agent", Agent);
    post.addHeader("Connection", "Keep-Alive");

    List params = new ArrayList();
    params.add(new BasicNameValuePair("TypeGroup", "rbGroup2"));
    params.add(new BasicNameValuePair("ddlCity", "A+"));
    params.add(new BasicNameValuePair("ddlSubCity", "%E5%85%A8%E9%83%A8%E9%84%89%E9%8E%AE%E5%8D%80"));
    params.add(new BasicNameValuePair("tbKWQuery", ""));
    params.add(new BasicNameValuePair("TimeGroup", "open24"));
    params.add(new BasicNameValuePair("btnQuery", "%E6%9F%A5+++%E8%A9%A2"));

    UrlEncodedFormEntity ent = new UrlEncodedFormEntity(params, HTTP.UTF_8);
    post.setEntity(ent);

    HttpResponse responsePOST = client.execute(post);
    if (responsePOST.getStatusLine().getStatusCode() == 200) {
    HttpEntity resEntityPOST = responsePOST.getEntity();
    POSTresult = EntityUtils.toString(resEntityPOST);
    }

    再次感謝Tony大大!!

    回覆刪除
    回覆
    1. 不是程式碼的問題,我用軟體直接送資料過去也得不到回應,要查看看網站是不是有防護機制或其他原因

      刪除
  29. 感謝Tony版主的回覆!!
    可以請教一下 防護機制是?或是提到的其他的可能原因嗎?
    因為是這方面的新手, 因此再冒昧請教一次
    我比較有方向去尋找!
    再次感謝版主的回覆!! :)

    回覆刪除
    回覆
    1. 它們網站是用 asp.net 寫的,在傳送 post 資料時會附加識別資料,所以有可能你沒附上的話就請求不成功,asp.net 我不熟,要詢問熟的人看看。

      刪除
    2. 謝謝TONY!!!
      這樣我就知道怎麼往下去尋找
      再次感謝!!

      刪除

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。