Đọc JSON Và Hiển Thị Ra Custom Listview Dùng Viewholder Pattern

Kết quả sau cùng của chúng ta sẽ như thế này:

2016-01-10_12-32-34.jpg

Bài này hướng dẫn các bạn cách custom listview dùng viewholder pattern thay cho cách truyền thống, mục đích là hạn chế việc gọi findViewById trong hàm getView, giúp cho listview của chúng ta đỡ lag hơn trong những listview có nhiều dữ liệu.

 

Rắc rối bạn có thể gặp:

  • Không đọc được JSON (1)
  • Hình ảnh định dạng GIF không hiển thị trên listview. (2)

Cách khắc phục, dùng mẹo:

  • (1) Dùng subString(start, end) để cắt bỏ phần thừa nội dung JSON, thêm urlConnection.setRequestProperty(“blabla”) khi mở kết nối.
  • (2) Dùng thư viện ion: https://github.com/koush/ion (vì dùng picasso, glide đều bị failed, bạn thêm thư viện này vào project luôn đi nhe, mình không hướng dẫn việc thêm thư viện).

 

 

OK bây giờ bắt đầu!!!

Nội dung JSON:

2016-01-10_12-40-54.jpg

Tạo thêm 3 class như hình:

 

2016-01-10_12-43-19

CustomAdapter: dùng custom.

Exchange: lưu thông tin cho từng item (mỗi đơn vị tiền tệ).

FetchData: Thực hiện việc đọc Json.

 

custom_layout.xml:

2016-01-10_11-43-45.jpg

<!--?xml version="1.0" encoding="utf-8"?-->

 

 

 

 

 

 

MainActivity:

 

public class MainActivity extends AppCompatActivity {
private ListView lvMain;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Fresco.initialize(this);
setContentView(R.layout.activity_main);
lvMain = (ListView)findViewById(R.id.lvMain);
runOnUiThread(new Runnable() {
@Override
public void run() {
new FetchData(MainActivity.this, R.layout.custom_layout, lvMain)
.execute("http://dongabank.com.vn/exchange/export");
}
});

}
}

 

CustomAdapter (chú ý Viewholder):

 

public class CustomAdapter extends ArrayAdapter {
Context context;
ArrayList arrayExchange;
public CustomAdapter(Context context, int resource, List objects) {
super(context, resource, objects);
this.context = context;
this.arrayExchange = (ArrayList) objects;
}

// Custom listview su dung view holder pattern, han che viec goi findViewById qua nhieu.
@Override
public View getView(int position, View v, ViewGroup parent) {
if(v == null){
v = LayoutInflater.from(context).inflate(R.layout.custom_layout, null);
ViewHolder viewHolder = new ViewHolder();
viewHolder.image = (ImageView) v.findViewById(R.id.imageViewFlag);
viewHolder.type = (TextView)v.findViewById(R.id.textViewType);
viewHolder.muatienmat = (TextView)v.findViewById(R.id.textViewMua);
viewHolder.bantienmat = (TextView)v.findViewById(R.id.textViewBan);
v.setTag(viewHolder);
}
Exchange ex = arrayExchange.get(position);
if(ex != null){
ViewHolder viewHolder = (ViewHolder)v.getTag();
// dung thu vien icon de hien thi anh GIF: https://github.com/koush/ion
// picasso or Glide failed here =)
Ion.with(viewHolder.image).load(ex.getImageurl());
viewHolder.type.setText(ex.getType());
viewHolder.muatienmat.setText(ex.getMuatienmat());
viewHolder.bantienmat.setText(ex.getBantienmat());
}
return v;
}

static class ViewHolder{
protected ImageView image;
protected TextView type;
protected TextView muatienmat;
protected TextView bantienmat;
}
}

FetchData:

public class FetchData extends AsyncTask<String, Void, String> {
Context context;
int customLayoutID;
ListView lvMain;
ArrayList arrayTemp;

// constructor.
public FetchData(Context context, int customLayoutID, ListView lvMain) {
this.context = context;
this.customLayoutID = customLayoutID;
this.lvMain = lvMain;
}

@Override
protected String doInBackground(String... params) {
arrayTemp = new ArrayList();
if(params[0] != null){
String content = readFromURL(params[0]);
try {
JSONObject root = new JSONObject(content);
JSONArray array = root.getJSONArray("items");
for(int i=0; i<array.length(); i++){
JSONObject item = array.getJSONObject(i);
String type = item.optString("type");
String imageurl = item.optString("imageurl");
String muatienmat = item.optString("muatienmat");
String bantienmat = item.optString("bantienmat");
arrayTemp.add(new Exchange(type, imageurl, muatienmat, bantienmat));
}
} catch (JSONException e) {
e.printStackTrace();
}
}
return null;
}

@Override
protected void onPostExecute(String value) {
CustomAdapter adapter = new CustomAdapter(context, customLayoutID, arrayTemp);
lvMain.setAdapter(adapter);
}

public Bitmap getBitmapFromURL(String src) {
try {
java.net.URL url = new java.net.URL(src);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
private static String readFromURL(String url) {
StringBuilder content = new StringBuilder();
try {
URL u = new URL(url);
URLConnection urlConnection = u.openConnection();
urlConnection.setRequestProperty("Accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(urlConnection.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null) {
content.append(line + "\n");
}
bufferedReader.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// this is a hack =))
return content.toString().substring(1, content.length()-2);
}
}

 

Exchange:

public class Exchange {
String type;
String image;
String muatienmat;
String bantienmat;

public Exchange(String type, String image, String muatienmat, String bantienmat) {
this.type = type;
this.image = image;
this.muatienmat = muatienmat;
this.bantienmat = bantienmat;
}

public String getType() {
return type;
}

public String getImageurl() {
return image;
}

public String getMuatienmat() {
return muatienmat;
}

public String getBantienmat() {
return bantienmat;
}
}

 

Không quên thêm permissions cho phép kết nối đến internet vào androidManifest nhé!

 

 

This project on Github: 

https://github.com/minhhuy150894/Dong-A-Bank-Exchange

Nếu gặp vướng mắc bạn có thể comment bên dưới.

Advertisements

4 thoughts on “Đọc JSON Và Hiển Thị Ra Custom Listview Dùng Viewholder Pattern

    • Khi mới làm quen thì tất nhiên là bắt đầu với Async nhưng khi đã nâng cao lên rồi thì bạn nên dùng volley hơn, Volley có thể xem như là phiên bản nâng cấp của Async. Có thể thực hiện nhiều truy cập đồng thời mà k làm ảnh hưởng đến thread. Ngoài volley, mình hay dùng thằng retrofit

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s