Closed. This question needs details or clarity。它当前不接受答案。
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            想改善这个问题吗?添加详细信息并通过editing this post阐明问题。
                        
                        去年关闭。
                                                                                            
                
        
因此,在学习android的基础知识时,这个词Fragment出现在许多地方,例如Navigation DrawersViewPagerPreferencesActivity,创建动态视图等。所以我开始阅读它,发现这是Android平台的一个非常重要的部分。它通过允许应用程序更好地在不同大小的屏幕上分布数据来增强用户体验。

例如,像Gmail这样的应用程序将在小型屏幕设备上跨多个“页面”显示其数据(请查看下面的图片以获得更好的主意),并在平板电脑等较大的设备上将所有数据显示在一个页面中。


  

因此,通常会出现的问题是“这是如何分割的?”以及“它如何管理其神奇的点击,当在小屏幕设备中时,它会完全改变布局,而在大屏幕设备中时,只需改变其数据?”好吧,当我们考虑活动布局方面时,这是一个相当困难的问题。

因此,经过更多的搜索和阅读,我能够成功地学习更多有关片段背后的理论,其生命周期和静态片段(Fragment Documentation)的知识。

我现在希望实现一些现实生活中的片段应用程序,例如gmail,其中包含adding fragments programmically 的概念。因此,我设计了一个小任务,可以帮助我学习动态片段和片段-片段/片段-活动通信的概念。

任务:


将有一个基本应用程序,其中1个MainActivityLinearLayout作为其根viewGroup。
2个片段:FragmentA(或Frag 1或Pink背景片段)和FragmentB(或frag2 / BlueFragment)将在第一次运行时添加到MainActivity中。
两个片段在其余时间内都应该能够操纵另一个片段的可见性,因此每个片段将具有2个按钮open Other fragmentClose other fragment
单击片段2中的open frag1时,应将片段1添加到屏幕上,或者不执行任何操作(如果已存在)。同样,如果fragment1已经存在或不执行任何操作,则在片段2中按close frag1应该可以删除片段1。


目标图像样本:


活动显示2个片段,粉红色片段和蓝色片段(忽略大小,正在测试linearlayout#weight):
  
相同的活动现在仅显示fragment1,因为用户在close fragment 2中按下了pink fragment。因此布局会动态更改:
  


(第二个片段也可以使用相同的内容)

成就:这样做之后,我能够更好地了解片段间通信,而且我想我现在知道Gmail中的那些“神奇的点击”如何在完全不同的片段中更改数据/布局。

我认为在这里提出所有可能的失败尝试是不明智的,因此,我只提及在解决此任务时遇到的其他一些问题:

问题:
1.片段无法相互通信(片段1中按下的按钮无法关闭片段2)
2.片段在旋转时会多次重新添加到屏幕上。
3.保存显示内容:启动App时,默认显示片段1。在会话期间,根据用户的输入,此布局可以更改为显示2个片段或仅显示片段“ 2”。但是,如果用户旋转手机,则不会保存屏幕上存在的内容,并且活动开始显示片段1。

最佳答案

步骤0:创建一个片段,其他文件
创建fragment.xml,fragment.java扩展片段并在onCreateView()中扩大布局。(对于两个片段)

public class Frag_b extends Fragment {

    public Frag_b() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_frag_b, container, false);
    }

}


步骤(1)动态片段:
众所周知,当应用启动时,androidOS首先调用该活动以显示(具有"android.intent.action.MAIN"权限的活动)。因此,要在运行时显示片段,我们使用一个名为FragmentManager()的类(有关其功能here的更多信息。
1-在主要活动中创建片段和片段管理器的全局对象。
2-创建全局片段标签:它们对于相同片段对象的可恢复性非常重要,它们将用作访问/识别字符串的标签。
3-通过片段管理器添加:因此出现了片段管理器的第一个用例:动态(在运行时)添加片段。这是它的代码:

public class MainActivity extends AppCompatActivity implements FragAHandler,FragBHandler {
    LinearLayout layRoot;

    FragmentManager manager=getSupportFragmentManager();

    public static  final String FRAG_A_TAG="FRAG_A";
    public static  final String FRAG_B_TAG="FRAG_B";


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        layRoot=findViewById(R.id.layout_root);
        manager.beginTransaction().add(R.id.layout_root,new Frag_a(),FRAG_A_TAG).commit();
        manager.beginTransaction().add(R.id.layout_root,new Frag_b(),FRAG_B_TAG).commit();

    }

}


步骤2片段通讯:
here所示,片段通信是一个4层过程:
 *接口定义功能(片段要执行的任务)。
 *该活动将实现它们。
 *该片段获取此接口的一个实例(以活动上下文的形式)。
 * Fragment根据需要使用此实例。
{如果是片段片段通信,则会向其添加2个小步骤}:
 *片段向活动发送信号。
 *活动然后处理信号并将其发送到其他片段。

因此,如果片段FragA希望主活动在按钮单击时显示通知(出现在片段内):


创建一个具有函数void showNotif()的接口FragAcall。
在MainActivity中实现它(并定义希望您的活动在收到来自片段A的点击时执行的任何操作,即显示通知)。
在fragA中,创建接口FragAcall(FragAcall callObj)的对象。
在fragA中,重写一个名为onAttach(context)的方法。将此上下文广播到FragAcall'Object。
在按钮的点击侦听器内部,调用callObj.showNotiff()。


类似地,对于2段片段通信,我使用以下步骤实现了代码:
 *创建接口FragAHandler和FragBHandler:

public interface FragAHandler {
    void addFrag1();
    void closeFrag1();
    }
public interface FragBHandler {
    void addFrag2();
    void closeFrag2();
    }



在主要活动中实施这些步骤:

public class MainActivity extends AppCompatActivity implements FragAHandler,FragBHandler
{

LinearLayout layRoot;
FragmentManager manager=getSupportFragmentManager();
public static final String FRAG_A_TAG = "FRAG_A";
public static final String FRAG_B_TAG = "FRAG_B";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    layRoot = findViewById(R.id.layout_root);
    manager.beginTransaction().add(R.id.layout_root, new Frag_a(), FRAG_A_TAG).commit();
}

@Override
public void addFrag1() {
    if (manager.findFragmentByTag(FRAG_A_TAG) == null) {
        manager.beginTransaction().add(R.id.layout_root, new Frag_a(), FRAG_A_TAG).commit();
    } else {
        Toast.makeText(MainActivity.this, "frag1 Already present", Toast.LENGTH_SHORT);
    }
}

@Override
public void closeFrag1() {
    Frag_a fragA = (Frag_a) manager.findFragmentByTag(FRAG_A_TAG);
    if (fragA != null) {
        manager.beginTransaction().remove(fragA).commit();
    } else {
        Toast.makeText(MainActivity.this, "frag1 Already not there", Toast.LENGTH_SHORT);
    }

}

@Override
public void addFrag2() {

    if (manager.findFragmentByTag(FRAG_B_TAG) == null) {
        manager.beginTransaction().add(R.id.layout_root, new Frag_b(), FRAG_B_TAG).commit();
    } else {
        Toast.makeText(MainActivity.this, "frag2 Already present", Toast.LENGTH_SHORT);
    }
}

@Override
public void closeFrag2() {
    Frag_b frag_b = (Frag_b) manager.findFragmentByTag(FRAG_B_TAG);

    if (frag_b != null) {
        manager.beginTransaction().remove(frag_b).commit();
    } else {
        Toast.makeText(MainActivity.this, "frag2 Already not there", Toast.LENGTH_SHORT);

    }

}
}



在此代码中,manager.findFragByTag()用于检查天气,一个片段是否已显示,因为我们只想打开另一个片段的一个实例。有关其详细用法,请参见this


在片段内,将mainActivity的类上下文附加到处理程序obj上,并在按钮内使用它:

public class Frag_a extends Fragment {

    FragBHandler fragBHandler;

    public Frag_a() {
        // Required empty public constructor
    }

    @Override
    public void onAttach(Context context) {
        // context is the activity's context.
        super.onAttach(context);

        try {
            // This makes sure that the container activity has implemented
            // the callback interface. If not, it throws an exception
            fragBHandler = (FragBHandler) context;
        } catch (ClassCastException e) {
            e.printStackTrace();
            Log.e("", "onAttach: class has not implemented fragAhandler");
        }
    }
    // THIS SHOULD NEVER BE AN APPROCH.
    // public Frag_a(FragBHandler fragBHandler) {
    // this.fragBHandler = fragBHandler;
    // }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View v = inflater.inflate(R.layout.fragment_frag_a, container, false);
        v.findViewById(R.id.bt_open_frag2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                openFrag2();
            }
        });
        v.findViewById(R.id.bt_close_frag2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                closeFrag2();
            }
        });

        return v;
    }

    public void closeFrag2() {
        fragBHandler.closeFrag2();

    }

    public void openFrag2() {
        fragBHandler.addFrag2();

    }

}



VOILA,两个片段现在都可以说话!
**第3部分:片段复制**
这是最困难的任务之一。到目前为止,我的目标是创建一个包含两个片段进行通信的应用程序。但是,当我旋转手机时,出现了一个重大失败:无论屏幕上显示的内容如何都被创建了多个时代!

我通过执行以下操作找到了解决方案:
 -将一个公用对象用于在onCreate()期间创建的frag1和2,并通过检查是否在后堆栈中已经存在该对象,然后仅使用该对象再次添加。
 -在检查后向堆栈后也添加初始片段。

所以我最后的mainActivity代码变成:

    public class MainActivity extends AppCompatActivity implements FragAHandler, FragBHandler {
        LinearLayout layRoot;
        FragmentManager manager = getSupportFragmentManager();


        Frag_a fragmentObjA;
        Frag_b fragmentObjB;
        public static final String FRAG_A_TAG = "FRAG_A";
        public static final String FRAG_B_TAG = "FRAG_B";


        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            initialise();

            if (manager.findFragmentByTag(FRAG_A_TAG) == null && manager.findFragmentByTag(FRAG_B_TAG) == null) {
                //both are imp because of testcase not giving exact answer:
                // >>>open app: shows frag1>'press open frag2'>>>frg2 opens >'close frag 1' >>> rotate.
                //Expected output >> "fragment 2(already present object in backstack and on screen) to remain on screen
                //output recieved : both frag 1 and frg2 showing
                manager.beginTransaction().add(R.id.layout_root, fragmentObjA, FRAG_A_TAG)
                        .setTransitionStyle(FragmentTransaction.TRANSIT_ENTER_MASK)
                        .commit();
            } else {
                Toast.makeText(MainActivity.this, "frag1 Already present or fragment 2 present", Toast.LENGTH_SHORT).show();
            }

        }

        private void initialise() {
            layRoot = findViewById(R.id.layout_root);

            if(manager.findFragmentByTag(FRAG_A_TAG)!=null){
                fragmentObjA= (Frag_a) manager.findFragmentByTag(FRAG_A_TAG);
                Log.e(">>", "initialise: frgement A object recieved from the frag manager is used" );

            }
            else{
                Log.e(">>", "initialise:new frag a object created" );
                fragmentObjA=new Frag_a();

            }
            if(manager.findFragmentByTag(FRAG_B_TAG)!=null){
                fragmentObjB= (Frag_b) manager.findFragmentByTag(FRAG_B_TAG);

                Log.e(">>", "initialise: frgement B object recieved from the frag manager is used" );
            }
            else{
                Log.e(">>", "initialise:new frag object created" );
                fragmentObjB=new Frag_b();
            }
        }


        //-----------handler methods-------------------
        @Override
        public void addFrag1() {
            if (manager.findFragmentByTag(FRAG_A_TAG) == null) {
                manager.beginTransaction().add(R.id.layout_root, fragmentObjA, FRAG_A_TAG)
                        .setTransitionStyle(FragmentTransaction.TRANSIT_ENTER_MASK)
                        .commit();
            } else {
                Toast.makeText(MainActivity.this, "frag1 Already present", Toast.LENGTH_SHORT).show();
            }
        }

        @Override
        public void closeFrag1() {
            Frag_a fragA = (Frag_a) manager.findFragmentByTag(FRAG_A_TAG);
            if (fragA != null) {
                manager.beginTransaction().remove(fragA)
                        .setTransitionStyle(FragmentTransaction.TRANSIT_EXIT_MASK)
                        .commit();
            } else {
                Toast.makeText(MainActivity.this, "frag1 Already not there", Toast.LENGTH_SHORT).show();

            }

        }

        @Override
        public void addFrag2() {

            if (manager.findFragmentByTag(FRAG_B_TAG) == null) {
                manager.beginTransaction().add(R.id.layout_root, fragmentObjB, FRAG_B_TAG)
                        .setTransitionStyle(FragmentTransaction.TRANSIT_ENTER_MASK)
                        .commit();
            } else {
                Toast.makeText(MainActivity.this, "frag2 Already present", Toast.LENGTH_SHORT).show();
            }


        }

        @Override
        public void closeFrag2() {
            Frag_b frag_b = (Frag_b) manager.findFragmentByTag(FRAG_B_TAG);

            if (frag_b != null) {
                manager.beginTransaction().remove(frag_b)
                        .setTransitionStyle(FragmentTransaction.TRANSIT_EXIT_MASK)
                        .commit();
            } else {
                Toast.makeText(MainActivity.this, "frag2 Already not there", Toast.LENGTH_SHORT).show();

            }

        }

    }

关于java - [示例]动态 fragment , fragment 间通信, fragment 重新添加到屏幕问题( fragment 保留)中,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49662707/

10-09 06:55
查看更多