Файл JSON с местоположениями библиотек
Мы снова будем использовать формат JSON в качестве транспорта для пере
-
дачи данных. Вот как должен выглядеть файл
location.json
:
[
{
"street_address": "123 Eiffel Tower Street",
"city": "Paris",
"country": "France",
"emoji": "
",
"hours": "8am–7pm"
352
Сетевые операции в приложении
},
{
"street_address": "86 Libery Boulevard",
"city": "New York",
"country": "America",
"emoji": "
",
"hours": "6am–10pm"
},
{
"street_address": "49 Lombard Street",
"city": "San Francisco",
"country": "America",
"emoji": "
",
"hours": "8am–8pm"
},
{
"street_address": "1901 Aussie Way",
"city": "Melbourne",
"country": "Australia",
"emoji": "
",
"hours": "7am–8pm"
},
{
"street_address": "302 Deutsch Avenue",
"city": "Berlin",
"country": "Germany",
"emoji": "
",
"hours": "9am–6pm"
}
]
Как вы могли заметить, здесь перечислены местонахождения нескольких
библиотек. Это всего лишь примеры (а не реальные библиотеки), которые ис
-
пользуются для иллюстрации структуры данных. Вы можете добавить сюда
свои библиотеки – не стесняйтесь проявлять творческую сметку!
в
ызов
служБы
Чтобы отправить запрос этой службе, в Android и iOS рекомендуется создать
отдельный объект, отвечающий за сетевые взаимодействия, вместо непосред
-
ственного использования API на уровне представления. Поэтому далее созда
-
дим объект
LocationsController
, который будет играть роль посредника между
пользовательским интерфейсом поиска и сетевой службой. Закончив создание
объекта, мы включим его в работу.
Сначала реализуем объект в Android.
Android
В Android имеется ряд служб, готовых помочь в организации взаимодействий
с веб-службами RESTful, но мы, как и прежде, вновь обратимся к стандартным
Вызов службы
353
библиотекам и будем выполнять сетевые запросы с их помощью, как было по
-
казано в главе 9. Поскольку мы знаем, что результат будет иметь вид строки
в формате JSON, то снова обратимся к библиотеке Gson, которая обсуждалась
в главе 12. Так как мы уже видели многое из того, что потребуется в нашем при
-
ложении, например десериализацию JSON, взаимодействие
RecyclerView
с
Adapt
er
и передачу данных через
Intent
, перейдем прямо к коду. Далее представлена
реализация
Ac ti vi ty
, включающая весь необходимый код поиска и пользо
-
вательский интерфейс. Если бы это приложение было больше или требовало
большей гибкости, мы, вероятно, начали бы с выделения логических блоков
в соответствующие классы и интерфейсы. Но, так как все это мы уже виде
-
ли раньше, просто возьмем этот файл с кодом, написанным на скорую руку
и включающим полный набор функций, и передадим его нашему заказчику
(который, как мы знаем, никогда не отличался ни своим терпением, ни стрем
-
лением к элегантному коду):
Java
public class SearchResultsAc ti vi ty extends Ac ti vi ty {
public static final String QUERY = "QUERY";
private ProgressBar mProgressBar;
private RecyclerView mRecyclerView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
mProgressBar = findViewById(R.id.search_progress);
mRecyclerView = findViewById(R.id.search_results_recyclerview);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
String query = getIntent().getStringExtra(QUERY);
new Thread(() -> fetchResults("magic://my.app/search?query=" + query)).start();
}
private void onResultsReceived(List locations) {
mProgressBar.setVisibility(View.GONE);
mRecyclerView.setVisibility(View.VISIBLE);
Adapter adapter = new Adapter(locations);
mRecyclerView.setAdapter(adapter);
}
private void fetchResults(String urlWithQuery) {
try {
StringBuilder builder = new StringBuilder();
URL url = new URL(urlWithQuery);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
int data;
while ((data = connection.getInputStream().read()) != -1) {
builder.append((char) data);
}
String json = builder.toString();
List locations = new Gson().fromJson(json,
new TypeToken>(){}.getType());
354
Сетевые операции в приложении
onResultsReceived(locations);
} catch (IOException e) {
Log.d("MyApp",
"Something went wrong when fetching results. Probably the fake URL! " +
e.getMessage());
}
}
private static class Adapter extends RecyclerView.Adapter {
private List mLocations;
public Adapter(List locations) {
mLocations = locations;
}
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(new TextView(parent.getContext()));
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Location location = mLocations.get(position);
holder.mTextView.setText(location.getStreetAddress() + ", " +
location.getCity() + ", " + location.getCountry());
}
@Override
public int getItemCount() {
return mLocations.size();
}
private static class ViewHolder extends RecyclerView.ViewHolder {
private TextView mTextView;
public ViewHolder(View itemView) {
super(itemView);
mTextView = (TextView) itemView;
}
}
}
}
Kotlin
class SearchResultsAc ti vi ty : Ac ti vi ty() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_search)
search_results_recyclerview.layoutManager = LinearLayoutManager(this)
val query = intent.getStringExtra(QUERY)
Thread { fetchResults("magic://my.app/search?query=$query") }.start()
}
private fun onResultsReceived(locations: List) {
search_progress.visibility = View.GONE
Вызов службы
355
search_results_recyclerview.visibility = View.VISIBLE
search_results_recyclerview.adapter = Adapter(locations)
}
private fun fetchResults(urlWithQuery: String) {
try {
val builder = StringBuilder()
val url = URL(urlWithQuery)
val connection = url.openConnection() as HttpURLConnection
var data: Int = connection.inputStream.read()
while (data != -1) {
builder.append(data.toChar())
data = connection.inputStream.read()
}
val json = builder.toString()
val locations = Gson().fromJson >(json,
object : TypeToken>() {}.type)
onResultsReceived(locations)
} catch (e: IOException) {
Log.d("MyApp",
"Something went wrong when fetching results. Probably the fake URL!")
}
}
private class Adapter(private val locations: List) :
RecyclerView.Adapter() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(TextView(parent.context))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val (streetAddress, city, country) = locations[position]
holder.textView.text = "$streetAddress, $city, $country"
}
override fun getItemCount(): Int {
return locations.size
}
private class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val textView: TextView = itemView as TextView
}
}
companion object {
val QUERY = "QUERY"
}
}
(Не забудьте добавить этот объект
Ac ti vi ty
в
Do'stlaringiz bilan baham: |