Большинству приложений необходимы сетевые подключения к внешним службам для доступа и обмена данными. Обычно это происходит через 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. Это состоит из структурирования кода на два класса. ApiCallRequestBuilderRequestBody
сетей
Пришло время создать некоторые вызовы 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();
}
}
В обоих методах класса ApiCallOkHttpClient Вы можете конструировать методы по-разному, так что каждый раз создается новый клиент, но это не разумное решение, и я рекомендую вам прочитать этот ответ StackOverflow , чтобы доказать, что это лучшее решение.
В обоих методах параметр URL HttpUrl url Он представлен как экземпляр HttpUrlString
public static String POST(OkHttpClient client, String url, RequestBody body) throws IOException {
//...
}
Вы можете применить это в обоих методах, и это будет иметь тот же результат, что и экземпляр HttpUrl Важно отметить, что строка URL может быть неправильно структурирована, что может привести к исключению MalformedURLException .
Последнее, что следует упомянуть, это RequestBodyPOST Он представляет собой набор параметров в парах имя / значение, отправленных в теле запроса POST
Создание запроса URL
Затем вам нужно создать класс Java, который создает URL-адрес сетевого запроса и RequestBodyPOST
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-класс RequestBuilderRequestBodyHttpUrl Примеры состоят из создания RequestBodyHttpUrl
Вернуться к деятельности
До сих пор необходимо подготовить способ работы с сетью из действия и использовать созданные классы. Сначала в классе действия создайте глобальный 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 обычно возвращают потоки JSONXML
Загрузка файлов
В этом разделе я расскажу о загрузке файлов с помощью 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();
}
Эта функция возвращает объект MultipartBodyRequestBodyRequestBuilder
Теперь, когда тело запроса на загрузку завершено, как выполнить вызов на загрузку? Загрузки — это вызовы 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 на основе указанных политик в классе CookieStoreOkHttpClient
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(new CookieStore())
.build();
Теперь вы обновили OkHttpClientCookieStore
Этого примера достаточно для сеансовых файлов cookie, но для тех, кто хочет сохранить файлы cookie при последующих запусках приложения, этой политики недостаточно. Существует решение этой проблемы с помощью реализации PersistentCookieJar, основанной на SharedPreferences Чтобы использовать этот пакет с OkHttpClientинструкциям по использованию .
Все ок?
В этой статье я рассмотрел начало работы с OkHttp и поделился советом, который может пригодиться при работе с ним. Я надеюсь, что вы найдете, что библиотека экономит ваше время и хотела бы знать, что вы создаете с ее помощью.