Как вызвать метод RESTful из Android?

Я пробовал два разных способа вызова простого метода REST из Android; указанный метод REST, который работает от других клиентов, просто возвращает значение типа int, например 17.

Обе следующие попытки были основаны на коде, который я нашел в Интернете. Один такой:

public void onFetchBtnClicked (View v) {if (v.getId () == R.id.FetchBtn) {Toast.makeText (getApplicationContext (), "Вы нажали кнопку, чувак.", Toast.LENGTH_SHORT).show(); новый 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) ;

...Я получил, "*E/callWebService﹕ IOException in callWebService(). Connection to http://localhost:28642 refused*"

Эта проблема может быть проблемой многопоточности, так как я читал ее в книге О'Рейли "Программирование на Android" Медниекса, Дорнина, Майке и Накамуры: "AsyncTask - удобный инструмент для выполнения небольших асинхронных задач. Просто помните, что метод doInBackground выполняется в другом потоке! Он не должен записывать никакое состояние, видимое из другого потока, или читать любое состояние, доступное для записи из другого потока. Это включает его параметры. "

С другой моей попыткой:

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

... отладчик сбрасывает меня в View.class после попадания в ту же строку проблемы (result = httpclient.execute(request, handler)). Почему это так, я не знаю *, но я думаю, что суть проблемы, как указано в сообщении err msgs в logcat, заключается в следующем: "Причина: android.os.NetworkOnMainThreadException"

* Может быть, потому что в потоке пользовательского интерфейса (View) предпринимается попытка чего-то плохого.

Также (не большое дело, но, пожалуй, "интересно"): Toast не появляется, когда после него выполняется вызов метода (он работает иначе).

Сервер (Web API) имеет точку останова, установленную в соответствующем методе Controller, но она никогда не достигается. Как уже упоминалось, сервер работает и прекрасно реагирует на другие клиенты (приложения Windows).

Должен быть несколько простой способ вызова метода RESTful из Android. Но что / как?

ОБНОВИТЬ

Я попробовал это, теперь тоже, называя это так:

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

... но он также (или кажется, в любом случае) с удовольствием выдает исключение "NetworkOnMainThread".

ОБНОВЛЕНИЕ 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, но они никогда не достигаются.

Что может быть не так?

Является ли "localhost" неправильной вещью (в URL)? Должен ли я использовать имя компьютера вместо этого?

URL (передается буквально как "http://localhost:28642/api/Departments/GetCount?serialNum=4242") нужно дословно?

ОБНОВЛЕНИЕ 4

Изменяя "locohost" на имя машины, я получаю "Нет адреса, связанного с именем хоста", так что это не проблема...

Как ни странно, эта строка работает нормально:

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

... тогда как это последняя строка перед тем, как исключение выдается / перехватывается:

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

Глядя на это, тем не менее, возможно, мне нужно избежать моих ударов; но когда у вас уже есть двойные удары, как, например, после "http:", вы должны делать тройные удары? Или четырехместные удары? Уж точно не потолочный воск...?

1 ответ

Решение

У меня это работает сейчас. Здесь есть статья об этом.

Это код оттуда без каких-либо объяснений:

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

}
Другие вопросы по тегам