从一个片段保存信息和对话框,如果用户导航到另一片段 [英] Saving information from one fragment and dialog if the user navigates to another fragment

查看:159
本文介绍了从一个片段保存信息和对话框,如果用户导航到另一片段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个屏幕,用户presses一个按钮,弹出一个 DialogFragment 的EditText 。他们输入自己的信息,和preSS 确定。如果他们再preSS的按钮,我做了它,因此的EditText 将显示他们刚刚投入的信息,一切工作正常。

不过,如果他们输入的信息,preSS 确定,然后使用选项菜单去看看另一个屏幕/ 片段,该信息将不会显示在的EditText ,一旦他们再次preSS的按钮。

我如何能保存信息,即使用户从该屏幕一会儿导航离开?我认为这将需要在片段类的newInstance 的方法,然后让主办活动的呼叫的newInstance 而不是构造函数。但我不确定如何实现它。任何帮助AP preciated。谢谢!

SingleFragmentActivity

 公共抽象类SingleFragmentActivity扩展FragmentActivity
{
    受保护的抽象片段createFragment();

    @覆盖
    公共无效的onCreate(包savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.activity_fragment);

        FragmentManager FM = getSupportFragmentManager();
        片段片段= fm.findFragmentById(R.id.fragmentContainer);

        如果(片段== NULL)
        {
            片段= createFragment();
            fm.beginTransaction()
                。新增(R.id.fragmentContainer,片段)
                。承诺();
        }
    }
}
 

从主办活动的相关code,AdviceActivity:

 公共类AdviceActivity扩展SingleFragmentActivity
{
    @覆盖
    受保护的片段createFragment()
    {
        返回新AdviceFragment();
    }
}
 

从托管片段,AdviceFragment相关code:

 私人布尔isTextButtonFirstClick = TRUE;

...

@覆盖
公共查看onCreateView(LayoutInflater吹气,父母的ViewGroup,捆绑savedInstanceState)
{
    mTextButton =(按钮)v.findViewById(R.id.textButton);
    mTextButton.setOnClickListener(新View.OnClickListener()
    {
        公共无效的onClick(视图v)
        {
            如果(isTextButtonFirstClick)
            {
                FragmentManager FM = getActivity()getSupportFragmentManager()。
                InputTextFragment对话框= InputTextFragment.newInstance(,isTextButtonFirstClick);
                dialog.setTargetFragment(AdviceFragment.this,REQUEST_TEXT);
                dialog.show(FM,DIALOG_TEXT);
                isTextButtonFirstClick = FALSE;
            }
            其他
            {
                FragmentManager FM = getActivity()getSupportFragmentManager()。
                InputTextFragment对话框= InputTextFragment.newInstance(mAdvice.getText(),isTextButtonFirstClick);
                dialog.setTargetFragment(AdviceFragment.this,REQUEST_TEXT);
                dialog.show(FM,DIALOG_TEXT);
            }
        }
    });
...
}
 

从DialogFragment InputTextFragment相关code:

 公共静态InputTextFragment的newInstance(字符串文本,布尔isTextButtonFirstClick)
{
    捆绑的args =新包();
    args.putSerializable(EXTRA_TEXTBUTTON_FIRSTCLICK,isTextButtonFirstClick);
    args.putSerializable(EXTRA_TEXT,文本);

    InputTextFragment片段=新InputTextFragment();
    fragment.setArguments(参数);

    返回片段;
}

...

@覆盖
公共对话onCreateDialog(包savedInstanceState)
{
    ...

    布尔isTextButtonFirstClick = getArguments()getBoolean(EXTRA_TEXTBUTTON_FIRSTCLICK)。

    最后的EditText EDITTEXT =(EditText上)v.findViewById(R.id.dialogInputEditText);
    如果(!isTextButtonFirstClick)
    {
        editText.setText(文本);
        editText.setSelection(text.length());
    }

    ...
}
 

XML activity_fragment:

 < RelativeLayout的的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
    机器人:ID =@ + ID / fragmentContainer
    机器人:layout_width =match_parent
    机器人:layout_height =match_parent>

< / RelativeLayout的>
 

解决方案

听起来好像布尔isTextButtonFirstClick只是被错误地设置为false。

么片段的新实例的这将是有意义的在导航期间创建的。

尝试

  • 设置setRetainInstance(真)的咨询片段的onCreate为了保持布尔。

  • 如果R.id.fragmentContainer是XML片段标记,然后将其更改为的LinearLayout或RelativeLayout的(要添加片段在上面反正,我怀疑findFragmentById总是返回null)

  • 更​​改code在你的活动为:

      FragmentManager FM = getSupportFragmentManager();
    片段片段= fm.findFragmentByTag(singleFragment);
    
    如果(片段== NULL)
    {
        片段= createFragment();
    }
    
       fm.beginTransaction()
            .replace(R.id.fragmentContainer,片段,singleFragment)
            。承诺();
     

通常,当编程添加片段,您可以使用标签,而定义的片段时,在XML让Android框架处理生命周期,可以通过ID找到它。

在我看来,如果你是一个在中间的解决方案,努力做到既,如预期这将无法正常工作。

希望这能帮助和遗憾,如果事先有格式问题。答案已经写从电话:-)

编辑:

如果你只是想救简单类型的信息(如布尔),我想指出你的我的旧的答案在这里,人们:<一href="http://stackoverflow.com/questions/19038823/saving-textview-in-a-fragment-when-rotating-screen/19039229#19039229">Saving TextView的一个片段,当旋转屏

您最后的评论发现,你有一些复杂的信息(文字,图片,视频等),要坚持。

使所有Parcelable将是一个巨大的痛苦,所以在这里不用我的第二个建议是:

  1. 添加EventBus到项目 https://github.com/greenrobot/EventBus
  2. 有关的信息,创建一个holder类,如

     公共类AdviceHolder {
        私人布尔isTextButtonFirstClick;
        私人字符串文本;
        私人位图图像;
        ...
    
       // setter和getter方法​​(如果使用eclipse ALT +狗屎+ S'创建setter和干将领域)
    }
     

  3. 现在开始AdviceActivity的时候,你prepare新AdviceHolder

     公共类AdviceActivity扩展SingleFragmentActivity
    {
        @覆盖
        公共无效的onCreate(包savedInstanceState){
            //创建一个新Adv​​iceHolder如果不存在
            AdviceHolder持有人=新AdviceHolder();
            AdviceHolder existingHolder = EventBus.getDefault()getStickyEvent(AdviceHolder.class)。
            如果(existingHolder == NULL){
                 。EventBus.getDefault()postSticky(保持器);
            }
    
            super.onCreate(savedInstanceState);
        }
    
        @覆盖
        受保护的片段createFragment()
        {
            返回新AdviceFragment();
        }
    }
     

这一步将使AdviceHolder对象提供的的任何地方的在code。把它看成是一个全球性的资源库。

这意味着,不管你怎么Activites或片段之间移动,他们都获得AdviceHolder,并可以进行编辑。

因此​​,例如在你AdviceFragment:

 私人AdviceHolder持有人;

...
@覆盖
公共无效的onCreate(包savedInstanceState){
    AdviceHolder架=(AdviceHolder)EventBus.getDefault()getStickyEvent(AdviceHolder.class)。
}

@覆盖
公共查看onCreateView(LayoutInflater吹气,父母的ViewGroup,捆绑savedInstanceState)
{
    //从持有人读isTextButtonFirstClick
    布尔isTextButtonFirstClick = holder.isTextButtonFirstClick();

    mTextButton =(按钮)v.findViewById(R.id.textButton);
    mTextButton.setOnClickListener(新View.OnClickListener()
    {
        公共无效的onClick(视图v)
        {
            如果(isTextButtonFirstClick)
            {
                FragmentManager FM = getActivity()getSupportFragmentManager()。
                InputTextFragment对话框= InputTextFragment.newInstance(,isTextButtonFirstClick);
                dialog.setTargetFragment(AdviceFragment.this,REQUEST_TEXT);
                dialog.show(FM,DIALOG_TEXT);

                //更新isTextButtonFirstClick的持有人
                holder.setTextButtonFirstClick(假);
                。EventBus.getDefault()postStickyEvent(保持器);
            }
            其他
            {
                FragmentManager FM = getActivity()getSupportFragmentManager()。
                InputTextFragment对话框= InputTextFragment.newInstance(mAdvice.getText(),isTextButtonFirstClick);
                dialog.setTargetFragment(AdviceFragment.this,REQUEST_TEXT);
                dialog.show(FM,DIALOG_TEXT);
            }
        }
    });
...
}
 

当你在某个时候完成填充 AdviceHolder (并将其发送到服务器或任何计划),从EventBus删除它,以使建立一个 AdviceActivity 在新的持有者。

  EventBus.getDefault()removeStickyEvent(AdviceHolder.class)。
 

有关EventBus其他例子看看 HTTP:// WWW。 stevenmarkford.com/passing-objects-between-android-activities/

这是所有了很多资料,希望这不是太混乱了。

I have a screen where the user presses a button to bring up a DialogFragment with an EditText. They enter their information, and press Ok. If they press the button again, I've made it so the EditText will display the information they had just put in, and everything works fine.

However, if they enter the information, press Ok, and then use the options menu to go look at another screen/fragment, the information will not be displayed in the EditText once they press the button again.

How can I save the information even if the user navigates away from that screen for a moment? I think it would require a newInstance method in the fragment class, and then have the hosting activity call newInstance instead of the constructor. But I'm unsure of how to implement it. Any help appreciated. Thanks!

SingleFragmentActivity:

public abstract class SingleFragmentActivity extends FragmentActivity
{
    protected abstract Fragment createFragment();

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fragment);

        FragmentManager fm = getSupportFragmentManager();
        Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);

        if (fragment == null)
        {
            fragment = createFragment();
            fm.beginTransaction()
                .add(R.id.fragmentContainer, fragment)
                .commit();
        }
    }
}

Relevant code from hosting activity, AdviceActivity:

public class AdviceActivity extends SingleFragmentActivity
{
    @Override
    protected Fragment createFragment()
    {
        return new AdviceFragment();
    }
}

Relevant code from the hosting fragment, AdviceFragment:

private boolean isTextButtonFirstClick = true;

...

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
{
    mTextButton = (Button) v.findViewById(R.id.textButton);
    mTextButton.setOnClickListener(new View.OnClickListener()
    {
        public void onClick(View v)
        {
            if (isTextButtonFirstClick)
            {
                FragmentManager fm = getActivity().getSupportFragmentManager();
                InputTextFragment dialog = InputTextFragment.newInstance("", isTextButtonFirstClick);
                dialog.setTargetFragment(AdviceFragment.this, REQUEST_TEXT);
                dialog.show(fm, DIALOG_TEXT);
                isTextButtonFirstClick = false;
            }
            else
            {
                FragmentManager fm = getActivity().getSupportFragmentManager();
                InputTextFragment dialog = InputTextFragment.newInstance(mAdvice.getText(), isTextButtonFirstClick);
                dialog.setTargetFragment(AdviceFragment.this, REQUEST_TEXT);
                dialog.show(fm, DIALOG_TEXT);
            }
        }
    });
...
}

Relevant code from DialogFragment InputTextFragment:

public static InputTextFragment newInstance(String text, boolean isTextButtonFirstClick)
{
    Bundle args = new Bundle();
    args.putSerializable(EXTRA_TEXTBUTTON_FIRSTCLICK, isTextButtonFirstClick);
    args.putSerializable(EXTRA_TEXT, text);

    InputTextFragment fragment = new InputTextFragment();
    fragment.setArguments(args);

    return fragment;
}

...

@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
    ...

    boolean isTextButtonFirstClick = getArguments().getBoolean(EXTRA_TEXTBUTTON_FIRSTCLICK);

    final EditText editText = (EditText) v.findViewById(R.id.dialogInputEditText);
    if (!isTextButtonFirstClick)
    {
        editText.setText(text);
        editText.setSelection(text.length());
    }

    ...
}

XML activity_fragment:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragmentContainer"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</RelativeLayout>

解决方案

It sounds as if the boolean isTextButtonFirstClick simply is mistakenly set to false.

This would make sense of a new instance of Advice Fragment is created during the navigation.

Try

  • Setting setRetainInstance(true) in onCreate of Advice Fragment in order to keep the boolean.

  • If R.id.fragmentContainer is a fragment tag in XML, then change it to a LinearLayout or RelativeLayout (you are adding a fragment on top anyways, and I suspect the findFragmentById to always return null)

  • Change the code in your Activity to:

    FragmentManager fm = getSupportFragmentManager();
    Fragment fragment = fm.findFragmentByTag("singleFragment");
    
    if (fragment == null)
    {
        fragment = createFragment();
    }
    
       fm.beginTransaction()
            .replace(R.id.fragmentContainer, fragment,  "singleFragment" )
            .commit();
    

Generally when programmatically adding fragments, you use tags, whereas when defining the fragment in XML letting the Android framework handle the lifecycle, you can find it by id.

Looks to me as if you are in a in-between solution, trying to do both, which will not work as intended.

Hope this can help and sorry in advance if there are formatting issues. The answer has been written from a phone :-)

Edit:

If you only wanted to save simple types of info (such as the boolean), I would point you to one of my old answers here: Saving textview in a fragment when rotating screen

Your last comment revealed that you have some complex information (text, photos, videos etc) that you want to persist.

Making all that Parcelable will be a huge pain, so here goes my second advice:

  1. Add EventBus to your project https://github.com/greenrobot/EventBus
  2. Create a holder class for the information, such as

    public class AdviceHolder {
        private boolean isTextButtonFirstClick;
        private String text;
        private BitMap image;
        ... 
    
       // setter and getter methods (if using eclipse alt+shit+s 'create setter and getters from fields') 
    }
    

  3. Now when starting AdviceActivity, you prepare a new AdviceHolder

    public class AdviceActivity extends SingleFragmentActivity
    {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            // make a new AdviceHolder if none existed
            AdviceHolder holder = new AdviceHolder();
            AdviceHolder existingHolder = EventBus.getDefault().getStickyEvent(AdviceHolder.class);
            if (existingHolder == null) {        
                 EventBus.getDefault().postSticky(holder);
            }
    
            super.onCreate(savedInstanceState);
        }
    
        @Override
        protected Fragment createFragment()
        {
            return new AdviceFragment();
        }
    }
    

This step will make a AdviceHolder object available anywhere in your code. Think of it as a global repository.

This means that no matter how you move between Activites or Fragments, they all have access to AdviceHolder and can edit it.

So for example in you AdviceFragment:

private AdviceHolder holder;

...
@Override
public void onCreate (Bundle savedInstanceState) {
    AdviceHolder holder = (AdviceHolder)EventBus.getDefault().getStickyEvent(AdviceHolder.class);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState)
{
    // read isTextButtonFirstClick from holder
    boolean isTextButtonFirstClick = holder.isTextButtonFirstClick();

    mTextButton = (Button) v.findViewById(R.id.textButton);
    mTextButton.setOnClickListener(new View.OnClickListener()
    {
        public void onClick(View v)
        {
            if (isTextButtonFirstClick)
            {
                FragmentManager fm = getActivity().getSupportFragmentManager();
                InputTextFragment dialog = InputTextFragment.newInstance("", isTextButtonFirstClick);
                dialog.setTargetFragment(AdviceFragment.this, REQUEST_TEXT);
                dialog.show(fm, DIALOG_TEXT);

                // update isTextButtonFirstClick in holder
                holder.setTextButtonFirstClick(false);
                EventBus.getDefault().postStickyEvent(holder);
            }
            else
            {
                FragmentManager fm = getActivity().getSupportFragmentManager();
                InputTextFragment dialog = InputTextFragment.newInstance(mAdvice.getText(), isTextButtonFirstClick);
                dialog.setTargetFragment(AdviceFragment.this, REQUEST_TEXT);
                dialog.show(fm, DIALOG_TEXT);
            }
        }
    });
...
}

When you at some point are done filling the AdviceHolder (and sent it to a server or whatever the plan is), remove it from EventBus to enable the creation of a new holder in AdviceActivity.

EventBus.getDefault().removeStickyEvent(AdviceHolder.class);

For other examples about EventBus have a look at http://www.stevenmarkford.com/passing-objects-between-android-activities/

This is all a lot of information, hope it is not too confusing.

这篇关于从一个片段保存信息和对话框,如果用户导航到另一片段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆