How to call a RESTful Method from Android?

2019-03-04 12:23发布

I've tried two different ways to call a simple REST method from Android; said REST method - which works from other clients - simply returns an int val such as 17.

Both of the following attempts were based on code I found online. One is like so:

public void onFetchBtnClicked(View v){ if(v.getId() == R.id.FetchBtn){ Toast.makeText(getApplicationContext(), "You mashed the button, dude.", Toast.LENGTH_SHORT).show(); new NetworkTask().execute(); } }

public static class NetworkTask extends 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); }

With the code above, after the following line of code fails:

result = httpclient.execute(request, handler) ;

...I get, "*E/callWebService﹕ IOException in callWebService(). Connection to http://localhost:28642 refused*"

This problem may be a threading issue, as I read this in O'Reilly's "Programming Android" book by Mednieks, Dornin, Meike, and Nakamura: "AsyncTask is a convenenient tool for running small, asynchronous tasks. Just remember that the doInBackground method runs on a different thread! It must not write any state visible from another thread or read any state writable from another thread. This includes its parameters."

With my other attempt:

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

...the debugger dumps me into View.class after hitting that same problem line (result = httpclient.execute(request, handler)). Why it does that, I don't know*, but I think the crux of the problem, as indicated by err msgs in logcat, is: "Caused by: android.os.NetworkOnMainThreadException"

*Maybe because something untoward is being attempted within the UI (View) thread.

Also (not a big deal, but "interesting," perhaps): the Toast doesn't pop up when a method call is made after it (it works otherwise).

The (Web API) server has a breakpoint set in its corresponding Controller method, but it is never reached. As mentioned, the server is running, and responds just fine to other (Windows app) clients.

There must be a somewhat straightforward way of calling a RESTful method from Android. But what/how?

UPDATE

I tried this, now, too, calling it like so:

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

...but it also is (or seems, anyway) happy to throw the "NetworkOnMainThread" exception.

UPDATE 2

This is the closest I've gotten so far, I think. Maybe the server is the culprit in this case, because with this code:

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

....the exception that is thrown is:

libcore.io.ErrnoException: connect failed: ECONNREFUSED (Connection refused) failed to connect to localhost/127.0.0.1 (port 28642): connect failed: ECONNREFUSED (Connection refused)

...and the Android app continues to run (it falls over in the other examples).

Why is my server refusing the connection?

UPDATE 3

I thought for a minute I had it: I forgot to pass the serial Num with the URL. But even after doing so, it fails.

I have a breakpoint in the server app, in the Controller method; also, in the Repository method, but they are never reached.

What could be wrong?

Is "localhost" the wrong thing to use (in the URL)? Should I use the name of the computer instead?

Does the URL (passed literally as "http://localhost:28642/api/Departments/GetCount?serialNum=4242") need to be verbatimized?

UPDATE 4

Changing the "locohost" to the machine name, I get "No address associated with hostname" so that's not the problem...

Oddly, though, this line runs fine:

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

...whereas this is the last line before the exception is thrown/caught:

in = new BufferedInputStream(urlConnection.getInputStream());

Looking at this, though, perhaps I need to escape my whacks; but when you already have double-whacks, as in after "http:", do you have to do triple-whacks? Or quadruple whacks? Surely not ceiling wax...?

1条回答
放我归山
2楼-- · 2019-03-04 12:53

I've got it working now. There's an article about it here.

This is the code from there without any explanation:

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

}
查看更多
登录 后发表回答