您的位置:首页 > 移动开发 > Android开发

Android Fragment、Activity、Dialog 各种组件直接数据共享,更新通知

2015-09-07 17:14 796 查看
     我要放大招了,纠结了两个礼拜的一个问题,让师傅几分钟写了一堆代码轻松就搞定了,再次非常感谢阿博师傅,之前两个月的代码很多都是他帮了很大的忙,我就是一个总结,总想着这些问题,在百度了一大圈都没有很好的解决方案之后,我解决了,就想分享给和我遇到同样的问题的同行业的,不管你是大牛还是菜鸟,都可以提出建议,我所有的解决方案都是基于解决实际问题而出发的,所以很多时候没有考虑扩展性或者复用性、效率这些问题,欢迎提出建议,共同进步。

         有点扯远了,回到正题好了,详细描述如下:相信很多人都会使用下拉列表、对话框、弹出框、自定义对话框、等等其他的时间控件之类的组件,有时候会有这样的需求:   下拉列表选中的数据或者自定义的组件选中的数据,要返回到原来的界面(也就是你点击了某一个按钮或者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 来开发界面的同学,对于数据共享和通知更新有一个新的解决方案,共同进步。

     欢迎有同样的问题,咨询。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息