В данном уроке я покажу как можно на Android работать с MySQL базой данных на основе JSON формата.
В этой части данного урока мы перейдем не посредственно к созданию самого Android приложения, так как backend мы написали в прошлом уроке ‘Как работать с MySQL в Android? Часть 1‘, где мы сделали серверную часть на PHP которая получает данные с БД и формирует ответ в качестве JSON формата.
Шаг 1. Создание Android приложение
Создаем Androi приложение File->New Project :
Шаг 2. Настраиваем Manifest
Теперь заходим в AndroidManifest.xml и прописываем там все наши только что созданные классы, все кроме класса JSONPaser, так как все эти классы будут Activity.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.devcolibri.androidandmysql" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="8"/> <application android:label="@string/app_name"> <activity android:name=".MainScreenActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <!-- All Product Activity --> <activity android:name=".AllProductsActivity" android:label="All Products" > </activity> <!-- Add Product Activity --> <activity android:name=".NewProductActivity" android:label="Add New Product" > </activity> <!-- Edit Product Activity --> <activity android:name=".EditProductActivity" android:label="Edit Product" > </activity> </application> <!-- Internet Permissions --> <uses-permission android:name="android.permission.INTERNET" /> </manifest>
Шаг 3. Создание layout
Теперь для каждого класса Activity создадим layout.
Первый будет main_screen.xml для Activity MainScreenActivity:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:gravity="center_horizontal"> <!-- Эта кнопка будет открывать окно для просмотра всех продуктов --> <Button android:id="@+id/btnViewProducts" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/btn_viewproduct" android:layout_marginTop="25dip"/> <!-- Эта кнопка будет открывать окно для создания нового продукта --> <Button android:id="@+id/btnCreateProduct" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/btn_addnewproduct" android:layout_marginTop="25dip"/> </LinearLayout>
Выглядеть она должна так:
Теперь создадим layout all_products.xml для AllProductsActivity:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <!-- Главный ListView Всегда давайте значение идентификатора в виде списка(@android:id/list) --> <ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="wrap_content"/> </LinearLayout>
и вторая дополнительная list_item.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" > <!-- Идентификатор продукта id (pid) - будет HIDDEN - используется для передачи в другой activity --> <TextView android:id="@+id/pid" android:layout_width="fill_parent" android:layout_height="wrap_content" android:visibility="gone" /> <TextView android:id="@+id/name" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingTop="6dip" android:paddingLeft="6dip" android:textSize="17dip" android:textStyle="bold" /> </LinearLayout>
Выглядит она так:
Следующая add_product.xml для NewProductActivity:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Product Name" android:paddingLeft="10dip" android:paddingRight="10dip" android:paddingTop="10dip" android:textSize="17dip"/> <EditText android:id="@+id/inputName" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="5dip" android:layout_marginBottom="15dip" android:singleLine="true"/> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Price" android:paddingLeft="10dip" android:paddingRight="10dip" android:paddingTop="10dip" android:textSize="17dip"/> <EditText android:id="@+id/inputPrice" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="5dip" android:layout_marginBottom="15dip" android:singleLine="true" android:inputType="numberDecimal"/> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Description" android:paddingLeft="10dip" android:paddingRight="10dip" android:paddingTop="10dip" android:textSize="17dip"/> <EditText android:id="@+id/inputDesc" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="5dip" android:layout_marginBottom="15dip" android:lines="4" android:gravity="top"/> <Button android:id="@+id/btnCreateProduct" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Create Product"/> </LinearLayout>
Выглядит она так:
И последний это edit_product.xml для EditProductActivity:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Product Name" android:paddingLeft="10dip" android:paddingRight="10dip" android:paddingTop="10dip" android:textSize="17dip"/> <EditText android:id="@+id/inputName" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="5dip" android:layout_marginBottom="15dip" android:singleLine="true"/> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Price" android:paddingLeft="10dip" android:paddingRight="10dip" android:paddingTop="10dip" android:textSize="17dip"/> <EditText android:id="@+id/inputPrice" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="5dip" android:layout_marginBottom="15dip" android:singleLine="true" android:inputType="numberDecimal"/> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Description" android:paddingLeft="10dip" android:paddingRight="10dip" android:paddingTop="10dip" android:textSize="17dip"/> <EditText android:id="@+id/inputDesc" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="5dip" android:layout_marginBottom="15dip" android:lines="4" android:gravity="top"/> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/btnSave" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Save Changes" android:layout_weight="1"/> <Button android:id="@+id/btnDelete" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Delete" android:layout_weight="1"/> </LinearLayout> </LinearLayout>
Выглядит так:
Шаг 4. Пишем Activity
Начнем с самого главного MainScreenActivity:
package com.devcolibri.androidandmysql; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; public class MainScreenActivity extends Activity { Button btnViewProducts; Button btnNewProduct; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_screen); btnViewProducts = (Button) findViewById(R.id.btnViewProducts); btnNewProduct = (Button) findViewById(R.id.btnCreateProduct); // обработчик на нажатиЯ кнопки View Products btnViewProducts.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // Запускаем Activity вывода всех продуктов Intent i = new Intent(getApplicationContext(), AllProductsActivity.class); startActivity(i); } }); // обработчик на нажатия кнопки Add New Products btnNewProduct.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // Запускаем Activity создания нового продукта Intent i = new Intent(getApplicationContext(), NewProductActivity.class); startActivity(i); } }); } }
В комментариях к коду я старался объяснить код, что будет не понятно в комментарии к этому уроку задавайте ваши вопросы.
Следующий это AllProductsActivity:
package com.devcolibri.androidandmysql; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import com.devcolibri.parser.JSONParser; import org.apache.http.NameValuePair; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.ListActivity; import android.app.ProgressDialog; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; public class AllProductsActivity extends ListActivity { private ProgressDialog pDialog; // Создаем JSON парсер JSONParser jParser = new JSONParser(); ArrayList<HashMap<String, String>> productsList; // url получения списка всех продуктов private static String url_all_products = "http://test.devcolibri.com/get_all_products.php"; // JSON Node names private static final String TAG_SUCCESS = "success"; private static final String TAG_PRODUCTS = "products"; private static final String TAG_PID = "pid"; private static final String TAG_NAME = "name"; // тут будет хранится список продуктов JSONArray products = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.all_products); // Hashmap for ListView productsList = new ArrayList<HashMap<String, String>>(); // Загружаем продукты в фоновом потоке new LoadAllProducts().execute(); // получаем ListView ListView lv = getListView(); // на выбор одного продукта // запускается Edit Product Screen lv.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // getting values from selected ListItem String pid = ((TextView) view.findViewById(R.id.pid)).getText() .toString(); // Запускаем новый intent который покажет нам Activity Intent in = new Intent(getApplicationContext(), EditProductActivity.class); // отправляем pid в следующий activity in.putExtra(TAG_PID, pid); // запуская новый Activity ожидаем ответ обратно startActivityForResult(in, 100); } }); } // Ответ из Edit Product Activity @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // если результующий код равен 100 if (resultCode == 100) { // если полученный код результата равен 100 // значит пользователь редактирует или удалил продукт // тогда мы перезагружаем этот экран Intent intent = getIntent(); finish(); startActivity(intent); } } /** * Фоновый Async Task для загрузки всех продуктов по HTTP запросу * */ class LoadAllProducts extends AsyncTask<String, String, String> { /** * Перед началом фонового потока Show Progress Dialog * */ @Override protected void onPreExecute() { super.onPreExecute(); pDialog = new ProgressDialog(AllProductsActivity.this); pDialog.setMessage("Загрузка продуктов. Подождите..."); pDialog.setIndeterminate(false); pDialog.setCancelable(false); pDialog.show(); } /** * Получаем все продукт из url * */ protected String doInBackground(String... args) { // Будет хранить параметры List<NameValuePair> params = new ArrayList<NameValuePair>(); // получаем JSON строк с URL JSONObject json = jParser.makeHttpRequest(url_all_products, "GET", params); Log.d("All Products: ", json.toString()); try { // Получаем SUCCESS тег для проверки статуса ответа сервера int success = json.getInt(TAG_SUCCESS); if (success == 1) { // продукт найден // Получаем масив из Продуктов products = json.getJSONArray(TAG_PRODUCTS); // перебор всех продуктов for (int i = 0; i < products.length(); i++) { JSONObject c = products.getJSONObject(i); // Сохраняем каждый json елемент в переменную String id = c.getString(TAG_PID); String name = c.getString(TAG_NAME); // Создаем новый HashMap HashMap<String, String> map = new HashMap<String, String>(); // добавляем каждый елемент в HashMap ключ => значение map.put(TAG_PID, id); map.put(TAG_NAME, name); // добавляем HashList в ArrayList productsList.add(map); } } else { // продукт не найден // Запускаем Add New Product Activity Intent i = new Intent(getApplicationContext(), NewProductActivity.class); // Закрытие всех предыдущие activities i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(i); } } catch (JSONException e) { e.printStackTrace(); } return null; } /** * После завершения фоновой задачи закрываем прогрес диалог * **/ protected void onPostExecute(String file_url) { // закрываем прогресс диалог после получение все продуктов pDialog.dismiss(); // обновляем UI форму в фоновом потоке runOnUiThread(new Runnable() { public void run() { /** * Обновляем распарсенные JSON данные в ListView * */ ListAdapter adapter = new SimpleAdapter( AllProductsActivity.this, productsList, R.layout.list_item, new String[] { TAG_PID, TAG_NAME}, new int[] { R.id.pid, R.id.name }); // обновляем listview setListAdapter(adapter); } }); } } }
После идет activity NewProductActivity:
package com.devcolibri.androidandmysql; import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; import com.devcolibri.parser.JSONParser; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; public class NewProductActivity extends Activity { private ProgressDialog pDialog; JSONParser jsonParser = new JSONParser(); EditText inputName; EditText inputPrice; EditText inputDesc; private static String url_create_product = "http://test.devcolibri.com/create_product.php"; private static final String TAG_SUCCESS = "success"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.add_product); inputName = (EditText) findViewById(R.id.inputName); inputPrice = (EditText) findViewById(R.id.inputPrice); inputDesc = (EditText) findViewById(R.id.inputDesc); Button btnCreateProduct = (Button) findViewById(R.id.btnCreateProduct); btnCreateProduct.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new CreateNewProduct().execute(); } }); } /** * Фоновый Async Task создания нового продукта **/ class CreateNewProduct extends AsyncTask<String, String, String> { /** * Перед согданием в фоновом потоке показываем прогресс диалог **/ @Override protected void onPreExecute() { super.onPreExecute(); pDialog = new ProgressDialog(NewProductActivity.this); pDialog.setMessage("Создание продукта..."); pDialog.setIndeterminate(false); pDialog.setCancelable(true); pDialog.show(); } /** * Создание продукта **/ protected String doInBackground(String[] args) { String name = inputName.getText().toString(); String price = inputPrice.getText().toString(); String description = inputDesc.getText().toString(); // Заполняем параметры List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("name", name)); params.add(new BasicNameValuePair("price", price)); params.add(new BasicNameValuePair("description", description)); // получаем JSON объект JSONObject json = jsonParser.makeHttpRequest(url_create_product, "POST", params); Log.d("Create Response", json.toString()); try { int success = json.getInt(TAG_SUCCESS); if (success == 1) { // продукт удачно создан Intent i = new Intent(getApplicationContext(), AllProductsActivity.class); startActivity(i); // закрываем это окно finish(); } } catch (JSONException e) { e.printStackTrace(); } return null; } /** * После оконачния скрываем прогресс диалог **/ protected void onPostExecute(String file_url) { pDialog.dismiss(); } } }
Последний EditProductActivity:
package com.devcolibri.androidandmysql; import java.util.ArrayList; import java.util.List; import com.devcolibri.parser.JSONParser; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.app.ProgressDialog; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; public class EditProductActivity extends Activity { EditText txtName; EditText txtPrice; EditText txtDesc; Button btnSave; Button btnDelete; String pid; private ProgressDialog pDialog; JSONParser jsonParser = new JSONParser(); // url для получения одного продукта private static final String url_product_detials = "http://test.devcolibri.com/get_product_details.php"; // url для обновления продукта private static final String url_update_product = "http://test.devcolibri.com/update_product.php"; // url для удаления продукта private static final String url_delete_product = "http://test.devcolibri.com/delete_product.php"; // JSON параметры private static final String TAG_SUCCESS = "success"; private static final String TAG_PRODUCT = "product"; private static final String TAG_PID = "pid"; private static final String TAG_NAME = "name"; private static final String TAG_PRICE = "price"; private static final String TAG_DESCRIPTION = "description"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.edit_product); btnSave = (Button) findViewById(R.id.btnSave); btnDelete = (Button) findViewById(R.id.btnDelete); // показываем форму про детальную информацию о продукте Intent i = getIntent(); // получаем id продукта (pid) с формы pid = i.getStringExtra(TAG_PID); // Получение полной информации о продукте в фоновом потоке new GetProductDetails().execute(); // обрабочик на кнопку сохранение продукта btnSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // запускаем выполнение задачи на обновление продукта new SaveProductDetails().execute(); } }); // обработчик на кнопку удаление продукта btnDelete.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { // удалем продукт в фоновом потоке new DeleteProduct().execute(); } }); } /** * Фоновая асинхронная задача для получения полной информации о продукте **/ class GetProductDetails extends AsyncTask<String, String, String> { /** * Перед началом показать в фоновом потоке прогресс диалог **/ @Override protected void onPreExecute() { super.onPreExecute(); pDialog = new ProgressDialog(EditProductActivity.this); pDialog.setMessage("Loading product details. Please wait..."); pDialog.setIndeterminate(false); pDialog.setCancelable(true); pDialog.show(); } /** * Получение детальной информации о продукте в фоновом режиме **/ protected String doInBackground(String[] params) { // обновляем UI форму runOnUiThread(new Runnable() { public void run() { // проверяем статус success тега int success; try { // Список параметров List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("pid", pid)); // получаем продукт по HTTP запросу JSONObject json = jsonParser.makeHttpRequest(url_product_detials, "GET", params); Log.d("Single Product Details", json.toString()); success = json.getInt(TAG_SUCCESS); if (success == 1) { // Успешно получинна детальная информация о продукте JSONArray productObj = json.getJSONArray(TAG_PRODUCT); // получаем первый обьект с JSON Array JSONObject product = productObj.getJSONObject(0); // продукт с pid найден // Edit Text txtName = (EditText) findViewById(R.id.inputName); txtPrice = (EditText) findViewById(R.id.inputPrice); txtDesc = (EditText) findViewById(R.id.inputDesc); // покаываем данные о продукте в EditText txtName.setText(product.getString(TAG_NAME)); txtPrice.setText(product.getString(TAG_PRICE)); txtDesc.setText(product.getString(TAG_DESCRIPTION)); }else{ // продукт с pid не найден } } catch (JSONException e) { e.printStackTrace(); } } }); return null; } /** * После завершения фоновой задачи закрываем диалог прогресс **/ protected void onPostExecute(String file_url) { // закрываем диалог прогресс pDialog.dismiss(); } } /** * В фоновом режиме выполняем асинхроную задачу на сохранение продукта **/ class SaveProductDetails extends AsyncTask<String, String, String> { /** * Перед началом показываем в фоновом потоке прогрксс диалог **/ @Override protected void onPreExecute() { super.onPreExecute(); pDialog = new ProgressDialog(EditProductActivity.this); pDialog.setMessage("Saving product ..."); pDialog.setIndeterminate(false); pDialog.setCancelable(true); pDialog.show(); } /** * Сохраняем продукт **/ protected String doInBackground(String[] args) { // получаем обновленные данные с EditTexts String name = txtName.getText().toString(); String price = txtPrice.getText().toString(); String description = txtDesc.getText().toString(); // формируем параметры List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair(TAG_PID, pid)); params.add(new BasicNameValuePair(TAG_NAME, name)); params.add(new BasicNameValuePair(TAG_PRICE, price)); params.add(new BasicNameValuePair(TAG_DESCRIPTION, description)); // отправляем измененные данные через http запрос JSONObject json = jsonParser.makeHttpRequest(url_update_product, "POST", params); // проверяем json success тег try { int success = json.getInt(TAG_SUCCESS); if (success == 1) { // продукт удачно обнавлён Intent i = getIntent(); // отправляем результирующий код 100 чтобы сообщить об обновлении продукта setResult(100, i); finish(); } else { // продукт не обновлен } } catch (JSONException e) { e.printStackTrace(); } return null; } /** * После окончания закрываем прогресс диалог **/ protected void onPostExecute(String file_url) { // закрываем прогресс диалог pDialog.dismiss(); } } /** * Фоновая асинхронная задача на удаление продукта **/ class DeleteProduct extends AsyncTask<String, String, String> { /** * На начале показываем прогресс диалог **/ @Override protected void onPreExecute() { super.onPreExecute(); pDialog = new ProgressDialog(EditProductActivity.this); pDialog.setMessage("уДАЛЕМ ПРОДУКТ..."); pDialog.setIndeterminate(false); pDialog.setCancelable(true); pDialog.show(); } /** * Удаление продукта **/ protected String doInBackground(String[] args) { int success; try { List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair("pid", pid)); // получение продукта используя HTTP запрос JSONObject json = jsonParser.makeHttpRequest(url_delete_product, "POST", params); Log.d("Delete Product", json.toString()); success = json.getInt(TAG_SUCCESS); if (success == 1) { // Продукт удачно удален Intent i = getIntent(); // отправляем результирующий код 100 для уведомления об удалении продукта setResult(100, i); finish(); } } catch (JSONException e) { e.printStackTrace(); } return null; } /** * После оконачния скрываем прогресс диалог **/ protected void onPostExecute(String file_url) { pDialog.dismiss(); } } }
Шаг 5. Добавим название некоторых кнопок
Давайте теперь добавим название кнопок главного Activity в string.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">AndroidAndMySQL</string> <string name="btn_viewproduct">View Products</string> <string name="btn_addnewproduct">Add New Products</string> </resources>
Шаг 6. Добавим нужные библиотеки
После того как вы сделаете все что описано выше вы увидите, что фрагменты кода которые работают с JSON не определяются, правильно ведь мы еще не добавили нужную библиотеку json.jar его вы найдете вы прикрепленном исходнике к этому посту.
Давайте добавим эту библиотеку к нашему проекту.
Для начало скиньте её в корень проекта папку libs/json-20090211.jar.
После в Intellij IDEA зайдите в Project Structure:
После того как вы добавите библиотеку нажмите Ok.
Шаг 7. Запускаем.
Теперь смотри, что же получилось.
ПОХОЖИЕ ПУБЛИКАЦИИ
- None Found
155 комментариев к статье "Как работать с MySQL в Android? Часть 2"