ورچر

آموزشهای پراکنده از دنیای برنامه نویسی اندروید

آموزش کامل دریافت اطلاعات از سرور و نمایش در اندروید (به همراه کدهای PHP) post image

آموزش کامل دریافت اطلاعات از سرور و نمایش در اندروید (به همراه کدهای PHP)

دسته : آموزش
تگ ها : آموزش دریافت داده از وب سرویس در اندروید,دریافت داده از سرور با اندروید,کلاینت وب سرویس در اندروید
آخرین ویرایش : 1395/8/10

به نام خدا

در این آموزش هدف یاددادن روش ایجاد وب سرویس ساده با زبان Php و ساخت کلاینت اندرویدی برای دریافت اطلاعات و نمایش در لیست به کاربران می باشد.

 

کدهای سمت سرور

1.یک دیتابیس به اسم mobile می سازیم. سپس یک جدول به اسم phone می سازیم با ساختار زیر.

 

2.کدهای پی اچ پی برای کارکردن با دیتابیس رو به صورت جداگانه در یک کلاس می نویسیم. ابتدا فایل Database.php را ایجاد کنید و کد های پی اچ پی را به شکل زیر در آن قراردهید.

<?php

class Database
{
    private $host = "localhost"; // آدرس دیتابیس
    private $user = "root"; // یوزر نیم دیتابیس
    private $pass = ""; // رمز یوزر نیم دیتابیس
    private $db = "mobile"; // نام دیتابیس مورد نظر
    private $conn;

    public function __construct() // تابع سازنده برای ایجاد ارتباط با دیتابیس
    {
        $this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db, $this->user, $this->pass);
    }

    public function showData($page = '1', $limit = '10') // تابع دریافت اطلاعات جدول phone
    {
        $offset = ($page - 1) * $limit;
        $sql = "SELECT * FROM phone LIMIT $limit OFFSET $offset"; // دستور انتخاب داده های موبایل
        $q = $this->conn->query($sql) or die("failed!");

        while ($r = $q->fetch(PDO::FETCH_ASSOC)) { // این سه سطر برای دریافت اطلاعات و قراردادن در آرایه کاربرد دارد.
            $data[] = $r;
        }
        return $data;// یک آرایه با داده خروجی تابع می باشد.
    }
}
?>

3. یک فایل دیگر به اسم index.php ایجاد می کنیم و دستورات زیر را در آن قرار می دهیم تا تابع نمایش داده ها فراخوانی شود و داده ها تبدیل به json شوند و به کاربر نمایش داده شوند.

<?php
require_once 'Database.php'; // فراخوانی دستورات فایل Database.php

$db = new Database(); // ایجاد داده از نوع دیتابیس

if (isset($_GET['page'])) { // اگر متغییر page در آدرس وارد شده باشد 
    $page = $_GET['page']; // مقدارش به متغییر page ذخیره میشود
} else {
    $page = 1; // در صورتی که وارد نشده باشد مقدار یک قرار میگیرد
}

if(isset($_GET['limit'])){ // اگر مقدار لیمیت نیز تعریف شده باشد
    echo(json_encode($db->showData($page, $_GET['limit']))); // تابع showData فراخوانی می شود و در داخل تابع json_encode به جیسون تبدیل می شود و با echo بصورت خروجی چاپ می شود.
}

4. سمت سرور در این قسمت کامل شده است. من یک نمونه از این کد رو دریکی از سرورهام ساختم در این آدرس هست.

 

یک نمونه خروجی از api بالا

[
    {"id":"1","title":"Iconia Talk S ","img":"http:\/\/cdn2.gsmarena.com\/vv\/bigpic\/acer-iconia-talk-s.jpg","link":"acer_iconia_talk_s-8306.php"},
    {"id":"2","title":"Liquid Z6 Plus ","img":"http:\/\/cdn2.gsmarena.com\/vv\/bigpic\/acer-liquid-z6-plus.jpg","link":"acer_liquid_z6_plus-8305.php"},
    {"id":"3","title":"Liquid Z6 ","img":"http:\/\/cdn2.gsmarena.com\/vv\/bigpic\/acer-liquid-z6.jpg","link":"acer_liquid_z6-8304.php"},
    {"id":"4","title":"Iconia Tab 10 A3-A40 ","img":"http:\/\/cdn2.gsmarena.com\/vv\/bigpic\/acer-iconia-tab-10-a3-a40.jpg","link":"acer_iconia_tab_10_a3_a40-8080.php"},
    {"id":"5","title":"Liquid X2 ","img":"http:\/\/cdn2.gsmarena.com\/vv\/bigpic\/acer-liquid-x2-1.jpg","link":"acer_liquid_x2-8034.php"},
    {"id":"6","title":"Liquid Jade 2 ","img":"http:\/\/cdn2.gsmarena.com\/vv\/bigpic\/acer-liquid-jade-2.jpg","link":"acer_liquid_jade_2-7956.php"},
    {"id":"7","title":"Liquid Zest Plus ","img":"http:\/\/cdn2.gsmarena.com\/vv\/bigpic\/acer-liquid-zest-plus-z628.jpg","link":"acer_liquid_zest_plus-8059.php"},
    {"id":"8","title":"Liquid Zest ","img":"http:\/\/cdn2.gsmarena.com\/vv\/bigpic\/acer-zest.jpg","link":"acer_liquid_zest-7955.php"},
    {"id":"9","title":"Predator 8 ","img":"http:\/\/cdn2.gsmarena.com\/vv\/bigpic\/acer-predator-8.jpg","link":"acer_predator_8-7750.php"},
    {"id":"10","title":"Liquid Jade Primo ","img":"http:\/\/cdn2.gsmarena.com\/vv\/bigpic\/acer-liquid-jade-primo-.jpg","link":"acer_liquid_jade_primo-7650.php"}
]

 

کدهای سمت اندروید

1.ابتدا یک پروژه ای جدید با اکتیویتی MainActivity ایجاد کنید.

2. در فایل گریدل app هم کد های زیر را وارد نمایید تا کتابخانه های مورد نیاز به پروژه اضافه بشود.

    compile 'com.android.support:design:24.2.1'
    compile 'com.android.support:recyclerview-v7:24.2.1'
    compile 'com.android.support:cardview-v7:24.2.1'    
    compile 'com.loopj.android:android-async-http:1.4.9'
    compile 'com.squareup.picasso:picasso:2.5.2'

3. پس از اضافه شدن کتابخانه ها در منیفست دسترسی های لازم را اضافه نمایید.

<uses-permission android:name="android.permission.INTERNET" /> // دسترسی اینترنت

4. پس از دسترسی ها نوبت تعریف یک مدل رسیده است. یک کلاس به اسم Phone.java ایجاد می کنیم و محتوای آن را به شکل زیر تغییر میدهیم.

public class Phone {
    public int id;
    public String title, link, img;

    public Phone(JSONObject jsonObject) { // تابع سازنده برای دریافت مقادیر از JsonObject
        try {
            this.id = jsonObject.getInt("id");
            this.title = jsonObject.getString("title");
            this.link = jsonObject.getString("link");
            this.img = jsonObject.getString("img");
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}

5. یک فایل به اسم item_phone.xml ایجاد می کنیم و محتوا را به شکل زیر قرار میدهیم. (این item_phone ظاهر همان آیتم های لیستمان خواهد بود.)

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="4dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/img"
            android:layout_width="wrap_content"
            android:layout_height="120dp"
            android:layout_margin="8dp"
            android:layout_marginBottom="50dp"
            android:adjustViewBounds="true"
            android:src="@drawable/acer" />

        <TextView
            android:id="@+id/title"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_margin="8dp"
            android:layout_weight="1"
            android:gravity="center_vertical"
            android:text="Acer Iconia"
            android:textSize="24dp" />

    </LinearLayout>

</android.support.v7.widget.CardView>

6. برای نمایش آیتم ها در لیست یا ریسایکلر ویو به یک آداپتر کاستوم نیازمندیم که با ایجاد کلاس PhoneAdapter.java انجام میشود.

توضیحات در داخل کدها

public class PhoneAdapter extends RecyclerView.Adapter<PhoneAdapter.PhoneHolder> { // مشتق شده از اداپتر ریسایکلر ویو

    List<Phone> mDataset; // لیست داده هایی از نوع مدل phone که در اداپتر هستند
    Context context; // کانتکست لیست

    public PhoneAdapter(Context context, List<Phone> myDataset) { // تابع سازنده
        this.mDataset = myDataset;
        this.context = context;
    }

    @Override
    public PhoneHolder onCreateViewHolder(ViewGroup parent, int viewType) { // این تابع برای نمایش item_phone اجرا می شود.
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_phone, parent, false); // توجه کنید در این قسمت اسم item_phone موجود هست. در پروژه های دیگر هم این قسمت نیازمند تغییر هست فقط.
        PhoneHolder dataObjectHolder = new PhoneHolder(view);
        return dataObjectHolder;
    }

    @Override
    public void onBindViewHolder(PhoneHolder holder, int position) { // تابعی که برای مقدار دهی به ویو های ظاهری فراخوانی میشود.
// در این قسمت holder از نوع PhoneHolder می باشد که در پایین بصورت کلاس داخلی تعریف کرده ایم.
        holder.title.setText(mDataset.get(position).title);  // به ویو title موجود در holder مقدار ست می کنیم.

// در صورتی که ویو سطر های شما عکس داشته باشد به کمک کتابخانه پیکاسو به این شکل لود می کنیم.
        Picasso.with(context)
                .load(mDataset.get(position).img) // دریافت آدرس از داده ها
                .placeholder(R.drawable.acer)
                .into(holder.img); // img از holder
    }

    public void update(List<Phone> list) { // تابعی اضافی که خودمان برای تغییر داده های اداپتر ساخته ایم.
        mDataset = list; // مقدارهای جدید را به اداپتر ست می کند.
        notifyDataSetChanged(); // به اداپتر می گوید داده ها تغییر یافته است.
    }

    @Override
    public int getItemCount() { // از توابع خود اداپتر برای دریافت تعداد داده ها می باشد.
        return mDataset.size();
    }

    public static class PhoneHolder extends RecyclerView.ViewHolder { // تابع viewholder برای تعریف اشاره گر به آیتم های هر سطر
// به طور مثال در هر سطر یک imageview و یک textview داریم . همان ویو های موجود در فایل item_phone.xml
        TextView title;
        ImageView img;

        public PhoneHolder(View itemView) { در تابع سازنده ویو هلدر اشاره گرها را ست می کنیم.
            super(itemView);
            title = (TextView) itemView.findViewById(R.id.title);
            img = (ImageView) itemView.findViewById(R.id.img);
        }
    }
}

7. حال به activity_main.xml رفته و ریسایکلر ویو تعریف می کنیم به شکل زیر.

در خارج تگ ریسایکلر ویو تگ سوایپ ریفرش هم گزاشتیم تا کدهای ریلود داده ها را نیز توضیح دهیم.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="ir.technopedia.gsm.MainActivity">

    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipe"
        android:layout_marginLeft="4dp"
        android:layout_marginRight="4dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.RecyclerView
            android:id="@+id/list"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>

8. در کلاس MainActivity.java کدها را به شکل زیر قرار میدهیم.

public class MainActivity extends AppCompatActivity {

    RecyclerView recyclerView;
    PhoneAdapter adapter;
    LinearLayoutManager linearLayoutManager;
    List<Phone> array;

    SwipeRefreshLayout swipeRefreshLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe); // اشاره گر سوایپ ریفرش لیوت
        recyclerView = (RecyclerView) findViewById(R.id.list); // اشاره گر ریسایکلر ویو
        linearLayoutManager = new LinearLayoutManager(getBaseContext(), LinearLayoutManager.VERTICAL, false); // تعریف لینیر لیوت منیجر به صورت عمودی
        array = new ArrayList<>();// ایجاد لیست داده ها
        adapter = new PhoneAdapter(getBaseContext(), array); //ساخت اداپتر از لیست داده ها

        recyclerView.setLayoutManager(linearLayoutManager); //  ست کردن لیوت منیجر به ریسایکلر ویو
        recyclerView.setAdapter(adapter); // ست کردن آداپتر به ریسایکلر ویو

    }

}

تا اینجا می توانید برنامه را اجرا کرده و مشاهده کنید. خروجی که می بینید صفحه ای خالی خواهد بود چون داده ای برای نمایش موجود نمی باشد.

9. برای دریافت داده یک کلاس کمکی به نام NetUtils به شکل زیر ایجاد خواهیم کرد.

این کلاس برای مرتب بودن کدهای کتابخانه loopj تعریف شده است.

public class NetUtils {
    private static final String BASE_URL = "http://technopedia.ir/pro/gsm/"; // آدرس اصلی api

    private static AsyncHttpClient client = new AsyncHttpClient();

    public static void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
        client.get(getAbsoluteUrl(url), params, responseHandler);
    }

    public static void post(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
        client.post(getAbsoluteUrl(url), params, responseHandler);
    }

    private static String getAbsoluteUrl(String relativeUrl) {
        return BASE_URL + relativeUrl;
    }
}

10. حال در کلاس MainActivity.java یک تابع به اسم loadData() بصورت زیر تعریف می کنیم .

public void loadData(int page) { 
        NetUtils.get("?data=phone&limit=10&page=" + (page+1), null, new JsonHttpResponseHandler() {
            @Override
            public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
                JSONArray phones = response;
                try {
                    for (int i = 0; i < phones.length(); i++) { // تمامی داده ها را میگیرم و به لیست اضافه می کنیم
                        array.add(new Phone(phones.getJSONObject(i)));
                    }
                    adapter.update(array); // به اداپتر لیست با داده های جدید را میفرستیم و آپدیت میکنیم.
                    swipeRefreshLayout.setRefreshing(false);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
                Toast.makeText(getBaseContext(), "Error on request", Toast.LENGTH_LONG).show();
            }

        });
    }

11. حال در آخر تابع onCreate موجود در MainActivity.java تابع loadData(0); را فراخوانی میکنیم.

حال برنامه را اجرا کنید 10 عدد داده در مورد گوشی ها نمایش داده خواهد شد.

 

اضافه کردن اسکرول بینهایت

12. برای اضافه کردن لود بینهایت برای لود کردن داده های بیشتر در برنامه کلاس EndlessRecyclerViewScrollListener.java را دانلود کنید و به پروژه خود اضافه کنید.

13. حال کدهای MainActivity.java را به شکل زیر تغییر دهید. تا اسکرول بینهایت فعال شود.

public class MainActivity extends AppCompatActivity {

    RecyclerView recyclerView;
    PhoneAdapter adapter;
    LinearLayoutManager linearLayoutManager;
    List<Phone> array;
    EndlessRecyclerViewScrollListener scrollListener; // تعریف اسکرول لیسنر
    SwipeRefreshLayout swipeRefreshLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe);
        recyclerView = (RecyclerView) findViewById(R.id.list);
        linearLayoutManager = new LinearLayoutManager(getBaseContext(), LinearLayoutManager.VERTICAL, false);
        array = new ArrayList<>();
        adapter = new PhoneAdapter(getBaseContext(), array);

        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setAdapter(adapter);
        recyclerView.setHasFixedSize(true);

        loadData(0);

        scrollListener = new EndlessRecyclerViewScrollListener(linearLayoutManager) { // مقدار دهی اسکرول لیسنتر
            @Override
            public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
                loadData(page); // کارهایی که باید بعد از اسکرول اتفاق بیافتد. در اینجا لود دادهای دیگر می باشد.
            }
        };
        recyclerView.addOnScrollListener(scrollListener); // ست کردن اسکرول لیسنر به ریسایکلر ویو

    }

public void loadData(int page) {
        NetUtils.get("?data=phone&limit=10&page=" + (page+1), null, new JsonHttpResponseHandler() {
            @Override
            public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
                JSONArray phones = response;
                try {
                    for (int i = 0; i < phones.length(); i++) {
                        array.add(new Phone(phones.getJSONObject(i)));
                    }
                    adapter.update(array);
                    swipeRefreshLayout.setRefreshing(false);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {
                Toast.makeText(getBaseContext(), "Error on request", Toast.LENGTH_LONG).show();
            }

        });
    }

}

حال پروژه را اجرا کنید و اسکرول کنید.

 

اضافه کردن ریفرش کردن با سوایپ با ریسایکلر ویو

14. دستورات زیر را به آخر تابع onCreate اضاقه کنید.

swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
// دستورات در هنگامی که ریفرش می شود لیست.
                array = new ArrayList<Phone>(); // لیست خالی می شود.
                loadData(0); // در این مثال دستور لود داده های اول برنامه را اجرا می کنیم.
                scrollListener.resetState(); // اسکرول لیسنر را ریست می کنیم
            }
        });

 

اضافه کردن کلیک بر روی آیتم های ریسایکلر ویو

15. روش های مختلفی برای این کار هست. ما با استفاده از کلاس کمکی این کار را انجام می دهیم.

فایل RecyclerItemClickListener.java را دانلود کنید و به پروژه خود اضافه کنید.

16. حال کدهای زیر را به آخر تابع onCreate اضافه کنید.

recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getBaseContext(), new RecyclerItemClickListener.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
// در این قسمت کارهایی که وقتی کلیک می شود را تعریف می کنیم
                Toast.makeText(getBaseContext(), "آیتم شماره " + array.get(position).id + " را کلیک کردید!", Toast.LENGTH_LONG).show();
            }
        }));