آموزش دریافت اطلاعات از mysql و قرار دادن در Spinner

سلام دوستان امیدوارم حالتان خوب باشد در این سری از آموزش برنامه نویسی اندروید به آموزش دریافت اطلاعات از mysql و قرار دادن در Spinner می پردازیم ما آموزش استفاده از دیتابیس Mysql و خواندن آن را به صورت شش پارت جداگانه در سایت قرار دادیم امروز به بررسی خواندن جدول (table) از دیتابیس mysql و قرار دادن آن در spinner خواهیم پرداخت در ادامه با ما همراه باشید.
در این آموزش ما از مجازی ساز xampp برای ایجاد دیتابیس استفاده خواهیم کرد در صورتی که شبیه سازی های متاوفت دیگری دارید می توانید از آنها استفاده کنید (زیاد فرق نمی کنند) در صورتی که مک دارید از می توایند از مجازی ساز MAMP استفاده کنید و در صورتی که از لینوکس دارید از LAMP می توانید استفاده کنید.
امکان استفاده از این آموزش در
بعد از اجرای xampp دو سرویس Apache و Mysql را اجرا کنید ( بروی دکمه های start کلیک کنید.
سپس در کنار همان دکمه start گزینه Admin را کلیک کنید منظور mysql است . آن را در مروگر باز کنید می توانید از آدرس زیر نیز استفاده کنید.

localhost/phpmyadmin/

سپس یک دیتابیس به نام food ایجاد کنید.
سپس کد sql زیر را در آن اجرا کنید برای اینکار ابتدا باید دیتابیس ساخته شده (food) را انتخاب کنید سپس وارد tab  به نام sql شده و در آن کادر کد زیر را قرار دهید.

CREATE TABLE IF NOT EXISTS `categories` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(30) NOT NULL,
  PRIMARY KEY (`id`)
);
INSERT INTO `categories` (`name`) VALUES
('Beverages'),
('Bread'),
('Cereals'),
('Cheese'),
('Citrus Fruits');

یک پوشه به نام food_api در مسیر زیر ایجاد کنید.

C:\xampp

فایل های php که ایجاد می کنید باید در این پوشه باشد.
در پوشه ذکر شده یک فایل به نام Config.php ایجاد کرده و کدهای زیر را در آن قرار دهید.

<?php
define('DB_USERNAME', 'root');
define('DB_PASSWORD', '');
define('DB_HOST', 'localhost');
define('DB_NAME', 'food');
?>

این فایل شامل نام دیتابیس و یوزر و پسورد دیتابیس است. در صورتی که بروی سرر است شما باید بخش پسورد را نیز پر کنید.
باید یک فایل کلاس برای بررسی اتصال به دیتابیس ایجاد کنیم.
پس یک فالی php به نام DbConnect.php ایجاد کرده و کدهای زیر را در آن قرار دهید.

<?php
class DbConnect {
    private $conn;
    function __construct() {
        $this->connect();
    }
    function __destruct() {
        $this->close();
    }
    function connect() {
        include_once dirname(__FILE__) . './Config.php';
        $this->conn = mysql_connect(DB_HOST, DB_USERNAME, DB_PASSWORD) or die(mysql_error());
        mysql_select_db(DB_NAME) or die(mysql_error());
        return $this->conn;
    }
    function close() {
        mysql_close($this->conn);
    }
}
?>

یک فایل php دیگر به نام get_categories.php ایجاد کرده و کدهای زیر را در آن قرار دهید. کار اصلی این کار دیافت رکورد ها  از دیتابیس دریافت می کنید و به صورت json آن را خروجی میدهد.

<?php
include_once './DbConnect.php';
function getCategories(){
    $db = new DbConnect();
    $response = array();
    $response["categories"] = array();
    $result = mysql_query("SELECT * FROM categories");
    while($row = mysql_fetch_array($result)){
        $tmp = array();
        $tmp["id"] = $row["id"];
        $tmp["name"] = $row["name"];
        array_push($response["categories"], $tmp);
    }
    header('Content-Type: application/json');
    echo json_encode($response);
}
getCategories();
?>

ما یک فایل دیگه به نام new_category.php داریم کار این فایل اضافه کردن یک categories جدید به دیتابیس است . (در صورتی که خواستید می تونید از این بخش استفاده کنید )

<?php
include_once './DbConnect.php';
function createNewCategory() {
    if (isset($_POST["name"]) && $_POST["name"] != "") {
        $response = array();
        $category = $_POST["name"];
        $db = new DbConnect();
        $query = "INSERT INTO categories(name) VALUES('$category')";
        $result = mysql_query($query) or die(mysql_error());
        if ($result) {
            $response["error"] = false;
            $response["message"] = "Category created successfully!";
        } else {
            $response["error"] = true;
            $response["message"] = "Failed to create category!";
        }
    } else {
        $response["error"] = true;
        $response["message"] = "Category name is missing!";
    }
    echo json_encode($response);
}
createNewCategory();
?>

کد بالا عملیات post را انجام میدهد یعنی یک مقداری ورودی را میگیرد و پست می کند.
تا اینجا کد های php به اتمام رسیده حالا به سراغ پروژه اندروید می رویم.
باید دسترسی استفاده از اینترنت را در AndroidManifest.xml اضافه کنید.

    <uses-permission android:name="android.permission.INTERNET"/>

ابتدا باید یک کلاس به نام  Category.java ایجاد کنید این کلاس همان کلاس model ماست به این کلاس getter و setter نیز می گویند.

package ir.programchi;
public class Category {
    private int id;
    private String name;
    public Category(){}
    public Category(int id, String name){
        this.id = id;
        this.name = name;
    }
    public void setId(int id){
        this.id = id;
    }
    public void setName(String name){
        this.name = name;
    }
    public int getId(){
        return this.id;
    }
    public String getName(){
        return this.name;
    }
}

یک کلاس به نام ServiceHandler.java ایجاد کنید کار این کلاس خواندن json است منظور همان دانلود است ابتدا باید دریافت شود سپس مورد استفاده قرار گیرد.

package ir.programchi;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.List;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import android.util.Log;
public class ServiceHandler {
    static InputStream is = null;
    static String response = null;
    public final static int GET = 1;
    public final static int POST = 2;
    public ServiceHandler() {
    }
    public String makeServiceCall(String url, int method) {
        return this.makeServiceCall(url, method, null);
    }
    public String makeServiceCall(String url, int method,
            List<NameValuePair> params) {
        try {
            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpEntity httpEntity = null;
            HttpResponse httpResponse = null;
            if (method == POST) {
                HttpPost httpPost = new HttpPost(url);
                if (params != null) {
                    httpPost.setEntity(new UrlEncodedFormEntity(params));
                }
                httpResponse = httpClient.execute(httpPost);
            } else if (method == GET) {
                if (params != null) {
                    String paramString = URLEncodedUtils
                            .format(params, "utf-8");
                    url += "?" + paramString;
                }
                HttpGet httpGet = new HttpGet(url);
                httpResponse = httpClient.execute(httpGet);
            }
            httpEntity = httpResponse.getEntity();
            is = httpEntity.getContent();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    is, "UTF-8"), 8);
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
            is.close();
            response = sb.toString();
        } catch (Exception e) {
            Log.e("Buffer Error", "Error: " + e.toString());
        }
        return response;
    }
}

کلاس بالا کاری همانند کتاب خانه های volley را انجام میدهد اما حجم کمتری دارد.
وارد activity_main.xml شده و کدهای زیر را قرار دهید.

<LinearLayout 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"
    android:orientation="vertical"
    android:padding="10dp" >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="New food category" />
    <EditText android:id="@+id/txtCategory"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>
    <Button android:id="@+id/btnAddNewCategory"
        android:text="Create"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="40dp"/>
    <TextView android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Select food category"/>
    <Spinner android:id="@+id/spinFood"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

 
در بالا یک EditText وجود دارد که با آن می توانید یک Category جدید در سرور ایجاد کنید و در پایین تر هم یک spinner وجود دارد.
و در آخر کد مربوط به MainActivity.java همانند زیر می شود.

package ir.programchi;
import java.util.ArrayList;
import java.util.List;
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.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements OnItemSelectedListener {
    private Button btnAddNewCategory;
    private TextView txtCategory;
    private Spinner spinnerFood;
    private ArrayList<Category> categoriesList;
    ProgressDialog pDialog;
    private String URL_NEW_CATEGORY = "http://10.0.2.2/food_api/new_category.php";
    private String URL_CATEGORIES = "http://10.0.2.2/food_api/get_categories.php";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnAddNewCategory = (Button) findViewById(R.id.btnAddNewCategory);
        spinnerFood = (Spinner) findViewById(R.id.spinFood);
        txtCategory = (TextView) findViewById(R.id.txtCategory);
        categoriesList = new ArrayList<Category>();
        spinnerFood.setOnItemSelectedListener(this);
        btnAddNewCategory.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (txtCategory.getText().toString().trim().length() > 0) {
                    String newCategory = txtCategory.getText().toString();
                    new AddNewCategory().execute(newCategory);
                } else {
                    Toast.makeText(getApplicationContext(),
                            "Please enter category name", Toast.LENGTH_SHORT)
                            .show();
                }
            }
        });
        new GetCategories().execute();
    }
    private void populateSpinner() {
        List<String> lables = new ArrayList<String>();
        txtCategory.setText("");
        for (int i = 0; i < categoriesList.size(); i++) {
            lables.add(categoriesList.get(i).getName());
        }
        ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_spinner_item, lables);
        spinnerAdapter
                .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinnerFood.setAdapter(spinnerAdapter);
    }
    private class GetCategories extends AsyncTask<Void, Void, Void> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            pDialog = new ProgressDialog(MainActivity.this);
            pDialog.setMessage("Fetching food categories..");
            pDialog.setCancelable(false);
            pDialog.show();
        }
        @Override
        protected Void doInBackground(Void... arg0) {
            ServiceHandler jsonParser = new ServiceHandler();
            String json = jsonParser.makeServiceCall(URL_CATEGORIES, ServiceHandler.GET);
            Log.e("Response: ", "> " + json);
            if (json != null) {
                try {
                    JSONObject jsonObj = new JSONObject(json);
                    if (jsonObj != null) {
                        JSONArray categories = jsonObj
                                .getJSONArray("categories");
                        for (int i = 0; i < categories.length(); i++) {
                            JSONObject catObj = (JSONObject) categories.get(i);
                            Category cat = new Category(catObj.getInt("id"),
                                    catObj.getString("name"));
                            categoriesList.add(cat);
                        }
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            } else {
                Log.e("JSON Data", "Didn't receive any data from server!");
            }
            return null;
        }
        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
            if (pDialog.isShowing())
                pDialog.dismiss();
            //populateSpinner();
        }
    }
    private class AddNewCategory extends AsyncTask<String, Void, Void> {
        boolean isNewCategoryCreated = false;
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            pDialog = new ProgressDialog(MainActivity.this);
            pDialog.setMessage("Creating new category..");
            pDialog.setCancelable(false);
            pDialog.show();
        }
        @Override
        protected Void doInBackground(String... arg) {
            String newCategory = arg[0];
            // Preparing post params
            List<NameValuePair> params = new ArrayList<NameValuePair>();
            params.add(new BasicNameValuePair("name", newCategory));
            ServiceHandler serviceClient = new ServiceHandler();
            String json = serviceClient.makeServiceCall(URL_NEW_CATEGORY,
                    ServiceHandler.POST, params);
            Log.d("Create Response: ", "> " + json);
            if (json != null) {
                try {
                    JSONObject jsonObj = new JSONObject(json);
                    boolean error = jsonObj.getBoolean("error");
                    // checking for error node in json
                    if (!error) {
                        // new category created successfully
                        isNewCategoryCreated = true;
                    } else {
                        Log.e("Create Category Error: ", "> " + jsonObj.getString("message"));
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            } else {
                Log.e("JSON Data", "Didn't receive any data from server!");
            }
            return null;
        }
        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
            if (pDialog.isShowing())
                pDialog.dismiss();
            if (isNewCategoryCreated) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // fetching all categories
                        new GetCategories().execute();
                    }
                });
            }
        }
    }
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position,
            long id) {
        Toast.makeText(
                getApplicationContext(),
                        parent.getItemAtPosition(position).toString() + " Selected" ,
                Toast.LENGTH_LONG).show();
    }
    @Override
    public void onNothingSelected(AdapterView<?> arg0) {
    }
}

کد بسیار طولانی است توصیه می کنم تست کنید سپس کد را  از بالا به پایین بررسی کنید.
URL_NEW_CATEGORY آدرس فایل ما در xampp است + آدرس آیپی local کامپیوتر من (این فایل برای ایجاد یک گروه جدید بود)
URL_CATEGORIES آدرس فایل ما در xampp + آدرس آیپی local کامپیوتر من (این فایل برای خواندن دیتابیس و قرار دادن در spinner بود)
 
در بالا دو تا کلاس Async داریم برای انجام عمل insert و خواندن json از آدرس url و در آخر هم دیتای خونده شده را در listview بالا populate یا قرار می دهیم.
از progressDialog هم استفاده شده است کمی دقت کنید چیز خاصی در کد بالا استفاده نشده است.
 
 
این آموزش هم به پایان رسید.
 
موفق و پیروز باشید.

مطالعه بیشتر