Android DeveloperDeveloperFeatured

เขียนแอพ Android ร่วมกับ JSON แสดงภาพบน ListView และ Intent

บทเรียนเบื้องต้นสำหรับผู้พัฒนาแอพพลิเคชัน Android กับการใช้งาน ListView แสดงค่า JSON แสดงผลรูปภาพ และทำ Intent Activity ส่งค่าไปอีกหน้าด้วย Android Studio

ก่อนจะเข้าสู่บทเรียนนี้ แนะนำว่าให้ไปศึกษาบทความ

เขียนแอพ Android เรียก JSON Web service แสดงบน ListView

ก่อน เพราะมันต่อเนื่องกันครับ

เริ่มต้น

ให้เราใช้ Project ก่อนหน้านี้มาทำการพัฒนาต่อเลยนะครับ โดยเราจะเพิ่ม Layout ใหม่เข้าไปชื่อว่า activity_row.xml เลือกเป็น Relative Layout นะครับ

Screen Shot 2558-04-01 at 11.20.50 PM

ทำการออกแบบตาม Layout ข้างต้นครับ

Screen Shot 2558-04-01 at 11.21.19 PM

หรือจะใช้ 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" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">


    <ImageView
        android:layout_width="fill_parent"
        android:layout_height="172dp"
        android:id="@+id/articleImage"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/banner"
        android:maxWidth="300dp"
        android:maxHeight="172dp" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="Large Text"
        android:id="@+id/articleTitle"
        android:layout_below="@+id/articleImage"
        android:layout_alignStart="@+id/articleImage"
        android:width="300dp" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:text="Small Text"
        android:id="@+id/articleID"
        android:layout_below="@+id/articleTitle"
        android:layout_alignEnd="@+id/articleTitle"
        android:width="300dp" />
</RelativeLayout>

เราจะได้ Layout ที่เปรียบเสมือน Row หรือแถวของ ListView ของเราทันทีครับ ต่อมาให้เปิดไฟล์ MainActivity.java ขึ้นมาแก้ไข บรรทัดส่วนของคำสั่งในการ Get ค่า JSON ส่วนนี้จากเดิมคือ

List<NameValuePair> params = new ArrayList<NameValuePair>();
 try {
 JSONArray data = new JSONArray(getJSON(url,params));

 final ArrayList<HashMap<String, String>> MyArrList = new ArrayList<HashMap<String, String>>();
 HashMap<String, String> map;

 for(int i = 0; i < data.length(); i++){
 JSONObject c = data.getJSONObject(i);

 map = new HashMap<String, String>();
 map.put("id", c.getString("id"));
 map.put("title", c.getString("title"));
 MyArrList.add(map);

 }


 SimpleAdapter simpleAdapterData;
 simpleAdapterData = new SimpleAdapter(MainActivity.this, MyArrList, R.layout.activity_column,
 new String[] {"id", "title"}, new int[] {R.id.articleID, R.id.articleTitle});
 listViewMovies.setAdapter(simpleAdapterData);
 } catch (JSONException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }

แก้ไขเป็น

final ListView listViewMovies = (ListView)findViewById(R.id.listView1);
        String url = "http://lovedesigner.net/feed/json";

        List<NameValuePair> params = new ArrayList<NameValuePair>();
        try {
            JSONArray data = new JSONArray(getJSON(url,params));

            final ArrayList<HashMap<String, String>> MyArrList = new ArrayList<HashMap<String, String>>();
            HashMap<String, String> map;

            for(int i = 0; i < data.length(); i++){
                JSONObject c = data.getJSONObject(i);

                map = new HashMap<String, String>();
                map.put("id", c.getString("id"));
                map.put("title", c.getString("title"));
                map.put("thumbnail", c.getString("thumbnail"));
                map.put("excerpt", c.getString("excerpt"));
                map.put("content", c.getString("content"));
                MyArrList.add(map);

            }


            SimpleAdapter simpleAdapterData;
            simpleAdapterData = new SimpleAdapter(MainActivity.this, MyArrList, R.layout.activity_row,
                    new String[] {"id", "title"}, new int[] {R.id.articleID, R.id.articleTitle});
            listViewMovies.setAdapter(simpleAdapterData);

            listViewMovies.setAdapter(new showImageOnList(this, MyArrList));
            listViewMovies.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    int itemPosition = position;
                    Intent showPage = new Intent(MainActivity.this,MainActivity2.class);
                    showPage.putExtra("index",""+itemPosition+"");
                    showPage.putExtra("title",""+MyArrList.get(position).get("title")+"");
                    showPage.putExtra("thumbnail",""+MyArrList.get(position).get("thumbnail")+"");
                    showPage.putExtra("content",""+MyArrList.get(position).get("content")+"");
                    startActivity(showPage);
                }
            });



        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

เราจะดึง Key ใน json ของเราเพิ่มเข้ามาคือ thumbnail, excerpt (คำโปรย) และ content (เนื้อหาทั้งหมด) มาเก็บลงในตัวแปร MyArrList และพร้อมกับ สร้าง Intent เข้าไปเพิ่ม (อย่าลืม import header นะครับ)

ขณะนี้เราจะพบกับ Error อยู่ 1 จุดคือ showImageOnList ซึ่งมันไม่รู้จักให้กด Auto หรือ สร้าง Class ใหม่มารับรองมันก็ได้ครับ ซึ่งตรงนี้แหละครับที่เราจะใช้สำหรับ ดึง URL ของรูปภาพมาปรากฏบน ImageView ใน activity_row.xml

ซึ่งให้สร้าง Class showImageOnList ขึ้นมาใหม่ครับ ใส่คำสั่งดังนี้

public class showImageOnList extends BaseAdapter
    {
        private Context context;
        private ArrayList<HashMap<String, String>> MyArr = new ArrayList<HashMap<String, String>>();

        public showImageOnList(Context c, ArrayList<HashMap<String, String>> list)
        {
            // TODO Auto-generated method stub
            context = c;
            MyArr = list;
        }

        public int getCount() {
            // TODO Auto-generated method stub
            return MyArr.size();
        }

        public Object getItem(int position) {
            // TODO Auto-generated method stub
            return position;
        }

        public long getItemId(int position) {
            // TODO Auto-generated method stub
            return position;
        }
        public View getView(int position, View convertView, ViewGroup parent) {
            // TODO Auto-generated method stub

            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            if (convertView == null) {
                convertView = inflater.inflate(R.layout.activity_row, null);
            }

            //ListViewImages
            final ImageView get_thumbnail = (ImageView) convertView.findViewById(R.id.articleImage);

get_thumbnail.setScaleType(ImageView.ScaleType.CENTER_CROP);
            try
            {
                get_thumbnail.setImageBitmap(loadBitmap(MyArr.get(position).get("thumbnail")));
            } catch (Exception e) {
                get_thumbnail.setImageResource(android.R.drawable.ic_menu_report_image);
            }

            final TextView titleMovies = (TextView) convertView.findViewById(R.id.articleTitle);
            titleMovies.setText(MyArr.get(position).get("title"));

            final TextView idContents = (TextView) convertView.findViewById(R.id.articleID);
            idContents.setText("Content ID: " + MyArr.get(position).get("excerpt"));
            return convertView;

        }

    }

ดังนั้นส่วนของ Header ที่ปรากฏก็จะเป็นเช่นนี้ครับ

import android.content.Context;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import java.net.URL;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.StrictMode;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleAdapter;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.TextView;

import android.content.Intent;

Class ของ showImageOnList นั้น

get_thumbnail.setImageBitmap(loadBitmap(MyArr.get(position).get("thumbnail")));

เป็นการดึง Key ของ thumbnail ที่เป็น URL ของรูปภาพมาเก็บที่ imageView ครับ โดยอ้างไฟล์ activity_row.xml ที่บรรทัด

if (convertView == null) {
                convertView = inflater.inflate(R.layout.activity_row, null);
            }

ตามด้วยการ Binding ค่า title และ excerpt มาปรากฏบน Layout

inal TextView titleMovies = (TextView) convertView.findViewById(R.id.articleTitle);
            titleMovies.setText(MyArr.get(position).get("title"));

            final TextView idContents = (TextView) convertView.findViewById(R.id.articleID);
            idContents.setText("Content ID: " + MyArr.get(position).get("excerpt"));

โดย Method สำหรับเรียกใช้งาน Bitmap นั้นอยู่ที่นี่ครับ

private static final String TAG = "ERROR";
    private static final int IO_BUFFER_SIZE = 4 * 1024;
    public static Bitmap loadBitmap(String url) {
        Bitmap bitmap = null;
        InputStream in = null;
        BufferedOutputStream out = null;

        try {
            in = new BufferedInputStream(new URL(url).openStream(), IO_BUFFER_SIZE);

            final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
            out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);
            copy(in, out);
            out.flush();

            final byte[] data = dataStream.toByteArray();
            BitmapFactory.Options options = new BitmapFactory.Options();

            bitmap = BitmapFactory.decodeByteArray(data, 0, data.length,options);
        } catch (IOException e) {
            Log.e(TAG, "Could not load Bitmap from: " + url);
        } finally {
            closeStream(in);
            closeStream(out);
        }

        return bitmap;
    }

    private static void closeStream(Closeable stream) {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                android.util.Log.e(TAG, "Could not close stream", e);
            }
        }
    }

    private static void copy(InputStream in, OutputStream out) throws IOException {
        byte[] b = new byte[IO_BUFFER_SIZE];
        int read;
        while ((read = in.read(b)) != -1) {
            out.write(b, 0, read);
        }
    }

ภาพรวมของ Code ไฟล์ MainActivity.java เป็นดังนี้ครับ

package com.daydev.webservices;

import android.content.Context;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import java.net.URL;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.StrictMode;

import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleAdapter;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.widget.TextView;

import android.content.Intent;

public class MainActivity extends ActionBarActivity {

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

        if (android.os.Build.VERSION.SDK_INT > 9) {
            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
            StrictMode.setThreadPolicy(policy);
        }

        final ListView listViewMovies = (ListView)findViewById(R.id.listView1);
        String url = "http://lovedesigner.net/feed/json";

        List<NameValuePair> params = new ArrayList<NameValuePair>();
        try {
            JSONArray data = new JSONArray(getJSON(url,params));

            final ArrayList<HashMap<String, String>> MyArrList = new ArrayList<HashMap<String, String>>();
            HashMap<String, String> map;

            for(int i = 0; i < data.length(); i++){
                JSONObject c = data.getJSONObject(i);

                map = new HashMap<String, String>();
                map.put("id", c.getString("id"));
                map.put("title", c.getString("title"));
                map.put("thumbnail", c.getString("thumbnail"));
                map.put("excerpt", c.getString("excerpt"));
                map.put("content", c.getString("content"));
                MyArrList.add(map);

            }


            SimpleAdapter simpleAdapterData;
            simpleAdapterData = new SimpleAdapter(MainActivity.this, MyArrList, R.layout.activity_row,
                    new String[] {"id", "title"}, new int[] {R.id.articleID, R.id.articleTitle});
            listViewMovies.setAdapter(simpleAdapterData);

            listViewMovies.setAdapter(new showImageOnList(this, MyArrList));
            listViewMovies.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    int itemPosition = position;
                    Intent showPage = new Intent(MainActivity.this,MainActivity2.class);
                    showPage.putExtra("index",""+itemPosition+"");
                    showPage.putExtra("title",""+MyArrList.get(position).get("title")+"");
                    showPage.putExtra("thumbnail",""+MyArrList.get(position).get("thumbnail")+"");
                    showPage.putExtra("content",""+MyArrList.get(position).get("content")+"");
                    startActivity(showPage);
                }
            });



        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public class showImageOnList extends BaseAdapter
    {
        private Context context;
        private ArrayList<HashMap<String, String>> MyArr = new ArrayList<HashMap<String, String>>();

        public showImageOnList(Context c, ArrayList<HashMap<String, String>> list)
        {
            // TODO Auto-generated method stub
            context = c;
            MyArr = list;
        }

        public int getCount() {
            // TODO Auto-generated method stub
            return MyArr.size();
        }

        public Object getItem(int position) {
            // TODO Auto-generated method stub
            return position;
        }

        public long getItemId(int position) {
            // TODO Auto-generated method stub
            return position;
        }
        public View getView(int position, View convertView, ViewGroup parent) {
            // TODO Auto-generated method stub

            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

            if (convertView == null) {
                convertView = inflater.inflate(R.layout.activity_row, null);
            }

            //ListViewImages
            final ImageView get_thumbnail = (ImageView) convertView.findViewById(R.id.articleImage);

            get_thumbnail.setScaleType(ImageView.ScaleType.CENTER_CROP);
            try
            {
                get_thumbnail.setImageBitmap(loadBitmap(MyArr.get(position).get("thumbnail")));
            } catch (Exception e) {
                get_thumbnail.setImageResource(android.R.drawable.ic_menu_report_image);
            }

            final TextView titleMovies = (TextView) convertView.findViewById(R.id.articleTitle);
            titleMovies.setText(MyArr.get(position).get("title"));

            final TextView idContents = (TextView) convertView.findViewById(R.id.articleID);
            idContents.setText("Content ID: " + MyArr.get(position).get("excerpt"));
            return convertView;

        }

    }

    public String getJSON(String url,List<NameValuePair> params) {
        StringBuilder str = new StringBuilder();
        HttpClient client = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);

        try {
            httpPost.setEntity(new UrlEncodedFormEntity(params));
            HttpResponse response = client.execute(httpPost);
            StatusLine statusLine = response.getStatusLine();
            int statusCode = statusLine.getStatusCode();
            if (statusCode == 200) {
                HttpEntity entity = response.getEntity();
                InputStream content = entity.getContent();
                BufferedReader reader_buffer = new BufferedReader
                (new InputStreamReader(content));

                String line;
                while ((line = reader_buffer.readLine()) != null) {
                    str.append(line);
                }
            } else {
                Log.e("Log", "Failed to download file..");
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return str.toString();
    }


    private static final String TAG = "ERROR";
    private static final int IO_BUFFER_SIZE = 4 * 1024;
    public static Bitmap loadBitmap(String url) {
        Bitmap bitmap = null;
        InputStream in = null;
        BufferedOutputStream out = null;

        try {
            in = new BufferedInputStream(new URL(url).openStream(), IO_BUFFER_SIZE);

            final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
            out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);
            copy(in, out);
            out.flush();

            final byte[] data = dataStream.toByteArray();
            BitmapFactory.Options options = new BitmapFactory.Options();

            bitmap = BitmapFactory.decodeByteArray(data, 0, data.length,options);
        } catch (IOException e) {
            Log.e(TAG, "Could not load Bitmap from: " + url);
        } finally {
            closeStream(in);
            closeStream(out);
        }

        return bitmap;
    }

    private static void closeStream(Closeable stream) {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                android.util.Log.e(TAG, "Could not close stream", e);
            }
        }
    }

    private static void copy(InputStream in, OutputStream out) throws IOException {
        byte[] b = new byte[IO_BUFFER_SIZE];
        int read;
        while ((read = in.read(b)) != -1) {
            out.write(b, 0, read);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

อย่าลืมไปสร้าง MainActivity2.java เพื่อมารับหน้าสำหรับ Intent ด้วยนะครับ

Screen Shot 2558-04-01 at 11.40.34 PM

Code ของ MainActivity2.java ไม่มีอะไรมาก

package com.daydev.webservices;

import android.content.Intent;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.text.Spanned;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;

import android.text.Html;

public class MainActivity2 extends ActionBarActivity {

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

        final TextView txtTitle_show = (TextView)findViewById(R.id.textTitle);
        final TextView txtDetail_show = (TextView)findViewById(R.id.textDetail);

        Intent intent= getIntent();
        final String txt_get_title = intent.getStringExtra("title");
        final String txt_get_detail= intent.getStringExtra("content");
        txtTitle_show.setText(txt_get_title);

        Spanned result = Html.fromHtml(txt_get_detail);
        txtDetail_show.setText(result);

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main_activity2, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

ส่วน Layout ของ activity_main2.xml ก็

Screen Shot 2558-04-01 at 11.40.42 PM

โครงสร้าง 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" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.daydev.webservices.MainActivity2">

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="Large Text"
        android:id="@+id/textTitle"
        android:layout_centerHorizontal="true" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:text="Small Text"
        android:id="@+id/textDetail"
        android:layout_below="@+id/textTitle"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="41dp"
        android:layout_alignParentBottom="true"
        android:singleLine="false" />
</RelativeLayout>

ทดสอบกันครับ

เปิดแอพ แบบไม่ใส่ Excerpt
เปิดแอพ แบบไม่ใส่ Excerpt
ใส่ excerpt เข้าไป
ใส่ excerpt เข้าไป
กด Intent แล้วเจอหน้า Detail
กด Intent แล้วเจอหน้า Detail

ตัวอย่างสำหรับผู้เริ่มต้นง่าย ลองเอาไปทำตามดูนะครับ

Asst. Prof. Banyapon Poolsawas

อาจารย์ประจำสาขาวิชาการออกแบบเชิงโต้ตอบ และการพัฒนาเกม วิทยาลัยครีเอทีฟดีไซน์ & เอ็นเตอร์เทนเมนต์เทคโนโลยี มหาวิทยาลัยธุรกิจบัณฑิตย์ ผู้ก่อตั้ง บริษัท Daydev Co., Ltd, (เดย์เดฟ จำกัด)

Related Articles

Back to top button

Adblock Detected

เราตรวจพบว่าคุณใช้ Adblock บนบราวเซอร์ของคุณ,กรุณาปิดระบบ Adblock ก่อนเข้าอ่าน Content ของเรานะครับ, ถือว่าช่วยเหลือกัน