POST запросы в Android. Как?

970
10 февраля 2017, 02:59

Решил попробовать пописать под Android, соответственно появилось очень большое количество вопросов. Кому не трудно ответьте пожалуйста. Пытаюсь сделать, чтобы приложение работало с неким API, общение с помощью json, но у меня не получается написать класс, как например на шарпе, в который я передаю адрес, параметры и выполняю POST запрос, например как здесь http://stackoverflow.com/questions/4015324/http-request-with-post. Насколько я понял приложение на Android не может выполнить POST запрос из обычного метода, нужно использовать AsyncTask<> - тут я вообще ничего не понял, начиная от самого синтаксиса, а именно doInBackground(String... params) - String... это перечисления параметров при вызове метода типа doInBackground(str1, str2, str3) или как? В общем я не прошу написать за меня готовый код, прошу помочь понять принцип как работать с POST запросами в Android, хотя бы один конкретный пример: отправка POST (json) и получение ответа так же в json и немного теории, пжлст)).

Answer 1

AsyncTask лучше один раз попробовать, и потом забыть про них. То же самое касается и HttpUrlConnection. В настоящий момент основной библиотекой для взаимодействия с Rest сервером в Android считается Retorofti. На официальном сайте есть примеры. Так же их не мало и на сторонних ресурсах, например здесь. Приведу лишь пример POST запроса.

Для этого нам потребуется класс-модель, в которую преобразуется полученный от сервера Json, класс-модель для тела запроса и интерфейс с методом аннотированным специальной анотацией.

Допустим сервер имеет метод, который добавляет почтовые адреса пользователю, и возвращает какую то информацию о статусе операции. В теле запроса сервер принимает обычный массив из строк, а результат возвращает в виде Json.

Сначала создаем модель ответа сервера(поля объявлены как public с целью уменьшения кода, в реальном приложении лучше использовать private + get/set методы):

public class AddEmailResult {
    @SerializedName("email")
    public String email;
    @SerializedName("primary")
    public Boolean primary;
    @SerializedName("verified")
    public Boolean verified;
}

Теперь создаем интерфейс, через который будет происходить взаимодействие с сервером.

public interface Server {
    @POST
    Call<List<AddEmailResult>> addEmail(@Body List<String> emails)
}

Аннотация над методом означает что будет выполнен POST запрос, аннотация @Body указывает на то, что этот объект должен быть передан в теле запроса.

Далее необходимо создать сервера. Делается это так:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com") // Адрес сервера
    .addConverterFactory(GsonConverterFactory.create()) // говорим ретрофиту что для сериализации необходимо использовать GSON
    .build();
Server service = retrofit.create(Server.class);
Call<List<AddEmailResult>> call = service.addEmail(/*list of string*/)
call.enqueue(new Callback<List<AddEmailResult>>() {  
    @Override
    public void onResponse(Call<List<AddEmailResult>> call, Response<List<AddEmailResult>> response) {
        if (response.isSuccessful()) {
            // запрос выполнился успешно, сервер вернул Status 200
        } else {
            // сервер вернул ошибку
        }
    }
    @Override
    public void onFailure(Call<List<AddEmailResult>> call, Throwable t) {
        // ошибка во время выполнения запроса
    }
});

Вызывая метод enqueue() вы говорите что бы запрос выполнился асинхронно. В конце результат придет в переданный callback где его можно обработать. Вот в принципе и все. Данная библиотека не ограничивается одним лишь POST запросом, она умеет делать все, что нужно для разработки клиент-серверного приложения.

Что бы добавить retrofit к себе в проект, необходимо в build.gradle добавить следующее:

compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.google.code.gson:gson:2.6.1'
Answer 2

Вот простой пример отправки запроса. params это просто неограниченный массив стрингов. HttpPost принимает строку которая является адресом скрипта на сервере.
BasicNameValuePair - это просто список ключ значение того, что вы отправляете. response это то что вывел нам серверный скрипт. Совсем не обязательно делать это в AsyncTask. Но обычно делают в нем. Т.к это не моментальная операция и лучше бы ее обрабатывать в новом потоке. Если нужно что-то конкретно пояснить, напишите в комментариях. Я отвечу

String doInBackground(String... params) throws IOException {
            DefaultHttpClient hc = new DefaultHttpClient();
            ResponseHandler<String> res = new BasicResponseHandler();
            HttpPost postMethod = new HttpPost(params[0]);
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(3);
            //nameValuePairs.add(new BasicNameValuePair("ID_group", PageViewActivity.Get_list_group.get(PageViewActivity.Cur_group_position).get(0)));
            nameValuePairs.add(new BasicNameValuePair("ID_group", group_id));
            nameValuePairs.add(new BasicNameValuePair("Login", Login));
            nameValuePairs.add(new BasicNameValuePair("Password", Password));
            postMethod.setEntity(new UrlEncodedFormEntity(nameValuePairs));
            String response = hc.execute(postMethod, res);
            System.out.println(response);
            return response;
        }

А теперь о парсинге json. response - строка с json

            JSONObject jsonResponse = new JSONObject(response);
            JSONArray movies = jsonResponse.getJSONArray("Resourse");
            for (int i = 0; i < movies.length(); i++) {
                JSONObject actor = null;
                actor = movies.getJSONObject(i);
                String Text = null;
                Text = actor.getString("ID");
                News_list.add(text);
           }

Пример самого json который мы парсим можно тут увидеть. Чисто для понимания формата http://contester.ddns.is74.ru:84/Get_all_group_list.ashx

Answer 3

Вот ещё один пример с готовой активностью, отправляющий на сервер простой json. Скопировал из своего ответа:

public class MainActivity extends Activity {
ProgressDialog dialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    new RequestTask().execute("http://www.site.ru/login.php"); // скрипт, на который посылаем запрос
}
public String getJSON(String login, String pass) // получаем json объект в виде строки
{
    JSONObject bot = new JSONObject();
    try {
        bot.put("Login", login);
        bot.put("Password", pass);
    } catch (JSONException e) {
        e.printStackTrace();
    }
    return bot.toString();
}
public class RequestTask extends AsyncTask<String, String, String> {
    @Override
    protected String doInBackground(String... params) {
        try {
            DefaultHttpClient hc = new DefaultHttpClient();
            ResponseHandler<String> res = new BasicResponseHandler();
            HttpPost postMethod = new HttpPost(params[0]);
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
            // ключ - "json", параметр - json в виде строки
            nameValuePairs.add(new BasicNameValuePair("json", getJSON("userlogin", "userpass")));
            UrlEncodedFormEntity entity = new UrlEncodedFormEntity(nameValuePairs, "UTF-8");
            postMethod.setEntity(entity);
            return hc.execute(postMethod, res);
        } catch (Exception e) {
            System.out.println("Exp=" + e);
        }
        return null;
    }
    @Override
    protected void onPostExecute(String res) {
        dialog.dismiss();
        // res - ответ сервера
        super.onPostExecute(res);
    }
    @Override
    protected void onPreExecute() {
        dialog = new ProgressDialog(MainActivity.this);
        dialog.setMessage("Ожидание");
        dialog.setIndeterminate(true);
        dialog.setCancelable(false);
        dialog.show();
        super.onPreExecute();
    }
}
}

Обработать запрос можно, например, на PHP:

<?php
$json = $_POST['json']; // получаем json объект
$array = json_decode($json, true); // преобразуем его в ассоциативный массив
// получаем из него данные
$login = $array['Login'];
$pass = $array['Password'];
// дальше уже делаем то, что нужно
file_put_contents('login.txt', "$login\n$pass");
?>
READ ALSO
POST xml Bad Request 400

POST xml Bad Request 400

имеется XML файл matchxml, через curl легко отправить POST и добавить в базу

297
Что возвращает substring(0, 0)

Что возвращает substring(0, 0)

Хотелось бы узнать: какую строку возвращает substring(0, 0), если вызывающая строка состоит только из одного символа?

258
Разница между return (val) и return val

Разница между return (val) и return val

Есть ли разница между return (val) и return val?

251
Проблема отображения навигации Fancybox

Проблема отображения навигации Fancybox

ЗдравствуйтеЕсть блок слайдера с изображениями:

443