大家好。。以前我也好奇过有没有一些设计模式可以用来创建一个细节页面,直到最近我看了一些设计模式相关的博文和书后,我终于发现了以下的应用。
下面我们介绍一个Listview 点击后出现一个detail 页面的功能,功能简单,但是我们看的是思想。
首先我们实现自定义的ListView,ListItem 里面有一个TextView,一个EditText,一个Checkbox,对应存放数据的是一个Crime的类.ListView里面有好多个ListItem,而对应的是CrimeList 类,为了方便创建大量的Crime对象,我们用了工厂模式去实现这个CrimeList,而这个工厂是一个程序有且仅有一个的,对于工厂类的实现我们用了Singleton模式。
工厂实现的代码
public class CrimeLab { private ArrayList<Crime> mCrimes; private static CrimeLab sCrimeLab; private Context mAPPContext; private CrimeLab(Context appContext) { mAPPContext=appContext; mCrimes=new ArrayList<Crime>(); for(int i=0;i<100;i++) { Crime c=new Crime(); c.setTitle("Crime #"+i); c.setSolved(i%2==0); mCrimes.add(c); } } public ArrayList<Crime> getmCrimes() { return mCrimes; } public Crime getCrime(UUID id) { for(Crime c: mCrimes) { if(c.getId().equals(id)) return c; } return null; } public static CrimeLab get(Context c) { if(sCrimeLab==null) { sCrimeLab=new CrimeLab(c.getApplicationContext()); } return sCrimeLab; } }
那么我们怎么把这个Crime类里面的数据,传送给ListView呢,这里我们需要一个Adapter来连通Listview和我们的数据mCrimes,根据我们的需要,我们可以实现ArrayAdapter 子类并复写其中的getView方法,getView方法会被调用当这个ListView 有新的ListItem进么我们看到的界面的时候,当我们的CrimeAdapter 是专属于CrimeListFragment 的时候,我们可以让这个CrimeAdapter作为CrimeListFragment的成员类来写,那么我们在CrimeAdapter 只要传必要的数据mCrimes给它作为参数就可以了。
private class CrimeAdapter extends ArrayAdapter<Crime> { public CrimeAdapter(ArrayList<Crime> crimes) { super(getActivity(),0,crimes); } @Override public View getView(int position, View convertView, ViewGroup parent) { if(convertView==null) { convertView = getActivity().getLayoutInflater().inflate(R.layout.crime_item,null); } Crime c = getItem(position); TextView titleView=(TextView)convertView.findViewById(R.id.crime_title); titleView.setText(c.getTitle()); TextView dateView=(TextView)convertView.findViewById(R.id.crime_date); dateView.setText(c.getmDate().toString()); CheckBox solveBox=(CheckBox)convertView.findViewById(R.id.isResolved); solveBox.setChecked(c.getSolved()); return convertView; } }
同时我们要实现这个adatper的onlistItemClick方法,让activity跳转,但activity跳转的时候要通过putExtra在Intent 里面传递数据。Activity 与Activity之间通过Intent传递数据是无可厚非的,但是我们用的是Activity里装一个Fragment 这样的结构,到了Fragment 那里我们要怎么拿到Extra里面的数据呢。你会想到要用getActivity,没错在fragment 里面用getActivity的确可以用到activity 用的数据,但是这样会造成很强的耦合,我们的fragment 只能用于有相应Extra的Intent的Activity了,为了解开耦合,更好的方法是我们把数据放在自己的bundle里面,每个fragment 都有一个默认的bundle就是argument,有相应的方法设置和获取。先看一下Crimefragment 里面的代码。
public static CrimeFragment newInstance(UUID crimeId) { Bundle args = new Bundle(); args.putSerializable(EXTRA_CRIME_ID,crimeId);; CrimeFragment fragment = new CrimeFragment(); fragment.setArguments(args); return fragment; }
如果我们要返回一个对象且要对对象作特别操作,我们一般用newInstance方法名。在CrimeFragment 里面有了这个方法以后,我们每次只需要在Activity之间用Intent传递数据,而要在Activity里加入Fragment的新实例的时候,我们就可以用这个方法了。注意我们每次信息传递,无论是activity到activity,还是到Fragment, 我们都只传递UUID,这让我又想到了MVC 这个模式,module 是由CrimeList 去控制;controller就是各个acivity,fragment,Intent;view是控件和布局。只要我们controller有唯一的标识,到了哪里都可以跟module 沟通了。不知道这种模式是不是最好的,有更好的请告诉我