如何从Android调用RESTful方法?

时间:2014-04-01 21:25:10

标签: multithreading rest httpclient ui-thread networkonmainthread

我尝试过两种不同的方式从Android调用一个简单的REST方法;所谓的REST方法 - 它可以从其他客户端运行 - 只返回一个int值,例如17。

以下两种尝试均基于我在网上找到的代码。一个是这样的:

public void onFetchBtnClicked(View v){     if(v.getId()== R.id.FetchBtn){         Toast.makeText(getApplicationContext(),"你把按钮弄糟了,伙计。",Toast.LENGTH_SHORT).show();         new NetworkTask()。execute();     } }

公共静态类NetworkTask扩展了AsyncTask {

@Override
protected String doInBackground(Void... params) {
    final String TAG;
    TAG = "callWebService";
    String deviceId = "Android Device";

    HttpClient httpclient = new DefaultHttpClient();
    HttpGet request = new HttpGet("http://localhost:28642/api/Departments/GetCount");
    request.addHeader("deviceId", deviceId);

    ResponseHandler<String> handler = new BasicResponseHandler();
    String result = "";

    try
    {
        result = httpclient.execute(request, handler);
    }
    catch (ClientProtocolException e)
    {
        e.printStackTrace();
        Log.e(TAG, "ClientProtocolException in callWebService(). " + e.getMessage());
    }
    catch (IOException e)
    {
        e.printStackTrace();
        Log.e(TAG, "IOException in callWebService(). " + e.getMessage());
    }

    httpclient.getConnectionManager().shutdown();
    Log.i(TAG, "**callWebService() successful. Result: **");
    Log.i(TAG, result);
    Log.i(TAG, "*****************************************");

    return result;
}

@Override
protected void onPostExecute(String result) {
    final String TAG;
    TAG = "onPostExecute";
    if (null != result)

Log.i(TAG,结果);     }

使用上面的代码,在以下代码行失败后:

result = httpclient.execute(request, handler) ;

...我明白了,&#34; *E/callWebService﹕ IOException in callWebService(). Connection to http://localhost:28642 refused*&#34;

这个问题可能是一个线程问题,正如我在O&#39; Reilly&#34;编程Android&#34;由Mednieks,Dornin,Meike和Nakamura撰写的书:&#34; AsyncTask是一个用于运行小型异步任务的会议工具。请记住,doInBackground方法在不同的线程上运行!它不能写任何从另一个线程可见的状态或读取任何可从另一个线程写入的状态。这包括其参数。&#34;

我的另一次尝试:

public void onFetchBtnClicked(View v){
    if(v.getId() == R.id.FetchBtn){
        Toast.makeText(getApplicationContext(), "You mashed the button, dude.", Toast.LENGTH_SHORT).show();
        callWebService("http://localhost:28642/api/Departments/GetCount");
    }
}

public String callWebService(String requestUrl)
{
    final String TAG;
    TAG = "callWebService";
    String deviceId = "Android Device";

    HttpClient httpclient = new DefaultHttpClient();
    HttpGet request = new HttpGet(requestUrl);
    request.addHeader("deviceId", deviceId);

    ResponseHandler<String> handler = new BasicResponseHandler();
    String result = "";

    try
    {
        result = httpclient.execute(request, handler);
    }
    catch (ClientProtocolException e)
    {
        e.printStackTrace();
        Log.e(TAG, "ClientProtocolException in callWebService(). " + e.getMessage());
    }
    catch (IOException e)
    {
        e.printStackTrace();
        Log.e(TAG, "IOException in callWebService(). " + e.getMessage());
    }

    httpclient.getConnectionManager().shutdown();
    Log.i(TAG, "**callWebService() successful. Result: **");
    Log.i(TAG, result);
    Log.i(TAG, "*****************************************");

    return result;
}

...调试器在遇到相同的问题行(result = httpclient.execute(request,handler))之后将我转储到View.class中。为什么会这样,我不知道*,但我认为问题的关键,如logcat中的错误信息所示,是:&#34;引起:android.os.NetworkOnMainThreadException&#34;

*也许是因为在UI(View)线程中尝试了一些不愉快的事情。

另外(不是什么大不了,但是很有趣,&#34;也许):Toast在它之后进行方法调用时不会弹出(否则就会起作用)。

(Web API)服务器在其相应的Controller方法中设置了断点,但从未到达。如上所述,服务器正在运行,并且对其他(Windows应用程序)客户端响应良好。

必须有一种从Android调用RESTful方法的简单方法。但是/怎么样?

更新

我现在也试过this,这样称呼它:

RestClient client = new RestClient("http://localhost:28642/api/Departments/GetCount");

    try {
        client.Execute(RestClient.RequestMethod.GET);
    } catch (Exception e) {
        e.printStackTrace();
    }

    String response = client.getResponse();
    Log.i("CZECH_THIS", response);

...但它也是(或似乎,无论如何)很高兴抛出&#34; NetworkOnMainThread&#34;异常。

更新2

我认为这是我迄今为止最接近的。在这种情况下,服务器可能是罪魁祸首,因为使用此代码:

public void onFetchBtnClicked(View v){
    if(v.getId() == R.id.FetchBtn){
        Toast.makeText(getApplicationContext(), "You mashed the button, dude.", Toast.LENGTH_SHORT).show();
    new CallAPI().execute("http://localhost:28642/api/Departments/GetCount");
    }
}

public static class CallAPI extends AsyncTask<String, String, String> {

    @Override
    protected String doInBackground(String... params) {

        String urlString=params[0]; // URL to call
        String resultToDisplay = "";
        InputStream in = null;

        // HTTP Get
        try {
            URL url = new URL(urlString);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            in = new BufferedInputStream(urlConnection.getInputStream());

        } catch (Exception e ) {
            System.out.println(e.getMessage());
            return e.getMessage();
        }
        return resultToDisplay;

    }

    protected void onPostExecute(String result) {
        Log.i("FromOnPostExecute", result);
    }

} // end CallAPI

....引发的异常是:

libcore.io.ErrnoException:连接失败:ECONNREFUSED(拒绝连接) 无法连接到localhost / 127.0.0.1(端口28642):连接失败:ECONNREFUSED(拒绝连接)

...并且Android应用程序继续运行(在其他示例中它会失败)。

为什么我的服务器拒绝连接?

更新3

我想了一会儿:我忘了用URL传递序列号。但即便这样做,也会失败。

我在服务器应用程序中有一个断点,在Controller方法中;此外,在Repository方法中,但它们永远不会到达。

可能有什么不对?

是&#34; localhost&#34;使用错误的东西(在URL中)?我应该使用计算机的名称吗?

网址(字面意思为&#34; http://localhost:28642/api/Departments/GetCount?serialNum=4242&#34;)是否需要逐字逐句?

更新4

更改&#34; locohost&#34;对于机器名称,我得到&#34;没有与主机名相关的地址&#34;所以这不是问题...

奇怪的是,这条线路运行良好:

HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

...而这是抛出/捕获异常之前的最后一行:

in = new BufferedInputStream(urlConnection.getInputStream());
但是,看看this,或许我需要摆脱我的打击;但是当你已经有了双重打击时,就像在&#34; http:&#34;之后,你必须做三重打击吗?还是四重打击?当然不是天花板蜡......?

1 个答案:

答案 0 :(得分:0)

我现在已经开始工作了。有一篇关于它的文章here

这是来自那里的代码,没有任何解释:

public class MainActivity extends ActionBarActivity {

    private GetDepartmentsCount _getDeptsCount;

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

        Button getDeptsCountBtn = (Button)findViewById(R.id.DeptsCountBtn);
        getDeptsCountBtn.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                _getDeptsCount = new GetDepartmentsCount();
                _getDeptsCount.execute("http://10.0.2.2:28642/api/Departments/GetCount?serialNum=4242");
            }
        });
    }

    @Override
    public void onStop() {
        super.onStop();
        _getDeptsCount.cancel(true);
    }

    private class GetDepartmentsCount extends AsyncTask<String, String, String> {

        @Override
        protected String doInBackground(String... params) {

            String urlString = params[0]; // URL to call
            String result = "";

            // HTTP Get
            try {
                URL url = new URL(urlString);
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                InputStream inputStream = urlConnection.getInputStream();
                if (null != inputStream)
                    result = IOUtils.toString(inputStream);
            } catch (Exception e) {
                System.out.println(e.getMessage());
                return e.getMessage();
            }
            return result;
        }

        @Override
        protected void onPostExecute(String result) {
            EditText dynCount = (EditText)findViewById(R.id.dynamicCountEdit);
            dynCount.setText(result + " records were found");
            Log.i("FromOnPostExecute", result);
        }
    } 

}