Большинству приложений необходимы сетевые подключения к внешним службам для доступа и обмена данными. Обычно это происходит через API REST и HTTP-клиент в вашем приложении. OKHttp — это клиентская HTTP-библиотека Android от Square, которая сокращает количество необходимых шагов и позволяет уделять больше времени важным областям вашего приложения.
Почему OkHttp?
Это простая библиотека для использования, загрузка данных быстрее и экономия полосы пропускания. Это устраняет необходимость в тестировании сети, восстановлении после распространенных проблем с подключением и при сбое подключения OkHttp может повторить запрос с другим маршрутом.
OkHttp поддерживает Android 2.3 и выше, что составляет более 99% рынка, основываясь на текущей статистике использования версий.
Использование OkHttp в вашем приложении
OkHttp недавно обновлен до версии 3.0 и в настоящее время имеет версию 3.3.1. Я упоминаю об этом, потому что OkHttp сделал ключевые обновления в этой версии, а методы из предыдущих версий устарели.
Вы можете найти все примеры, которые я расскажу на GitHub .
Добавить зависимости
Откройте build.gradle (Module: app) и добавьте следующую зависимость или проверьте сайт OkHttp на наличие последних обновлений.
dependencies {
//...
compile 'com.squareup.okhttp3:okhttp:3.3.1'
}
В AndroidManifest.xml добавьте интернет-разрешение.
<uses-permission android:name="android.permission.INTERNET"/>
Сеть с OkHttp
Основное внимание в этой статье будет уделено построению следующих сетевых вызовов.
- ПОЛУЧИТЬ
- ПОЧТА
- Загрузка файлов с помощью OkHttp
- Мониторинг запросов и ход выполнения ответов
- Обрабатывать куки с OkHttp
Примечание : я стараюсь писать не избыточный код, а СУХОЙ код. Я чувствую, что сделал все возможное, чтобы оптимизировать работу моего кода с помощью OkHttp. Это состоит из структурирования кода на два класса. ApiCall
RequestBuilder
RequestBody
сетей
Пришло время создать некоторые вызовы API , в частности сетевые запросы GET и POST. Создайте следующий класс Java для обработки каждого из запросов.
public class ApiCall {
//GET network request
public static String GET(OkHttpClient client, HttpUrl url) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
//POST network request
public static String POST(OkHttpClient client, HttpUrl url, RequestBody body) throws IOException {
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
return response.body().string();
}
}
В обоих методах класса ApiCall
OkHttpClient
Вы можете конструировать методы по-разному, так что каждый раз создается новый клиент, но это не разумное решение, и я рекомендую вам прочитать этот ответ StackOverflow , чтобы доказать, что это лучшее решение.
В обоих методах параметр URL HttpUrl url
Он представлен как экземпляр HttpUrl
String
public static String POST(OkHttpClient client, String url, RequestBody body) throws IOException {
//...
}
Вы можете применить это в обоих методах, и это будет иметь тот же результат, что и экземпляр HttpUrl
Важно отметить, что строка URL может быть неправильно структурирована, что может привести к исключению MalformedURLException .
Последнее, что следует упомянуть, это RequestBody
POST
Он представляет собой набор параметров в парах имя / значение, отправленных в теле запроса POST
Создание запроса URL
Затем вам нужно создать класс Java, который создает URL-адрес сетевого запроса и RequestBody
POST
public class RequestBuilder {
//Login request body
public static RequestBody LoginBody(String username, String password, String token) {
return new FormBody.Builder()
.add("action", "login")
.add("format", "json")
.add("username", username)
.add("password", password)
.add("logintoken", token)
.build();
}
public static HttpUrl buildURL() {
return new HttpUrl.Builder()
.scheme("https") //http
.host("www.somehostname.com")
.addPathSegment("pathSegment")//adds "/pathSegment" at the end of hostname
.addQueryParameter("param1", "value1") //add query parameters to the URL
.addEncodedQueryParameter("encodedName", "encodedValue")//add encoded query parameters to the URL
.build();
/**
* The return URL:
* https://www.somehostname.com/pathSegment?param1=value1&encodedName=encodedValue
*/
}
}
Java-класс RequestBuilder
RequestBody
HttpUrl
Примеры состоят из создания RequestBody
HttpUrl
Вернуться к деятельности
До сих пор необходимо подготовить способ работы с сетью из действия и использовать созданные классы. Сначала в классе действия создайте глобальный OkHttpClient
public class MainActivity extends AppCompatActivity {
private OkHttpClient client;
//...
}
Инициализируйте клиента в onCreate()
@Override
protected void onCreate(Bundle savedInstanceState) {
//...
client = new OkHttpClient();
//...
}
Вы должны обрабатывать сетевые вызовы в Android асинхронно, в противном случае выдается исключение NetworkOnMainThreadException, когда приложение пытается выполнить сетевую операцию в главном потоке. Чтобы избежать этого исключения, используйте AsyncTask
.
Добавьте эти методы в свою активность:
private void loadContent() {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
try {
response = ApiCall.GET(client, RequestBuilder.buildURL());
//Parse the response string here
Log.d("Response", response);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}.execute();
}
private void attemptLogin(String url) {
new AsyncTask<String, Void, Void>() {
@Override
protected Void doInBackground(String... params) {
try {
response = ApiCall.POST(
client,
params[0],
RequestBuilder.LoginBody("username", "password","token"));
Log.d("Response", response);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}.execute(url);
}
Две функции, показанные здесь, представляют оба примера в классе RequestBuilder
Они только для демонстрационных целей, и вы могли бы конструировать их по-другому.
Оставляя в стороне реализацию AsyncTask
Весь код, реализованный в обоих предыдущих классах, структурирован в одну строку, которая возвращает тело ответа сетевого запроса, а избыточный код отсутствует. Довольно круто!
ApiCall.GET(client, RequestBuilder.buildURL());
После получения ответа может потребоваться некоторый анализ, поскольку API обычно возвращают потоки JSON
XML
Загрузка файлов
В этом разделе я расскажу о загрузке файлов с помощью OkHttp
Один из распространенных типов загрузки — multipart/form-data
В следующем примере загрузки изображения показано, как OkHttp может справиться с этим, но он действителен для других типов файлов.
//Upload request body
public static MultipartBody uploadRequestBody(String title, String imageFormat, String token, File file) {
MediaType MEDIA_TYPE = MediaType.parse("image/" + imageFormat); // e.g. "image/png"
return new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("action", "upload")
.addFormDataPart("format", "json")
.addFormDataPart("filename", title + "." + imageFormat) //e.g. title.png --> imageFormat = png
.addFormDataPart("file", "...", RequestBody.create(MEDIA_TYPE, file))
.addFormDataPart("token", token)
.build();
}
Эта функция возвращает объект MultipartBody
RequestBody
RequestBuilder
Теперь, когда тело запроса на загрузку завершено, как выполнить вызов на загрузку? Загрузки — это вызовы POST
File file = new File(""); //provide a valid file
ApiCall.POST(client, url, RequestBuilder.uploadRequestBody("title", "png", "someUploadToken", file));
Не забудьте назвать это асинхронно. Этот вызов возвращает подтверждение действия загрузки, успешно или нет.
Что дальше
Это все для основ OkHttp, но далее я упомяну некоторые советы и инструменты, которые могут быть полезны с OkHttp.
Мониторинг хода выполнения запроса
Часто при загрузке мультимедиа полезна возможность отслеживать прогресс. Некоторое время назад я нашел это решение Gist, которое является решением этой проблемы. Чтобы отслеживать ход выполнения запроса с этим решением, вы создаете экземпляр RequestBody
//Monitored request
File file = new File("");
MultipartBody body = RequestBuilder.uploadRequestBody("title", "png", "someUploadToken", file);
CountingRequestBody monitoredRequest = new CountingRequestBody(body, new CountingRequestBody.Listener() {
@Override
public void onRequestProgress(long bytesWritten, long contentLength) {
//Update a progress bar with the following percentage
float percentage = 100f * bytesWritten / contentLength;
if (percentage >= 0) {
//TODO: Progress bar
} else {
//Something went wrong
}
}
});
Я изменил код для использования его с OkHttp 3. Вот ссылка на класс в GitHub с соответствующими изменениями.
Обрабатывать Cookies с OkHttp
Вы можете обрабатывать куки в OkHttp с CookieJar
Следующий пример является примером того, как обрабатывать куки в OkHttp.
public class CookieStore implements CookieJar {
private final Set<Cookie> cookieStore = new HashSet<>();
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
/**
*Saves cookies from HTTP response
* If the response includes a trailer this method is called second time
*/
//Save cookies to the store
cookieStore.addAll(cookies);
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
/**
* Load cookies from the jar for an HTTP request.
* This method returns cookies that have not yet expired
*/
List<Cookie> validCookies = new ArrayList<>();
for (Cookie cookie : cookieStore) {
LogCookie(cookie);
if (cookie.expiresAt() < System.currentTimeMillis()) {
// invalid cookies
} else {
validCookies.add(cookie);
}
}
return validCookies;
}
//Print the values of cookies - Useful for testing
private void LogCookie(Cookie cookie) {
System.out.println("String: " + cookie.toString());
System.out.println("Expires: " + cookie.expiresAt());
System.out.println("Hash: " + cookie.hashCode());
System.out.println("Path: " + cookie.path());
System.out.println("Domain: " + cookie.domain());
System.out.println("Name: " + cookie.name());
System.out.println("Value: " + cookie.value());
}
}
Для обработки файлов cookie на основе указанных политик в классе CookieStore
OkHttpClient
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(new CookieStore())
.build();
Теперь вы обновили OkHttpClient
CookieStore
Этого примера достаточно для сеансовых файлов cookie, но для тех, кто хочет сохранить файлы cookie при последующих запусках приложения, этой политики недостаточно. Существует решение этой проблемы с помощью реализации PersistentCookieJar, основанной на SharedPreferences
Чтобы использовать этот пакет с OkHttpClient
инструкциям по использованию .
Все ок?
В этой статье я рассмотрел начало работы с OkHttp и поделился советом, который может пригодиться при работе с ним. Я надеюсь, что вы найдете, что библиотека экономит ваше время и хотела бы знать, что вы создаете с ее помощью.