Использование WEB API в вашем Android приложении

Использование WEB API в вашем Android приложении

Достаточно часто возникает потребность получения данных из интернета в вашем Android приложении. В этой статье мы рассмотрим, как получать данные о пользователях через API, из вашего приложения.

Есть два основных, широко используемых формата данных, это XML и JSON. XML расшифровывается как eXtensible Markup Language (расширяемый язык разметки), и его синтаксис напоминает еще один язык разметки - HTML (Hyper Text Markup Language).  Ниже пример XML:

<human>
    <sex>Male</sex>
    <age>27</age>
    <occupation>Software Developer</occupation>
</human>

JSON расшифровывается как JavaScript Object Notation, и это намек на то, что формат был разработан специально для JavaScript'а. JSON более стандартизирован, и более понятен для человека. Ниже пример JSON:

{
    human: {
        sex:"Male", 
        age:"27", 
        occupation:"Software Developer"
    }
}

В этой статье мы будем использовать JSON.  А чтобы было еще проще разобраться, наше приложение будет состоять всего из нескольких элементов и принцип работы у него будет такой:

  • EditText - для ввода текста.
  • Button - для отправки запроса к API.
  • TextView - для отображения результатов запроса.

Теперь нам нужно определиться какое API мы будем использовать. Не долго думая, я остановился на GitHub API, тем более, что оно у них открыто и даже не требует авторизации.

AndroidManifest.xml

Нашему приложению, нужен доступ в интернет, поэтому мы должны описать это разрешение в AndroidManifest.xml файле. Обратите внимание, что запрос на такое разрешение должен быть перед тегом <application>.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="su.zacorp.zacorp" >

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

Activity Layout

У нас будет очень простой Layout, как я уже писал выше он будет из EditText, в который мы будем вводить логин пользователя на  GitHub, кнопка для отправки запроса к API, под ними будет расположен TextView (обернутый в ScrollView), который просто будет отображать полученный JSON, и ProgressBar который по умолчанию будет спрятан с помощью android:visibility="gone". ProgressBar будет появляться когда мы нажмем на кнопку и исчезать когда данные будут получены и выведены на экран.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.sample.foo.simplewebapi.MainActivity">
    <EditText
        android:id="@+id/loginText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="textEmailAddress"
        android:hint="Enter GitHub user login"/>
    <Button
        android:id="@+id/queryButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end"
        style="@style/Base.Widget.AppCompat.Button.Borderless"
        android:text="Search"/>

    <TableRow
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="right"></TableRow>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center">
        <ProgressBar
            android:id="@+id/progressBar"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:indeterminate="true"
            android:layout_centerHorizontal="true"
            android:visibility="gone" />
        <ScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <TextView
                android:id="@+id/responseView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </ScrollView>
    </RelativeLayout>
</LinearLayout>

Main Activity

Прежде, чем мы начнем писать код для, хотелось бы обратить Ваше внимание, на очень важный момент. Android приложения, версии ниже Ice Cream, могли открывать подключения к сети и делать запросы из основного потока пользовательского интерфейса. В связи с этим приложение переставало реагировать, пока ждет ответ. Сейчас же правила ужесточились, и сетевые запросы теперь должны выполняться в отдельном потоке.  К нашему с вами счастью все уже сделали за нас, и теперь есть специальный класс который называется AsyncTask. Если сравнивать с Web, то он очень похож на Jquery.

Чтобы использовать возможности AsyncTask, нам нужно унаследоваться от него, и предоставить 3 общих типа - Params, Progress и Result. Params относится к параметрам, которые будут разобраны вашим Task'ом, Progress относится к типу индикатор прогресса/счетчика, а Result - это то, что будет возвращено по окончанию выполнения задачи. У AsyncTask есть 4 важных метода, onPreExecute (перед выполнением задачи), doInBackground (выполнение непосредственно самой задачи), onProgressUpdate (что делать, чтобы показать прогресс), и onPostExecute (после того как задача выполнена ).

package su.zacorp.zacorp;

import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;


public class MainActivity extends AppCompatActivity {

    EditText loginText;
    TextView responseView;
    ProgressBar progressBar;

    static final String API_URL = "https://api.github.com/users/";

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

        responseView = (TextView) findViewById(R.id.responseView);
        loginText = (EditText) findViewById(R.id.loginText);
        progressBar = (ProgressBar) findViewById(R.id.progressBar);

        Button queryButton = (Button) findViewById(R.id.queryButton);
        queryButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new RetrieveFeedTask().execute();
            }
        });
    }

    class RetrieveFeedTask extends AsyncTask<Void, Void, String> {

        private Exception exception;

        protected void onPreExecute() {
            progressBar.setVisibility(View.VISIBLE);
            responseView.setText("");
        }

        protected String doInBackground(Void... urls) {
            String login = loginText.getText().toString();
            // Do some validation here

            try {
                URL url = new URL(API_URL + login);
                HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                try {
                    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
                    StringBuilder stringBuilder = new StringBuilder();
                    String line;
                    while ((line = bufferedReader.readLine()) != null) {
                        stringBuilder.append(line).append("\n");
                    }
                    bufferedReader.close();
                    return stringBuilder.toString();
                }
                finally{
                    urlConnection.disconnect();
                }
            }
            catch(Exception e) {
                Log.e("ERROR", e.getMessage(), e);
                return null;
            }
        }

        protected void onPostExecute(String response) {
            if(response == null) {
                response = "THERE WAS AN ERROR";
            }
            progressBar.setVisibility(View.GONE);
            Log.i("INFO", response);
            responseView.setText(response);
        }
    }
}

Из приведенного выше кода, RetrieveFeedTask наследуется от  AsyncTask<Void, Void, String>, который указывает тип Params Void, Progress Void и Result String.

В методе onPreExecute, мы показываем ProgressBar, и чистим содержимое TextView. Это делается до того, как задача начинает выполняться.

Метод doInBackground ожидает Params, который в нашем случае Void. После этого мы создаем и открываем HttpURLConnection, чтобы сделать запрос API. URL адрес состоит из домена и имени пользователя, который мы ввели в EditText.

Метод onPostExecute скрывает ProgressBar, и отображает полученный ответ в TextView.

В заключении

В этом примере мы вообще ничего не делаем с JSON'ом который возвращается к нам. Обычно возвращаемый JSON преобразуется в Java Object, и дальше работают уже с объектами. Есть разные библиотеки для манипулирования и использования JSON объектов (например GSON и Jackson). А также есть более простой org.json пакет, который по умолчанию встроен в Android. Разобрать ответ в JSONObject, можно примерно следующим образом:

try {
    JSONObject object = (JSONObject) new JSONTokener(response).nextValue();
    String requestID = object.getString("requestId");
    int likelihood = object.getInt("likelihood");
    JSONArray photos = object.getJSONArray("photos");
    .
    .
    .
    .
} catch (JSONException e) {
    // Appropriate error handling code
}

Комментарии

К сожалению, комментариев пока нет
Для того чтобы оставлять комментарии, вам необходимо авторизоваться. Вход