Много раз нам нужно заполнить Listview, используя AsyncTask . Это тот случай, когда нам нужно вызвать удаленный сервер и обмениваться информацией, используя JSON .
В этом посте я хочу углубиться в анализ ListView . В предыдущих постах я описал, как использовать ListView несколькими способами с использованием стандартных и пользовательских адаптеров . Во всем примере я должен был установить фиксированные элементы. В этом посте я опишу, как можно получить элементы непосредственно с сервера JEE.
Для простоты предположим, что у нас есть простой JEE-сервер, который управляет некоторыми контактами. Наш контакт осуществляется по: имени, фамилии, электронной почте и номеру телефона. Как сделать этот сервер выходит за рамки этого поста, и я просто сделаю доступным исходный код. Просто чтобы дать вам некоторые подробности, я могу сказать, что сервер является сервером JEE, разработанным с использованием веб-сервисов RESTFul (в нашем случае — jersey api).
В этом случае приложение ведет себя как клиент, который вызывает службу удаления, чтобы получить список контактов и показать его с помощью ListView. Данные, передаваемые с сервера клиенту, форматируются с использованием JSON.
Как всегда, мы начинаем создавать наш собственный адаптер, который использует собственный макет. Если вам нужна дополнительная информация о создании собственного адаптера, вы можете посмотреть здесь и здесь . Вот код:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
public class SimpleAdapter extends ArrayAdapter<Contact> { private List<Contact> itemList; private Context context; public SimpleAdapter(List<Contact> itemList, Context ctx) { super(ctx, android.R.layout.simple_list_item_1, itemList); this.itemList = itemList; this.context = ctx; } public int getCount() { if (itemList != null) return itemList.size(); return 0; } public Contact getItem(int position) { if (itemList != null) return itemList.get(position); return null; } public long getItemId(int position) { if (itemList != null) return itemList.get(position).hashCode(); return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; if (v == null) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); v = inflater.inflate(R.layout.list_item, null); } Contact c = itemList.get(position); TextView text = (TextView) v.findViewById(R.id.name); text.setText(c.getName()); TextView text1 = (TextView) v.findViewById(R.id.surname); text1.setText(c.getSurname()); TextView text2 = (TextView) v.findViewById(R.id.email); text2.setText(c.getEmail()); TextView text3 = (TextView) v.findViewById(R.id.phone); text3.setText(c.getPhoneNum()); return v; } public List<Contact> getItemList() { return itemList; } public void setItemList(List<Contact> itemList) { this.itemList = itemList; }} |
К настоящему времени все гладко и просто.
HTTP-клиент
Единственное, что нам нужно сделать, — это создать наш HTTP-клиент, чтобы отправить запрос на сервер JEE. Как мы все знаем, HTTP-запрос может потребовать много времени, прежде чем ответ будет доступен, поэтому мы должны принять это во внимание, чтобы ОС Android не остановила наше приложение. Самое простое, что можно сделать — создать AsyncTask, который выполняет этот запрос и ожидает ответа.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
private class AsyncListViewLoader extends AsyncTask<String, Void, List<Contact>> { private final ProgressDialog dialog = new ProgressDialog(MainActivity.this); @Override protected void onPostExecute(List<Contact> result) { super.onPostExecute(result); dialog.dismiss(); adpt.setItemList(result); adpt.notifyDataSetChanged(); } @Override protected void onPreExecute() { super.onPreExecute(); dialog.setMessage("Downloading contacts..."); dialog.show(); } @Override protected List<Contact> doInBackground(String... params) { List<Contact> result = new ArrayList<Contact>(); try { URL u = new URL(params[0]); HttpURLConnection conn = (HttpURLConnection) u.openConnection(); conn.setRequestMethod("GET"); conn.connect(); InputStream is = conn.getInputStream(); // Read the stream byte[] b = new byte[1024]; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while ( is.read(b) != -1) baos.write(b); String JSONResp = new String(baos.toByteArray()); JSONArray arr = new JSONArray(JSONResp); for (int i=0; i < arr.length(); i++) { result.add(convertContact(arr.getJSONObject(i))); } return result; } catch(Throwable t) { t.printStackTrace(); } return null; } private Contact convertContact(JSONObject obj) throws JSONException { String name = obj.getString("name"); String surname = obj.getString("surname"); String email = obj.getString("email"); String phoneNum = obj.getString("phoneNum"); return new Contact(name, surname, email, phoneNum); }} |
Давайте проанализируем код.
На начальном этапе ( onPreExecute () ) перед запуском задачи мы просто показываем диалоговое окно, информирующее пользователя о том, что приложение загружает список контактов. Наиболее интересной частью является метод doInBackground, где приложение устанавливает HTTP-соединение. Сначала мы создаем HTTPConnection и устанавливаем метод GET следующим образом:
|
1
2
3
4
|
HttpURLConnection conn = (HttpURLConnection) u.openConnection();conn.setRequestMethod("GET");conn.connect(); |
Затем мы создаем поток ввода и затем читаем поток байтов:
|
1
2
3
4
5
6
|
InputStream is = conn.getInputStream(); // Read the stream byte[] b = new byte[1024]; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while ( is.read(b) != -1) baos.write(b); |
Теперь у нас есть весь поток в нашем байтовом массиве, и нам нужно просто проанализировать его с помощью JSON.
|
1
2
3
4
5
6
|
JSONArray arr = new JSONArray(JSONResp);for (int i=0; i < arr.length(); i++) { result.add(convertContact(arr.getJSONObject(i)));}return result; |
Готово! Что дальше?… Что ж, нам нужно сообщить адаптеру, что у нас есть новый список контактов, и он должен показать его. Мы можем сделать это в onPostExecute (результат List <Contact>), где:
|
1
2
3
4
|
super.onPostExecute(result);dialog.dismiss();adpt.setItemList(result);adpt.notifyDataSetChanged(); |