ListView Project (6)

ListView project ေလးတစ္ခု အပ်င္းေျပ ေရးၾကည္႔ရေအာင္ဗ်ာ ... အပိုင္း ( 6 )
***********************

ျပီးခဲ႔တဲ႔ အပိုင္းအထိ ျပည္႔ျပည္႔စံုစံု code ျပီးေနမယ္လို႔ ယူဆပါတယ္။

ဒီအပိုင္းမွာေတာ႔ က်ေနာ္တို႔ List အတြက္ လိုအပ္မယ္႔ Adapter ပိုင္းကို ေလ႔လာရင္း code သြားရေအာင္လား။

List ေတြကို ျပဖို႔ android က ေပးထားတဲ႔ မူရင္း Adapter class ေတြကို ယူသံုးရင္လည္း ရပါတယ္။ ဒါေပမယ္႔ က်ေနာ္တို႔က အဲ႔ဒီလို မသံုးခ်င္ဘူးေလ။ List အတြင္းက item ေလးေတြအတြက္ ကိုယ္တိုင္ စိတ္ၾကိဳက္ေရးထားတဲ႔ layout ေလးေတြကိုလည္း သံုးလိုက္ခ်င္ေသးတာ။ ဒီလို ကိုယ္႔စိတ္ၾကိဳက္ သံုးႏိုင္ဖို႔ဆိုရင္ List အတြက္ ကိုယ္သံုးမယ္႔ မူရင္း Adapter class ကို extends လုပ္ယူျပီး ကိုယ္သံုးခ်င္တဲ႔ layout ကို Custom Dialog class တုန္းကလို @Override လုပ္ယူေရးရမွာေပါ႔။ ( ကိုယ္႔ ListView မွာ ေပၚမယ္႔ list row အတြက္ ကိုယ္သံုးခ်င္တဲ႔ layout တစ္ခုကို list_row.xml ဆိုတဲ႔ နာမည္နဲ႔ design ဆြဲထားေပးပါ။ အခု project မွာသံုးမယ္႔ က်ေနာ္႔ list_row.xml layout ကို ဒီ post ေအာက္ဆံုးမွာ ေပးထားပါမယ္။)

ဘာပဲျဖစ္ျဖစ္ class တစ္ခုေတာ႔ ေရးကို ေရးရေတာ႔မွေပါ႔။ ကဲဗ်ာ ေျပာေနၾကာတယ္ အခုပဲ ေရးလိုက္ၾကရေအာင္။ အခု ေရးမွာက Adapter အတြက္ class ဆိုေတာ႔ နာမည္တစ္ခုခု ေပးျပီး class အသစ္ေတာင္းလိုက္ပါ။ ထားပါေတာ႔ class နာမည္ကို FighterAdapter ...

public class FighterAdapter
{

}

ဒီ class အတြက္ constructor ပါ ထည္႔ေရးဗ်ာ။ (ရွင္းျပျပီး။)

public class FighterAdapter
{


FighterAdapter() {


}

}

ေနဦး အခု class က android SDK မွာပါတဲ႔ မူရင္း Adapter class တစ္ခုခုကို extends လုပ္ျပီး ကိုယ္႔ Layout View ကို @Override လုပ္ ေရးရမွာ မဟုတ္လား? ဆိုေတာ႔ မူရင္း ဘယ္ Adapter class ကို extends လုပ္ယူရင္ ေကာင္းမလဲ?

OK, က်ေနာ္တို႔က List ကို ArrayList<> အမ်ိဳးအစား သံုးမယ္လို႔ ဆံုးျဖတ္ထားျပီးသားေနာ္။ ဆိုေတာ႔ android မွာ ေပးထားတဲ႔ မူရင္း Adapter class ေတြထဲမွာ ArrayAdapter ဆိုတဲ႔ class တစ္ခု ပါတယ္ဗ်။ ArrayList<> အတြက္ ArrayAdapter ကြက္စတိပဲ။ အဲ႔ class ကို extends ယူေရးမယ္ဗ်။ (အျခား CursorAdapter, BaseAdapter  စတဲ႕ class ေတြလည္း ရွိပါေသးတယ္။ )

ကဲ ArrayAdapter class ကို extends ယူလိုက္ၾကမယ္။

public class FighterAdapter extends ArrayAdapter<AIDEFighter> {


FighterAdapter() {


}

}

( extends ေနာက္က ArrayAdapter<AIDEFighter> မွာ ArrayList မွာ က်ေနာ္တို႔ထည္႕သံုးထားတဲ႔/မယ္႔ AIDEFighter (object) အမ်ိဳးအစား တိတိက်က် သတ္မွတ္ေပးထားတာကို သတိျပဳပါ။)

အဲ ... အခုလို ArrayAdapter class ကို extends လုပ္လိုက္တာနဲ႔ AIDE IDE က error ေပးေတာ႔တာပါပဲ။ ေအာက္က screenshot ပံုတစ္ခုထဲမွာလည္း error ကို ျပထားပါတယ္။ ဘာတဲ႔ error က ...

There is no applicable constructor to '( )' တဲ႔။

ဒီ error ကို နားလည္ဖို႔ က်ေနာ္တို႔ class ေတြရဲ႕ constructor ကို နည္းနည္း တီးမိေခါက္မိ ရွိရပါမယ္။

အဲ႔ဒါကေတာ႔ က်ေနာ္တို႔ class တစ္ခုကို extends လုပ္လိုက္တိုင္း ကူးတဲ႔ class (sub class) ရဲ႕  constructor ထဲမွာ အကူးခံရတဲ႔ class (super class) ရဲ႕ constructor ကိုပါ ျပန္ ေခၚေပးရတယ္ဆိုတာပါ။ (subclass superclass အေၾကာင္း အရင္အပိုင္းတြင္ ပါျပီး။)

ဆိုေတာ႔ အခု sub class ရဲ႕ constructor က

FighterAdapter() {


}

ဒီ constructor ထဲမွာ extends အကူးခံရတဲ႔ ArrayAdapter ဆိုတဲ႔ superclass ရဲ႕ constructor ကို ျပန္ ေခၚပါဆိုေတာ႔ ( super keyword နဲ႔ သံုး ေခၚပါတယ္။ ) ဒီလို ေခၚလိုက္ပါတယ္။

FighterAdapter() {
     super( );

}

တိန္!!! ... အဲ႔ဒီလို super(); နဲ႔ superclass ရဲ႕ constructor ကို လွမ္းေခၚတဲ႔ဟာ ေရးေပးလိုက္တာကိုပဲ ေစာေစာက ျပေနတဲ႔ error က ေပ်ာက္မသြားတဲ႔ျပင္ error က က်ေနာ္တို႔ ေရးလိုက္တဲ႔ super(); က ( ) ကို အနီလိုင္းနဲ႔ လာေထာက္ျပေနလိုက္ေသး! ခက္စေတာ႔ အေတာ္ေလးကို ခက္ေနျပီ။ ဘာလိုေနပါလိမ္႔? က်ေနာ္တို႔က မွန္ျပီး AIDE IDE ကမ်ား မွားေနေလေရာ႔သလား?! :)

မဟုတ္ပါဘူး။ အမွန္က ဒီလိုပါ က်ေနာ္တို႔ extends ကူးလိုက္တဲ႔ ArrayAdapter class ရဲ႕ constructor မွာကိုက သူ႔ class အတြင္းမွာ သံုးဖို႔ input အျဖစ္ data တစ္ခ်ိဳ႕ ေတာင္းထားတာ ရွိေနလို႔ပါ။ ဘာ data ေတြ ေတာင္းထားလဲ? input သံုးမ်ိဳးေတာင္းထားပါတယ္။

1) Context ရယ္၊
2) ListView မွာ row အျဖစ္သံုးဖို႔ layout ရယ္၊ ျပီးေတာ႔
3) ArrayList အမ်ိဳးအစား List စာရင္း data ရယ္ဆိုျပီး

သံုးမ်ိဳးေတာင္းထားပါတယ္။ က်ေနာ္တို႔က superclass constructor က ေတာင္းထားတဲ႔ data ေတြကို ထည္႔မေပးပဲ ဘာ data မွ မပါတဲ႔ ဗလာ constructor ( super();  ) နဲ႔ က်ေနာ္တို႔က ျပန္ေခၚမိတာေၾကာင့္ အခု error ျပေနျခင္းပါ။

ဒါဆို သူေတာင္းတဲ႔ data သံုးမ်ိဳးကိုလည္း က်ေနာ္တို႔က က်ေနာ္တို႔ subclass ရဲ႕ constructor ထဲမွာ ျပန္ေတာင္းျပီး superclass constructor ထဲကို ထည္႔ေပးလိုက္ႏိုင္ရင္ OK ျပီေပါ႔။

ဒါဆို က်ေနာ္တို႔ အခုေရးထားတဲ႔ FighterAdapter ရဲ႕ constructor ကိုလည္း လိုအပ္တဲ႔ဟာေတြ input ေတာင္းယူဖို႔ အခုလို ျပင္ေရးရပါမယ္။

FighterAdapter(Context context, ArrayList<AIDEFighter> fighterList) {

}

Context object ကို context ဆိုတဲ႔ variable နာမည္ေလးနဲ႔ ေတာင္းထားတယ္။ ArrayList<?> အမ်ိဳးအစား List စာရင္းကို fighterList ဆိုတဲ႔ variable နာမည္ေလးနဲ႔ input ေတာင္းယူ လက္ခံတယ္ေပါ႔။

ဒီေနရာမွာ က်ေနာ္တို႔ရဲ႕ constructor ထဲမွာ input ႏွစ္ခုပဲ ေတာင္းပါမယ္။ ယူသံုးမယ္႔ layout က ဆြဲျပီးသား list_row.xml ဆိုတဲ႔ Layout ကို  R.layout.xxxx ဆိုတာနဲ႔ superclass ဆီကို constructor ကေန လွမ္းပို႔လိုက္လို႔ရလို႔ပါ။

အဲ႔ဒီေတာ႔မွ superclass က ေတာင္းထားတဲ႔ data ေတြ ေပးႏိုင္ျပီမို႔ super keyword နဲ႔ superclass constructor ဆီကို ထည္႔ေပးလိုက္ပါ။

FighterAdapter(Context context, ArrayList<AIDEFighter> fighterList) {
super(context,R.layout.list_row,fighterList);

}

}

ဒါဆို ေစာေစာက error ေပ်ာက္သြားမွာျဖစ္ပါတယ္။

ဆက္လက္ျပီး subclass ရဲ႕ constructor ထဲမွာပဲ input အျဖစ္ေတာင္းယူထားတဲ႔ Context နဲ႔ ArrayList<> ကို အခု class ထဲမွာ ယူသံုးႏိုင္ေအာင္ class variable ႏွစ္ခုနဲ႔ ဖမ္းယူလိုက္ပါမယ္။ ဒါဆို အခု FighterAdapter class က ဒီလိုရလာမွာ ျဖစ္ပါတယ္။

public class FighterAdapter extends ArrayAdapter<AIDEFighter> {

Context mContext;
ArrayList<AIDEFighter> mFighterList;

FighterAdapter(Context context, ArrayList<AIDEFighter> fighterList) {

super(context,R.layout.list_row,fighterList);

mContext = context;
mFighterList = fighterList;
}

}

constructor ပိုင္း မွန္သြားျပီဆိုေတာ႔ List row မွာ ကိုယ္သံုးခ်င္တဲ႔ list_row.xml layout ကို View ျပင္ယူဖို႔အတြက္ Custom Dialog Box class မွာတုန္းကလို အခု Adapter class ရဲ႕ View ထုတ္ေပးတဲ႔ method ကို ရွာျပီး @Override လုပ္ေပးရမွာပါ။

Android source code ဆရာ Google က developer ေတြကို ေျပာျပီးသားပါ။ Custom View အစားထိုးခ်င္ရင္ အခုလို Adapter class ေတြရဲ႕ getView() method ကို @Override လုပ္ေပးၾကပါဆိုတာကို။ ဆိုတာ အရင္အပိုင္းက အတိုင္း getView() method ကို auto complete နဲ႔ @Override လုပ္ခ်လိုက္ပါ။ ဒီလို ရလာပါမယ္ -

@Override
public View getView(int position, View convertView, ViewGroup parent)
{
// TODO: Implement this method
return super.getView(position, convertView, parent);
}

ေျပာျပျပီးသားပါ custom layout View တစ္ခု ေခၚဖြင့္ဖို႕ LayoutInflator ဆိုတာ လိုပါတယ္လို႔။ အခု @Override လုပ္လိုက္တဲ႔ method မွာ LayoutInflator ဆိုတာေပးမထားပါဘူး။ int position တို႔ ViewGroup တို႕ပဲ ပါလာပါတယ္။ (Custom Dialog class တုန္းက အခုလို @Override လုပ္လိုက္ခ်ိန္ method တြင္းမွာ LayoutInflator object ပါ ပါလာတာကို ျပန္ၾကည္႔သတိျပဳပါ။)

ဒါေၾကာင့္ LayoutInflator ကို ကိုယ္႔နည္းကိုယ္႔ဟန္နဲ႔ လွမ္းယူရပါေတာ႔မယ္။ ဘယ္ကေနယူမလဲ ? ေစာေစာက ဖမ္းယူလိုက္တဲ႔ Context object ျဖစ္တဲ႔ mContext ကေန LayoutInflator ကို casting လုပ္ျပီး အခုလို code နဲ႔ ယူလို႔ရပါတယ္။

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

ျပီးေတာ႔မွ ဒီ LayoutInflator object ကေန inflate() method နဲ႔ list_row.xml က View ကို ယူပါမယ္။

View rowLayout = inflater.inflate(R.layout.list_row, parent, false);

ဒီရလာတဲ႔ View ကို return ကေန ထုတ္ေပးလိုက္ရံုပါပဲ။

return rowLayout;

ဒါဆို အခု @Override လုပ္လိုက္တဲ႔ method အျပည္႔အစံုက ဒီလို ျဖစ္ပါမယ္။

@Override
public View getView(int position, View convertView, ViewGroup parent) {

LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowLayout = inflater.inflate(R.layout.list_row, parent, false);


return rowLayout;
}

ဒီေနရာမွာ ျမင္တတ္သူမ်ားက ေမးခ်င္ရင္ ေမးလို႔ရတာ တစ္ခုရွိပါတယ္။ က်ေနာ္တို႔ superclass constructor ထဲကေန တစ္ခါတည္း က်ေနာ္တို႔သံုးခ်င္တဲ႔ list_row.xml layout ကို ထည္႔ျပီးေပးလိုက္ျပီးျပီ ဘာျဖစ္လို႔ ဒီ getView() method ကို @Override ထပ္လုပ္ျပီး View ကို ထပ္လုပ္ေနရသလဲ ဆိုတာပါ။ အေျဖက constructor မွာ ထည္႔ေပးလိုက္ျပီးသားမို႔ က်ေနာ္တို႔က အခု getView() မွာ  အဲ႔ဒီ View ကို @Override လုပ္ျပီး ယူျပီး ေျပာင္းလဲတာပါ။ ဘယ္လိုေျပာင္းလဲတာလဲဆိုေတာ႔ အဲ႔ဒီ View မွာ က်ေနာ္တို႔ စိတ္ၾကိဳက္ထည္႔လိုက္တဲ႔ TextView ေတြ Button ေတြ ပါပါတယ္။ အဲ႔ဒီ Button ေတြ click လုပ္ရင္သိေအာင္ OnClickListener() ေတြ ခ်ိတ္သင့္ရင္ ခ်ိတ္ေပးဖို႔အတြက္ပါ။ ဒါေၾကာင့္ အခု @Override လုပ္တဲ႔ method နာမည္ကိုက getView() ပါ။ List row အတြက္ Adapter က ယူသံုးထားတဲ႔ row layout View ကို get ဒီ method အတြင္းက ရယူႏိုင္ျပီး ေျပာင္းလဲတာေတြ ဘာေတြလုပ္ပါလို႔ ဆိုလိုတာပါ။ Google က ဒီလို method နာမည္ကို method က လုပ္ေပးတဲ႔ လုပ္ေဆာင္ခ်က္ေလးေတြနဲ႔ action ယူျပီး ေပးထားတာေၾကာင့္ နာမည္ၾကည္႔ရံုနဲ႔ ဘာ method ဆိုတာ သိႏိုင္ပါတယ္။ က်ေနာ္တို႔သာ ဒီ getView() method ကို @Override လုပ္မေျပာင္းပဲ သံုးမယ္ဆို list_row.xml ကိုေတာ႔ ယူသံုးပါရဲ႕ သူ႔ထဲက Button ေတြ onClick() မခ်ိတ္လိုက္ရတဲ႔အတြက္ click action ကို ဖမ္းလို႔ ရမွာမဟုတ္ပါဘူး။ ေနာက္အပိုင္းေတြမွာ ဒီေနရာကေန Button id ေတြရွာခ်ိတ္ျပီး OnClick() ခ်ိတ္သြားပါမယ္။

ဒါပါပဲ Adapter class က ဒီ getView() method တစ္ခုကို @Override လုပ္ရံုနဲ႔ က်ေနာ္တို႔ FighterAdapter class က စိတ္ၾကိဳက္ျပင္ယူထားတဲ႔ Custom Adapter class တစ္ခုအေနနဲ႔ အသံုးျပဳလို႔ ရသြားပါျပီ။

လိုက္ code ေနသူေတြအေနနဲ႔လည္း code ရင္း ဘယ္ code က ဘာေၾကာင့္ဆိုတာ အတတ္ႏိုင္ဆံုး သီအိုရီ လိုက္ေပးခဲ႔တာမို႔ တျဖည္းျဖည္း code flow ကို နားလည္လာႏိုင္မယ္လို႔ ေမွ်ာ္လင့္ပါတယ္။ နားမလည္ပါက ေရးျပသူ က်ေနာ္ ညံ႕ေသးလို႔ပဲလို႔ ေအာက္ေမ႔ျပီး ဆက္ၾကိဳးစား သြားပါမယ္။

ဆိုေတာ႔ ဒီအပိုင္းကို ဒီမွာတင္ ရပ္ျပီး ေနာက္အပိုင္းေတြမွာ ဘယ္ေနရာေတြ ဘယ္လို လိုက္ code မယ္ဆိုတာ ေစာင့္ေမွ်ာ္ရင္း ....

အပိုင္း ( 7 ) ေမွ်ာ္ .... :)

list_row.xml (အၾကမ္း)
===========

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<RelativeLayout
android:layout_height="100dp"
android:layout_width="match_parent"
android:background="#6D1092"
android:layout_centerVertical="true">

<ImageView
android:layout_height="50dp"
android:layout_width="50dp"
android:src="@android:drawable/ic_delete"
android:layout_centerVertical="true"
android:id="@+id/listrowImageView1"
android:layout_marginLeft="5dp"/>

<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:textColor="#FFFFFF"
android:layout_alignParentRight="true"
android:layout_centerVertical="false"
android:textSize="15sp"
android:background="#EC2929"
android:padding="5dp"
android:id="@+id/levelTv"/>

<LinearLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:orientation="horizontal"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:gravity="bottom|center"
android:id="@+id/listrowLinearLayout1">

<Button
android:layout_height="35dp"
style="?android:attr/buttonStyleSmall"
android:text="Delete"
android:layout_width="wrap_content"
android:layout_marginRight="35dp"
android:background="#FB4136"
android:textColor="#FBFBFB"/>

<Button
android:layout_height="35dp"
style="?android:attr/buttonStyleSmall"
android:text="Call"
android:layout_width="wrap_content"
android:background="#494EF1"
android:textColor="#FFFFFF"/>

</LinearLayout>

<TextView
android:layout_height="wrap_content"
android:text="Text"
android:layout_width="wrap_content"
android:layout_centerInParent="true"
android:layout_above="@id/listrowLinearLayout1"
android:padding="5dp"
android:textSize="18sp"
android:textColor="#FFFFFF"
android:id="@+id/nameTv"/>

</RelativeLayout>

</RelativeLayout>

-----------------------------------------

ကိုမ်ိဳး

AIDE Android Lessons And Project Group

မွ ကူးယူတင္ထားပါသည္

#mkk_ListView


Comments