Search the Community
Showing results for tags 'андроид'.
-
Opencart - Android - JSON - получаем список товаров в приложении
ocdroid posted a blog entry in ocdroid blog
Всем привет! Сегодня мы разберем получение товаров из категории Opencart в Android-приложение через JSON. Для начала не будем использовать сторонние библиотеки, а сделаем все нативным образом, чтобы ознакомиться с базовыми принципами обмена данными. Итак, поехали Сперва нужно определить выдачу массива товаров в JSON-объект из магазина. Открываем catalog/controller/product/category.php И в цикле выдачи данных для товаров добавляем свои запросы. Перед $data['products'][] = array( Добавляем // изображение для списка, размер 100х100 if ($result['image']) { $json_image = $this->model_tool_image->resize($result['image'], 100, 100); } else { $json_image = $this->model_tool_image->resize('placeholder.png', 100, 100); } // создаем массив данных для каждого товара // получаем имя, путь изображения, описание и цену $data['json-products'][] = array( 'name' => $result['name'], 'thumb' => $json_image, 'description' => utf8_substr(trim(strip_tags(html_entity_decode($result['description'], ENT_QUOTES, 'UTF-8'))), 0, $this->config->get('theme_' . $this->config->get('config_theme') . '_product_description_length')) . '..', 'price' => $price, ); Дальше ищем response $this->response->setOutput($this->load->view('product/category', $data)); И заменяем на // формируем массив products $data['json_products'] = array( 'products' => $data['json-products'], ); // и отдаем его в json при запросе в адресной строке &json_products // для этого поставим условие запроса if (isset( $this->request->get['json_products'])) { $this->response->setOutput(json_encode($data['json_products'])); } else { $this->response->setOutput($this->load->view('product/category', $data)); } Таким образом, теперь при запросе к сайту по адресу мой-сайт/index.php?route=product/category&path=20&json_products мы будем получать массив данных вида: {"products":[ {"name":"Apple Cinema30'", "thumb":"http:\/\/store.url\/image\/cache\/catalog\/demo\/apple_cinema_30-100x100.jpg", "description":"The 30-inch Apple Cinema HD Display delivers an amazing 2560 x 1600 pixel resolution. Designed speci..", "price":"$100.00"}, {"name":"Canon EOS 5D", "thumb":"http:\/\/store.url\/image\/cache\/catalog\/demo\/canon_eos_5d_1-100x100.jpg", "description":"Canon's press material for the EOS 5D states that it 'defines (a) new D-SLR category', while we're n..", "price":"$100.00"}, . . . , . . . , ]} С серверной частью закончили, переходим к программной части приложения. Что мы будем делать? Получим JSON данные из url Разберем эти данные и актуализируем с listView(textView) Скачаем картинки, кешируем их в приложении и актуализируем по позициям в listView(imageView) Для начала не забудьте дать приложению разрешение на использование сети (в манифесте): <uses-permission android:name="android.permission.INTERNET"/> Также в папку res/drawable мы поместим заглушку для изображений(до того, как они спарсятся) blank.png (100x100px) Теперь разметка. Для простоты будем работать с activity_main и стандартным listView activity_main.xml: <RelativeLayout 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" > <ListView android:id="@+id/lv_products" android:layout_width="wrap_content" android:layout_height="wrap_content" tools:context=".MainActivity" /> </RelativeLayout> Здесь все просто - в релятивную разметку мы поместили listView c id=lv_products Теперь создадим кастомную разметку для этого listView lv_layout.xml: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:id="@+id/tv_product" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:layout_marginRight="5dp" android:layout_marginTop="5dp" android:textColor="#195F74" android:textSize="20sp" android:textStyle="bold" /> <ImageView android:id="@+id/iv_thumb" android:layout_width="100dp" android:layout_height="100dp" android:layout_below="@id/tv_product" android:layout_centerVertical="true" android:contentDescription="@string/str_iv_thumb" android:padding="5dp" android:scaleType="fitXY" /> <TextView android:id="@+id/tv_description" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/tv_product" android:layout_toRightOf="@id/iv_thumb" android:textSize="16sp" /> <TextView android:id="@+id/tv_price" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/tv_description" android:layout_marginBottom="10dp" android:gravity="right" android:layout_marginRight="5dp" android:textColor="#cc3333" android:textSize="20sp" android:textStyle="bold"/> </RelativeLayout> С разметкой закончили — приступаем к коду Создаем файл ProductsJSONParser.java (это и будет класс парсера) package com.opencart.ocproducstlist; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.content.res.Resources; /** класс парсера JSON данных */ public class ProductsJSONParser { // Получаем JSONObject и возвращаем List public List<HashMap<String, Object>> parse(JSONObject jObject) { JSONArray jProducts = null; try { // Здесь элементы из массива 'products', который мы получаем из контроллера jProducts = jObject.getJSONArray("products"); } catch (JSONException e) { e.printStackTrace(); } // применяем getProducts к массиву объекта JSON // теперь каждый объект - это товар return getProducts(jProducts); } private List<HashMap<String, Object>> getProducts(JSONArray jProducts) { int productCount = jProducts.length(); List<HashMap<String, Object>> productList = new ArrayList<HashMap<String, Object>>(); HashMap<String, Object> product = null; // разбираем товары по одному и добавляем к объекту List for (int i = 0; i < productCount; i++) { try { // вызываем getProduct и парсим, добавляем product = getProduct((JSONObject) jProducts.get(i)); productList.add(product); } catch (JSONException e) { e.printStackTrace(); } } return productList; } // Разбираем JSON-объект product private HashMap<String, Object> getProduct(JSONObject jProduct) { HashMap<String, Object> product = new HashMap<String, Object>(); String name = ""; String thumb = ""; String description = ""; String price = ""; try { // обратите внимание на метод .replaceAll // без него разные "непечатные" символы будут отображаться неправильно name = jProduct.getString("name").replaceAll(""", "\""); thumb = jProduct.getString("thumb"); description = jProduct.getString("description").replaceAll(""", "\"").replaceAll("’", "\'"); price = jProduct.getString("price"); product.put("product", name); // здесь сперва ставим заглушку product.put("thumb", R.drawable.blank); product.put("thumb_path", thumb); product.put("description", description); product.put("price", price); } catch (JSONException e) { e.printStackTrace(); } return product; } } Ну а теперь MainActivity package com.opencart.ocproducstlist; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.HashMap; import java.util.List; import org.json.JSONObject; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.widget.ListView; import android.widget.SimpleAdapter; public class MainActivity extends Activity { ListView mListView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // URL с нашими JSON-данными String strUrl = "http://мойсайт.com/index.php?route=product/category&path=20&json_products"; // определяем задачу по загрузке // и запускаем ее с нашим url DownloadTask downloadTask = new DownloadTask(); downloadTask.execute(strUrl); // ссылаемся на ListView в activity_main mListView = (ListView) findViewById(R.id.lv_products); } /** метод загрузки данных из url */ private String downloadUrl(String strUrl) throws IOException { String data = ""; InputStream iStream = null; try { URL url = new URL(strUrl); // Создаем http соединение, соединяемся и считываем данные HttpURLConnection urlConnection = (HttpURLConnection) url .openConnection(); urlConnection.connect(); iStream = urlConnection.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader( iStream)); StringBuffer sb = new StringBuffer(); String line = ""; while ((line = br.readLine()) != null) { sb.append(line); } data = sb.toString(); br.close(); } catch (Exception e) { Log.d("Exception while downloading url", e.toString()); } finally { iStream.close(); } return data; } /** Асинхронно скачиваем json */ private class DownloadTask extends AsyncTask<String, Integer, String> { String data = null; @Override protected String doInBackground(String... url) { try { data = downloadUrl(url[0]); } catch (Exception e) { Log.d("Background Task", e.toString()); } return data; } @Override protected void onPostExecute(String result) { // закончили в non-ui ListViewLoaderTask listViewLoaderTask = new ListViewLoaderTask(); // начинаем парсить listViewLoaderTask.execute(result); } } /** Асинхронно парсим данные и кидаем в listView */ private class ListViewLoaderTask extends AsyncTask<String, Void, SimpleAdapter> { JSONObject jObject; // парсим в non-ui @Override protected SimpleAdapter doInBackground(String... strJson) { try { jObject = new JSONObject(strJson[0]); ProductsJSONParser productsJsonParser = new ProductsJSONParser(); productsJsonParser.parse(jObject); } catch (Exception e) { Log.d("JSON Exception1", e.toString()); } // Инстанцируем класс парсера ProductsJSONParser productsJsonParser = new ProductsJSONParser(); // Список для сохранения List<HashMap<String, Object>> products = null; try { // Получаем спарсеные данные в List (наш список) products = productsJsonParser.parse(jObject); } catch (Exception e) { Log.d("Exception", e.toString()); } // Ключи, которые используем в hashMap String[] from = { "product", "thumb", "description", "price" }; // и айдишники, используемые в listView int[] to = { R.id.tv_product, R.id.iv_thumb, R.id.tv_description, R.id.tv_price }; // задаем адаптер // и закидываем ключи в айдишники SimpleAdapter adapter = new SimpleAdapter(getBaseContext(), products, R.layout.lv_layout, from, to); return adapter; } /** doInBackground выполнен - займемся картинками */ @Override protected void onPostExecute(SimpleAdapter adapter) { // Задаем адаптер для listview mListView.setAdapter(adapter); for (int i = 0; i < adapter.getCount(); i++) { HashMap<String, Object> hm = (HashMap<String, Object>) adapter .getItem(i); String imgUrl = (String) hm.get("thumb_path"); ImageLoaderTask imageLoaderTask = new ImageLoaderTask(); HashMap<String, Object> hmDownload = new HashMap<String, Object>(); hm.put("thumb_path", imgUrl); hm.put("position", i); // запускаем ImageLoaderTask для скачивания // и актуализации картинок в listview imageLoaderTask.execute(hm); } } } /** Асинхронно качаем картинки и помещаем в listView */ private class ImageLoaderTask extends AsyncTask<HashMap<String, Object>, Void, HashMap<String, Object>> { @Override protected HashMap<String, Object> doInBackground( HashMap<String, Object>... hm) { InputStream iStream = null; String imgUrl = (String) hm[0].get("thumb_path"); int position = (Integer) hm[0].get("position"); URL url; try { url = new URL(imgUrl); // создаем соединение и подключаемся HttpURLConnection urlConnection = (HttpURLConnection) url .openConnection(); urlConnection.connect(); // считываем данные iStream = urlConnection.getInputStream(); // директория кеширования File cacheDirectory = getBaseContext().getCacheDir(); // временно сохраняем картинку в кеш-дир File tmpFile = new File(cacheDirectory.getPath() + "/ocpl_" + position + ".png"); // поток в кеш-файл FileOutputStream fOutStream = new FileOutputStream(tmpFile); // из потока в картинку Bitmap b = BitmapFactory.decodeStream(iStream); // пишем файл в темп (png) b.compress(Bitmap.CompressFormat.PNG, 100, fOutStream); // сбрасываем и закрываем поток fOutStream.flush(); fOutStream.close(); // создаем hashMap для передачи картинки // в listview, в соответствии с позицией HashMap<String, Object> hmBitmap = new HashMap<String, Object>(); // сохраняем путь к картинке // и позицию картинки в listview hmBitmap.put("thumb", tmpFile.getPath()); hmBitmap.put("position", position); // возвращаем объект с картинкой и позицией return hmBitmap; } catch (Exception e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(HashMap<String, Object> result) { // теперь получаем путь и позицию String path = (String) result.get("thumb"); int position = (Integer) result.get("position"); // задаем адаптер SimpleAdapter adapter = (SimpleAdapter) mListView.getAdapter(); // забираем объекты из hashMap // с соответствующей позицией в listview HashMap<String, Object> hm = (HashMap<String, Object>) adapter .getItem(position); // заменяем текущий путь (сейчас "заглушка" - res/drawable/blank.png) hm.put("thumb", path); // и сообщаем listView об изенении содержимого adapter.notifyDataSetChanged(); } } } Запускаем приложение и любуемся результатом: До новых встреч