Android Fragment、Activity、Dialog 各种组件直接数据共享,更新通知
2015-09-07 17:14
796 查看
我要放大招了,纠结了两个礼拜的一个问题,让师傅几分钟写了一堆代码轻松就搞定了,再次非常感谢阿博师傅,之前两个月的代码很多都是他帮了很大的忙,我就是一个总结,总想着这些问题,在百度了一大圈都没有很好的解决方案之后,我解决了,就想分享给和我遇到同样的问题的同行业的,不管你是大牛还是菜鸟,都可以提出建议,我所有的解决方案都是基于解决实际问题而出发的,所以很多时候没有考虑扩展性或者复用性、效率这些问题,欢迎提出建议,共同进步。
有点扯远了,回到正题好了,详细描述如下:相信很多人都会使用下拉列表、对话框、弹出框、自定义对话框、等等其他的时间控件之类的组件,有时候会有这样的需求: 下拉列表选中的数据或者自定义的组件选中的数据,要返回到原来的界面(也就是你点击了某一个按钮或者textview,弹出的自定义的Activity、Fragment等),这些数据需要从对话框等组件返回到主界面,用来完成其他的逻辑,那么有多少方案可以完成这个需求呢?。。。。
以下是针对于DatePicker日期选择组件,选择某一个日期之后,返回用户选择的日期到主界面,进行逻辑处理:
第一种方案是针对普通情况,可以使用一个类,专门保存数据,写好Setter/Getter方法,也算是一种组件的思想。大概的过程很简单:在用户选择某一个时间之后,使用该类的setter方法,设置这个变量的值,然后在主界面需要该变量值的地方使用Getter方法,得到数据,进而进行处理。
第一步:设置一个保存通用变量的类:DocCaptain.java (因为是公司的代码,所以抱歉不能给出完整的代码,只能贴出关键代码)
第三步:弹出日期控件的代码就不贴出来了,百度上有很多前辈已经写好了的。
总结一下,第一种方案,可以应用的范围:如果共享的数据不多,并且不是很多开发人员使用(因为会有并发操作的可能)。还有应用场景是:当从日期控件选择确定之后,可以通过Intent,将取到的数据传递给需要的主界面。我相信很多都能明白,也非常容易实现。应用范围很小,是有很多弊端性,但是避免了很多没必要的代码,更易于管理。不需要使用android sharedpreferences,以及数据库sqlite,在每个界面获取共享的数据,简化了代码。
还有一个最重要的弊端是,在以下应用场景下,上述的方案无法完成想要的需求,具体描述如下:
就是我的这个手机项目,看过之前我之前的博客的人都知道,我用的是下拉菜单,切换fragment,也就是通过替换主界面的Textview来实现,切换不同的fragment,利用fragmentmanager来管理,隐藏和显示。
实际的场景是这样的:有一个下拉spinner,有一个数组让用户选择的是有效期限,有一个特殊的选项是:自定义时间,需要点击下拉列表的:“自定义时间”这个列表项,点击之后跳转到 日期控件的界面,这时候用户选择了一个合适的时间,点击设置之后,日期对话框消失了,这时候,需要将用户选择的时间返回到该 Fragment,一个很棘手的问题来了: 对话框消失之后,如何能监听,并且拿到该数据?使用第一种方案,无法触发这个事件,返回之后无法执行设置下列spinner显示的内容,这样就出现了第二种终极方案:
第二种方案: 使用通用事件监听,当一个事件发生之后,通知给已经注册的类,拿到所需要的信息,并自己进行处理
我稍微加一点自己的理解:举个例子,当老师在黑板上写了一行数字,坐在下面的A 、B、C三个同学接收到老师看黑板的指令之后,就记下了这串数字,A拿到这串数字就写在本子上了,B看到这串数字,没什么感觉,C则在原来的基础上加了几个字。过了几分钟,老师重新擦掉了原来的一串数字,写了一首诗,老师提醒各位同学,黑板上内容已经变了,各位同学注意了,重新摘抄一遍。大概的流程就是这样:首先所有同学必须是这个班上的,所以需要先向老师报道(也就是注册,否则我怎么知道教哪些学生),老师发布内容,告诉同学们黑板上有新的内容(也就是通知每个同学这个事件已经发生了,想要的可以拿去处理)。
第一步:写一个通用的事件监听处理的方法,总共有4个类:
(A) IStationEventName.java
(C)StationEventData.java
(D)StationEventListener.java
至此就结束了,对于上述的代码不完整做一个解释,因为是公司的代码,不能贴出全部的代码,但核心代码已经贴出来了,讲的很模糊,有大牛的话可以指出错误。希望对同样 使用fragment 来开发界面的同学,对于数据共享和通知更新有一个新的解决方案,共同进步。
欢迎有同样的问题,咨询。
有点扯远了,回到正题好了,详细描述如下:相信很多人都会使用下拉列表、对话框、弹出框、自定义对话框、等等其他的时间控件之类的组件,有时候会有这样的需求: 下拉列表选中的数据或者自定义的组件选中的数据,要返回到原来的界面(也就是你点击了某一个按钮或者textview,弹出的自定义的Activity、Fragment等),这些数据需要从对话框等组件返回到主界面,用来完成其他的逻辑,那么有多少方案可以完成这个需求呢?。。。。
以下是针对于DatePicker日期选择组件,选择某一个日期之后,返回用户选择的日期到主界面,进行逻辑处理:
第一种方案是针对普通情况,可以使用一个类,专门保存数据,写好Setter/Getter方法,也算是一种组件的思想。大概的过程很简单:在用户选择某一个时间之后,使用该类的setter方法,设置这个变量的值,然后在主界面需要该变量值的地方使用Getter方法,得到数据,进而进行处理。
第一步:设置一个保存通用变量的类:DocCaptain.java (因为是公司的代码,所以抱歉不能给出完整的代码,只能贴出关键代码)
package client.verbank.mtp.allone.doc; import jedi.verbank.CSTS3.comm.struct.AccountBasic; public class DocCaptain { private static DocCaptain instance; //这个是日期控件用户选中的具体日期,可以放在里面,随时拿出来用 private String addPriceTime; public String getAddPriceTime() { return addPriceTime; } public void setAddPriceTime(String addPriceTime) { this.addPriceTime = addPriceTime; } }第二步,在使用的类中,这样使用:
package client.verbank.mtp.allone.frame.price.tipsprice.addtipsprice; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.List; public class AddTipsPriceFragment extends<span style="color:#ff0000;"><strong> Fragment</strong></span> { String timeAddPrice; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View vi = inflater.inflate(R.layout.activity_tipsprice_addtipsprice, container, false); if (flag == 0) { List<Instrument> list = APIDoc.getSystemDocCaptain() .getInstrumentList(); instrument = list.get(0).getInstrument(); DocCaptain.getInstance().setTipspriceInstrument(instrument); flag = 1; } else { instrument = DocCaptain.getInstance().getTipspriceInstrument(); timeAddPrice = DocCaptain.getInstance().getAddPriceTime();
timeView = (TextView) arg1; String initDateTime = "2015-9-7 12:22"; DateTimePickDialogUtil dateTimePicKDialog = new DateTimePickDialogUtil( getActivity(), initDateTime); dateTimePicKDialog.dateTimePicKDialog(); } } }
第三步:弹出日期控件的代码就不贴出来了,百度上有很多前辈已经写好了的。
总结一下,第一种方案,可以应用的范围:如果共享的数据不多,并且不是很多开发人员使用(因为会有并发操作的可能)。还有应用场景是:当从日期控件选择确定之后,可以通过Intent,将取到的数据传递给需要的主界面。我相信很多都能明白,也非常容易实现。应用范围很小,是有很多弊端性,但是避免了很多没必要的代码,更易于管理。不需要使用android sharedpreferences,以及数据库sqlite,在每个界面获取共享的数据,简化了代码。
还有一个最重要的弊端是,在以下应用场景下,上述的方案无法完成想要的需求,具体描述如下:
就是我的这个手机项目,看过之前我之前的博客的人都知道,我用的是下拉菜单,切换fragment,也就是通过替换主界面的Textview来实现,切换不同的fragment,利用fragmentmanager来管理,隐藏和显示。
实际的场景是这样的:有一个下拉spinner,有一个数组让用户选择的是有效期限,有一个特殊的选项是:自定义时间,需要点击下拉列表的:“自定义时间”这个列表项,点击之后跳转到 日期控件的界面,这时候用户选择了一个合适的时间,点击设置之后,日期对话框消失了,这时候,需要将用户选择的时间返回到该 Fragment,一个很棘手的问题来了: 对话框消失之后,如何能监听,并且拿到该数据?使用第一种方案,无法触发这个事件,返回之后无法执行设置下列spinner显示的内容,这样就出现了第二种终极方案:
第二种方案: 使用通用事件监听,当一个事件发生之后,通知给已经注册的类,拿到所需要的信息,并自己进行处理
我稍微加一点自己的理解:举个例子,当老师在黑板上写了一行数字,坐在下面的A 、B、C三个同学接收到老师看黑板的指令之后,就记下了这串数字,A拿到这串数字就写在本子上了,B看到这串数字,没什么感觉,C则在原来的基础上加了几个字。过了几分钟,老师重新擦掉了原来的一串数字,写了一首诗,老师提醒各位同学,黑板上内容已经变了,各位同学注意了,重新摘抄一遍。大概的流程就是这样:首先所有同学必须是这个班上的,所以需要先向老师报道(也就是注册,否则我怎么知道教哪些学生),老师发布内容,告诉同学们黑板上有新的内容(也就是通知每个同学这个事件已经发生了,想要的可以拿去处理)。
第一步:写一个通用的事件监听处理的方法,总共有4个类:
(A) IStationEventName.java
package client.verbank.mtp.allone.event; public interface IStationEventName { String EVENT_NAME_TIME_CHANGE = "EVENT_NAME_TIME_CHANGE"; }(B)StationEventCaptain.java
package client.verbank.mtp.allone.event; import java.util.ArrayList; import java.util.EventListener; import java.util.HashMap; import java.util.List; public class StationEventCaptain { private static StationEventCaptain instance; private HashMap<String, List<EventListener>> eventMap = new HashMap<String, List<EventListener>>(); public static StationEventCaptain getInstance() { if (instance == null) { instance = new StationEventCaptain(); } return instance; } public void fireEventDataChange(String eventName) { fireEventDataChange(new StationEventData(eventName)); } public void fireEventDataChange(StationEventData eventData) { synchronized (eventMap) { if (eventMap.containsKey(eventData.getEventName())) { List<EventListener> eventList = eventMap.get(eventData .getEventName()); for (EventListener eventListener : eventList) { StationEventListener stationEventListener = (StationEventListener) eventListener; stationEventListener.onDataEvent(eventData); } } } } public void addEventDataChangeListener(StationEventListener listener, String eventName) { synchronized (eventMap) { if (eventMap.containsKey(eventName)) { List<EventListener> eventList = eventMap.get(eventName); eventList.add(listener); } else { List<EventListener> eventListenerList = new ArrayList<EventListener>(); eventListenerList.add(listener); eventMap.put(eventName, eventListenerList); } } } public void removeEventDataChangeListener(StationEventListener listener, String eventName) { synchronized (eventMap) { if (eventMap.containsKey(eventName)) { List<EventListener> eventList = eventMap.get(eventName); eventList.remove(listener); } } } }
(C)StationEventData.java
package client.verbank.mtp.allone.event; public class StationEventData { private String eventName; private Object data; public StationEventData() { super(); } public StationEventData(String eventName) { super(); this.eventName = eventName; } public StationEventData(Object data) { super(); this.data = data; } public StationEventData(String eventName, Object data) { super(); this.eventName = eventName; this.data = data; } public String getEventName() { return eventName; } public void setEventName(String eventName) { this.eventName = eventName; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } }
(D)StationEventListener.java
package client.verbank.mtp.allone.event; import java.util.EventListener; public interface StationEventListener extends EventListener { public void onDataEvent(StationEventData data); }上述的代码完全可以复用的,可以直接复制黏贴到你的工程代码里面,相当于一个UTIL工具类。接下来就得使用了,首先在fragment里面注册一个事件,告诉他我是你的同学,等老师写了字的时候告诉我,并且重写接口里面的消息方法,我拿到这串数字,我要自己处理,别人管不着。代码片段如下:
package client.verbank.mtp.allone.frame.price.tipsprice.addtipsprice; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.List; //价格提示 public class AddTipsPriceFragment extends ControlFragment implements StationEventListener { 。。。。。。。。。。 private String instrument;
//注册监听事件 public AddTipsPriceFragment(MainActivity activity) { super(activity); StationEventCaptain.getInstance().addEventDataChangeListener(this, IStationEventName.EVENT_NAME_TIME_CHANGE); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View vi = inflater.inflate(R.layout.activity_tipsprice_addtipsprice, container, false); if (flag == 0) { List<Instrument> list = APIDoc.getSystemDocCaptain() .getInstrumentList(); instrument = list.get(0).getInstrument(); DocCaptain.getInstance().setTipspriceInstrument(instrument); flag = 1; } else { instrument = DocCaptain.getInstance().getTipspriceInstrument(); timeAddPrice = DocCaptain.getInstance().getAddPriceTime(); } initComponent(vi); setEffectDataForSpinner(vi); refreshUI(); return vi; } 。。。。。。。。。。。 // 使用数组形式操作 class effectivedateSpinnerSelectedListener implements OnItemSelectedListener { @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { switch (arg2) { case 9: /* * 跳转到日期控件选择界面 */ timeView = (TextView) arg1; String initDateTime = "2015-9-7 12:22"; DateTimePickDialogUtil dateTimePicKDialog = new DateTimePickDialogUtil( getActivity(), initDateTime); dateTimePicKDialog.dateTimePicKDialog(); break; default: break; } // Toast tst = Toast.makeText(getView().getContext(), "您点击了" + // m[arg2] // + "第" + arg2 + "项", Toast.LENGTH_SHORT); // tst.show(); } 。。。。。。。。。。。。。。。 } 。。。。。。。。。 // 当界面隐藏之后重新show,监听 @Override public void onHiddenChanged(boolean hidd) { if (hidd) { } else { if (tipsprice_inst != null) { tipsprice_inst.setText(DocCaptain.getInstance() .getTipspriceInstrument()); } instrument = DocCaptain.getInstance().getTipspriceInstrument(); timeAddPrice = DocCaptain.getInstance().getAddPriceTime(); } } 。。。。。。。。。。。 @Override public int getFramentKey() { return IBundleCommData.FRAGMENT_ID_ADDTIPSPRICE; } 。。。。。。。。。。。。。
//自己对消息自行处理的方法 @Override public void onDataEvent(final StationEventData data) { System.out.println(data.getData() + " =============================="); if (timeView != null) { Runnable work = new Runnable() { @Override public void run() { timeView.setText(data.getData().toString() + ":00"); } }; getHandler().post(work); } }</strong></span> }
至此就结束了,对于上述的代码不完整做一个解释,因为是公司的代码,不能贴出全部的代码,但核心代码已经贴出来了,讲的很模糊,有大牛的话可以指出错误。希望对同样 使用fragment 来开发界面的同学,对于数据共享和通知更新有一个新的解决方案,共同进步。
欢迎有同样的问题,咨询。
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories