บทเรียนเบื้องต้นสำหรับผู้พัฒนาแอพพลิเคชัน Android กับการใช้งาน ListView แสดงค่า JSON แสดงผลรูปภาพ และทำ Intent Activity ส่งค่าไปอีกหน้าด้วย Android Studio
ก่อนจะเข้าสู่บทเรียนนี้ แนะนำว่าให้ไปศึกษาบทความ
ก่อน เพราะมันต่อเนื่องกันครับ
เริ่มต้น
ให้เราใช้ Project ก่อนหน้านี้มาทำการพัฒนาต่อเลยนะครับ โดยเราจะเพิ่ม Layout ใหม่เข้าไปชื่อว่า activity_row.xml เลือกเป็น Relative Layout นะครับ
ทำการออกแบบตาม Layout ข้างต้นครับ
หรือจะใช้ 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 ด้วยนะครับ
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 ก็
โครงสร้าง 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>
ทดสอบกันครับ
ตัวอย่างสำหรับผู้เริ่มต้นง่าย ลองเอาไปทำตามดูนะครับ