首页 > 其他分享 >Fragment初学8——Fragment在Android开发中的应用2

Fragment初学8——Fragment在Android开发中的应用2

时间:2023-09-21 10:06:49浏览次数:48  
标签:transaction Fragment fragment 初学 Activity Override Android public


Fragment都是依附于Activity的,通信方式大致也分为如下几种:

  1. 如果Activity中包含自己管理的Fragment的引用,可以通过直接引用访问所有的Fragment的public方法
  2.  如果Activity中未保存任何Fragment的引用,那么可以通过 getFragmentManager.findFragmentByTag()或者findFragmentById()获得任何Fragment实 例,然后进行操作。
  3. 在Fragment中可以通过getActivity得到当前绑定的Activity的实例,然后进行操作。

注意:如果在Fragment中需要Context,可以通过调用getActivity(),如果该Context需要在Activity被销毁后还存在,则使用getActivity().getApplicationContext()。

因为要考虑Fragment的重复使用,所以必须降低Fragment与Activity的耦合,而且Fragment更不应该直接操作别的Fragment,毕竟Fragment操作应该由它的管理者Activity来决定。

下面通过两种方式分别重构FragmentOne和FragmentTwo的点击事件,以及Activity对点击事件的响应:


FragmentOne.java如下


public class FragmentOne extends Fragment {
 
    private Button mButton;
 

 
    /**
 
     * 设置按钮点击的回调接口
 
     * 
 
     */
 
    public interface BtnOneClickListener {
 
        void onBtnOneClick();
 
    }
 

 
    @Override
 
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
 
            Bundle savedInstanceState) {
 
        // return inflater.inflate(R.layout.fragment_one, container, false);
 
        View view = inflater.inflate(R.layout.fragment_one, container, false);
 
        mButton = (Button) view.findViewById(R.id.btn_fragment_one);
 
        mButton.setOnClickListener(new OnClickListener() {
 
            // 由所属的Activity处理
 
            @Override
 
            public void onClick(View v) {
 
                if (getActivity() instanceof BtnOneClickListener) {
 
                    ((BtnOneClickListener) getActivity()).onBtnOneClick();
 
                }
 
            }
 
        });
 
        return view;
 
    }
 
}


现在FragmentOne不和任何Activity耦合,任何Activity都可以使用;同时声明了一个接口回调其点击事件,想要管理其点击事件的Activity实现此接口就即可。可以看到我们在onClick中首先判断了当前绑定的Activity是否实现了该接口,如果实现了则调用。




FragmentTwo.java类如下


public class FragmentTwo extends Fragment {
 
 

 
 
    private Button mButton;
 
 
    private BtnTwoClickListener mBtnTwoClickListener;
 
 

 
 
    public interface BtnTwoClickListener {
 
 
        void onBtnTwoClick();
 
 
    }
 
 
      //设置回调接口  
 
 
    public void setBtnTwoClickListener(BtnTwoClickListener btnTwoClickListener)  
 
 
    {  
 
 
        this.mBtnTwoClickListener = btnTwoClickListener;  
 
 
    } 
 
 
    @Override
 
 
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
 
 
            Bundle savedInstanceState) {
 
 
        // return inflater.inflate(R.layout.fragment_one, container, false);
 
 
        View view = inflater.inflate(R.layout.fragment_two, container, false);
 
 
        mButton = (Button) view.findViewById(R.id.btn_fragment_two);
 
 
        mButton.setOnClickListener(new OnClickListener() {
 
 

 
 
            @Override
 
 
            public void onClick(View v) {
 
 
                 if(mBtnTwoClickListener != null)  
 
 
                    {  
 
 
                     mBtnTwoClickListener.onBtnTwoClick();  
 
 
                    }  
 
 
            }
 
 
        });
 
 
        return view;
 
 
    }
 
 
}

代码大致和FragmentOne结构相同,与FragmentOne不同的是我们提供了setListener这样的方法,意味着Activity不仅需要实现该接口,还必须显示调用mButton.setBtnTwoClickListener(this)。




MainActivity类如下

public class MainActivity extends Activity implements BtnOneClickListener,BtnTwoClickListener{
 
 

 
 
    private FragmentOne mFragmentOne;  
 
 
    private FragmentTwo mFragmentTwo;  
 
 
    private FragmentThree mFragmentThree; 
 
 
    @Override
 
 
    protected void onCreate(Bundle savedInstanceState) {
 
 
        super.onCreate(savedInstanceState);
 
 
        requestWindowFeature(Window.FEATURE_NO_TITLE);
 
 
        // getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
 
 
        // WindowManager.LayoutParams.FLAG_FULLSCREEN);
 
 
        setContentView(R.layout.activity_main);
 
 
        mFragmentOne=new FragmentOne();
 
 
        FragmentManager fragmentManager = getFragmentManager();
 
 
        FragmentTransaction transaction = fragmentManager.beginTransaction();
 
 
        transaction.add(R.id.framelayout_fragment_main, mFragmentOne, "ONE");
 
 
        transaction.commit();
 
 
    }
 
 

 
 
    @Override
 
 
    public void onBtnOneClick() {
 
 
        if (mFragmentTwo == null)  
 
 
        {  
 
 
            mFragmentTwo = new FragmentTwo();  
 
 
            mFragmentTwo.setBtnTwoClickListener(this);  
 
 
        }  
 
 
        FragmentManager fragmentManager = getFragmentManager();  
 
 
        FragmentTransaction transaction = fragmentManager.beginTransaction();  
 
 
        transaction.replace(R.id.framelayout_fragment_main, mFragmentTwo, "TWO");  
 
 
        transaction.addToBackStack(null);  
 
 
        transaction.commit(); 
 
 
    }
 
 
    @Override
 
 
    public void onBtnTwoClick() {
 
 
        if (mFragmentThree == null)  
 
 
        {  
 
 
            mFragmentThree = new FragmentThree();  
 
 

 
 
        }  
 
 
        FragmentManager fm = getFragmentManager();  
 
 
        FragmentTransaction transaction = fm.beginTransaction();  
 
 
        transaction.hide(mFragmentTwo);  
 
 
        transaction.add(R.id.framelayout_fragment_main, mFragmentThree, "THREE");  
 
 
        transaction.addToBackStack(null);  
 
 
        transaction.commit(); 
 
 
    }
 
 
}

通过重构,项目效果和上一节的效果是一样的,这两种通信方式都是值得推荐的,我建议还是选择第二种。虽然Fragment和Activity可以通过getActivity与 findFragmentByTag或者findFragmentById进行任何操作,甚至在Fragment里面操作另外的Fragment,但是除非万不得已还是别用。Activity担任的是Fragment间类似总线一样的角色,应当由它决定Fragment的操作。另外Fragment不能响应Intent,但是Activity可以,Activity可以接收Intent,然后根据参数判断显示哪个 Fragment。


可说了这么多,我们有没有发现,这些都是理想的情况下,一旦运行时配置发生变化,例如屏幕发生旋转,屏幕会重新加载,很多人觉得强制设置屏幕方向不变就可以了,以前我也这样做,但是当应用被置于后台(例如用户点击了home键)长时间没有返回的时候,应用也会被重新启动。 比如上例:如果把上面的例子置于FragmentThree界面,然后处于后台状态,长时间后你会发现当你再次通过home打开时,上面 FragmentThree与FragmentOne叠加在一起,这就是因为你的Activity重新启动,在原来的FragmentThree上又绘制 了一个FragmentOne。




为了体现一下效果,再写个简单的FragmentOne.java


public class FragmentOne extends Fragment {
 
 

 
 
     private static final String TAG = "xmr";  
 
 

 
 

 
 
    @Override
 
 
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
 
 
            Bundle savedInstanceState) {
 
 
        // return inflater.inflate(R.layout.fragment_one, container, false);
 
 
        View view = inflater.inflate(R.layout.fragment_one, container, false);
 
 

 
 
        return view;
 
 
    }
 
 
    @Override  
 
 
    public void onCreate(Bundle savedInstanceState)  
 
 
    {  
 
 
        // TODO Auto-generated method stub  
 
 
        super.onCreate(savedInstanceState);  
 
 

 
 
        Log.i(TAG, "onCreate");  
 
 
    }  
 
 

 
 
    @Override  
 
 
    public void onDestroyView()  
 
 
    {  
 
 
        // TODO Auto-generated method stub  
 
 
        super.onDestroyView();  
 
 
        Log.i(TAG, "onDestroyView");  
 
 
    }  
 
 

 
 
    @Override  
 
 
    public void onDestroy()  
 
 
    {  
 
 
        // TODO Auto-generated method stub  
 
 
        super.onDestroy();  
 
 
        Log.i(TAG, "onDestroy");  
 
 
    }  
 
 

 
 
}


MainActivity.java

public class MainActivity extends Activity {
 
 

 
 
    private FragmentOne mFragmentOne;
 
 

 
 
    @Override
 
 
    protected void onCreate(Bundle savedInstanceState) {
 
 
        super.onCreate(savedInstanceState);
 
 
        requestWindowFeature(Window.FEATURE_NO_TITLE);
 
 
        // getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
 
 
        // WindowManager.LayoutParams.FLAG_FULLSCREEN);
 
 
        setContentView(R.layout.activity_main);
 
 
        mFragmentOne = new FragmentOne();
 
 
        FragmentManager fragmentManager = getFragmentManager();
 
 
        FragmentTransaction transaction = fragmentManager.beginTransaction();
 
 
        transaction.add(R.id.framelayout_fragment_main, mFragmentOne, "ONE");
 
 
        transaction.commit();
 
 
    }
 
 

 
 
}


不断的旋转屏幕,你会发现每旋转一次屏幕,屏幕上就多了一个FragmentOne的实例,并且后台log会打印出许多套生命周期的回调。


Fragment初学8——Fragment在Android开发中的应用2_fragment




其实在上一节 Fragment状态管理 已经提到过,当屏幕发生旋转时,Activity会重新启动,默认的Activity中的Fragment也会跟着Activity重新创建,这就造成当旋转的时候,本身存在的Fragment会重新启动,然后当执行Activity的onCreate时,又会再次实例化一个新的Fragment, 这就是出现的原因。


解决办法就是通过检查onCreate的参数Bundle savedInstanceState判断当前是否发生Activity的重新创建。

简单改一下代码,只有在savedInstanceState==null时,才进行创建Fragment实例:


public class MainActivity extends Activity {
 
 

 
 
    private FragmentOne mFragmentOne;
 
 

 
 
    @Override
 
 
    protected void onCreate(Bundle savedInstanceState) {
 
 
        super.onCreate(savedInstanceState);
 
 
        requestWindowFeature(Window.FEATURE_NO_TITLE);
 
 
        // getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
 
 
        // WindowManager.LayoutParams.FLAG_FULLSCREEN);
 
 
        setContentView(R.layout.activity_main);
 
 
        if (savedInstanceState != null) {
 
 
            mFragmentOne = new FragmentOne();
 
 
            FragmentManager fragmentManager = getFragmentManager();
 
 
            FragmentTransaction transaction = fragmentManager
 
 
                    .beginTransaction();
 
 
            transaction
 
 
                    .add(R.id.framelayout_fragment_main, mFragmentOne, "ONE");
 
 
            transaction.commit();
 
 
        }
 
 
    }
 
 

 
 
}

现在无论进行多次旋转都只会有一个Fragment实例在Activity中。但是这并解决所有问题,例如当重新绘制时,Fragment发生重建,原本的数据如何保持?

其实和Activity类似,Fragment也有onSaveInstanceState的方法,在此方法中进行保存数据,然后在onCreate或者onCreateView或者onActivityCreated进行恢复都可以。


Fragment与ActionBar和MenuItem集成


Fragment可以添加自己的MenuItem到Activity的ActionBar或者可选菜单中。使用方法也很简单:

1、在Fragment的onCreate中调用setHasOptionsMenu(true);

2、然后在Fragment子类中实现onCreateOptionsMenu

3、如果希望在Fragment中处理MenuItem的点击,也可以实现onOptionsItemSelected,当然了Activity也可以直接处理该MenuItem的点击事件。

public class FragmentOne extends Fragment {
 
 

 
 
    private static final String TAG = "xmr";
 
 

 
 
    @Override
 
 
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
 
 
            Bundle savedInstanceState) {
 
 
        // return inflater.inflate(R.layout.fragment_one, container, false);
 
 
        View view = inflater.inflate(R.layout.fragment_one, container, false);
 
 
        Button mButton = (Button) view.findViewById(R.id.btn_fragment_one);
 
 
        return view;
 
 
    }
 
 

 
 
    @Override
 
 
    public void onCreate(Bundle savedInstanceState) {
 
 
        // TODO Auto-generated method stub
 
 
        super.onCreate(savedInstanceState);
 
 
        setHasOptionsMenu(true);
 
 
    }
 
 

 
 
    @Override
 
 
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
 
 
        // TODO Auto-generated method stub
 
 
        super.onCreateOptionsMenu(menu, inflater);
 
 
        inflater.inflate(R.menu.menu_fragment, menu);
 
 
    }
 
 

 
 
    @Override
 
 
    public boolean onOptionsItemSelected(MenuItem item) {
 
 
        switch (item.getItemId()) {
 
 
        case R.id.item1_menu_fragment:
 
 
            Toast.makeText(getActivity(), "fragment1", Toast.LENGTH_SHORT)
 
 
                    .show();
 
 
            return true;
 
 
        case R.id.item2_menu_fragment:
 
 
            Toast.makeText(getActivity(), "fragment1", Toast.LENGTH_SHORT)
 
 
                    .show();
 
 
            return true;
 
 
        default:
 
 
            return true;
 
 
        }
 
 
    }
 
 

 
 
    @Override
 
 
    public void onDestroyView() {
 
 
        // TODO Auto-generated method stub
 
 
        super.onDestroyView();
 
 
        Log.i(TAG, "--onDestroyView");
 
 
    }
 
 

 
 
    @Override
 
 
    public void onDestroy() {
 
 
        // TODO Auto-generated method stub
 
 
        super.onDestroy();
 
 
        Log.i(TAG, "--onDestroy");
 
 
    }
 
 

 
 
}
 

 

 
public class MainActivity extends Activity {
 
 

 
 
    private FragmentOne mFragmentOne;
 
 

 
 
    @Override
 
 
    protected void onCreate(Bundle savedInstanceState) {
 
 
        super.onCreate(savedInstanceState);
 
 
        requestWindowFeature(Window.FEATURE_NO_TITLE);
 
 
        // getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
 
 
        // WindowManager.LayoutParams.FLAG_FULLSCREEN);
 
 
        setContentView(R.layout.activity_main);
 
 
        if (savedInstanceState == null) {
 
 
            mFragmentOne = new FragmentOne();
 
 
            FragmentManager fragmentManager = getFragmentManager();
 
 
            FragmentTransaction transaction = fragmentManager
 
 
                    .beginTransaction();
 
 
            transaction
 
 
                    .add(R.id.framelayout_fragment_main, mFragmentOne, "ONE");
 
 
            transaction.commit();
 
 
        }
 
 
    }
 
 

 
 
    @Override
 
 
    public boolean onCreateOptionsMenu(Menu menu) {
 
 
        // TODO Auto-generated method stub
 
 
         super.onCreateOptionsMenu(menu);
 
 
        getMenuInflater().inflate(R.menu.main, menu);
 
 
        return true;
 
 
    }
 
 
      @Override  
 
 
        public boolean onOptionsItemSelected(MenuItem item)  
 
 
        {  
 
 
            switch (item.getItemId())  
 
 
            {  
 
 
            case R.id.action_settings:  
 
 
                Toast.makeText(this, "setting", Toast.LENGTH_SHORT).show();  
 
 
                return true;  
 
 
            default:  
 
 
                //如果希望Fragment自己处理MenuItem点击事件,一定不要忘了调用super.xxx  
 
 
                return super.onOptionsItemSelected(item);  
 
 
            }  
 
 
        } 
 
 
}


源代码


参考:

http://www.mamicode.com/info-detail-495507.html




标签:transaction,Fragment,fragment,初学,Activity,Override,Android,public
From: https://blog.51cto.com/u_6947107/7548584

相关文章

  • Android 妙用TextView实现左边文字,右边图片
    有时候,需要文字在左边,右边有个箭头,我个人之前会有两种做法:使用线性布局来实现或者使用约束布局,一个左对齐,一个右对齐这几天突然想到是否可以使用TextView的设置图标的方式实现,研究发现确实可以实现我的需求,也是记录下文字和图标左右显示效果:代码:<TextViewandroid:id="@+id/......
  • Android开发中Button背景颜色不能修改问题及解决方法
    在Android中,Button是一种按钮组件,用户能够在该组件上点击,并引发相应的事件处理函数。在进行Android开发的时候,都需要使用到按钮,但是对于初学者来说,刚开始的按钮都是默认的主题颜色,不管怎么修改都变不了颜色,在此记录一下踩过的坑。问题:使用AndroidStudio进行android开发时,不管是......
  • 简历被筛、面试被拒?Android求职者们如何给自己争取面试机会?
    前言相信各位小伙伴在求职过程中,都会遇到简历投递之后已读不回、面试邀请迟迟没有音讯以及初试被刷的情况。一般来说,大多数小伙伴就会直接选择放弃这家公司了,但是!先别急着换下一家投递呀!求职面试是彼此双向选择的一个过程,不要觉得有心理负担,也不要觉得不好意思,如果是真的很需要一个......
  • 初学C语言
    今天继续来分享我初学C语言的收获,与大家共享。作为一名小白,其实对于大多数知识都是全新的,所以我分享的收获更为基础,或者说是更为低级。今天主要分享的是数据类型:数据类型(代码)数据名称字节char字符数据类型1short短整型2int整型4long长整型4/8longlong更长的整型8float单精度浮点型......
  • 最全详解Android设备UDID还是唯一ID?
    这篇文章主要介绍了Android设备UDID还是唯一ID?我觉得挺不错的,现在分享给大家,也给大家做个参考。我想为我的Android应用程序生成android设备唯一ID,以根据用户设备udid创建收藏夹.所有设备都有唯一的ID.importandroid.provider.Settings.Secure;privateStringandroid_id=Se......
  • 2022最新手机设备标识码(IMEI、MEID、UDID、UUID、ANDROID_ID、GAID、IDFA等)教程
    Android篇 1IMEI和MEID(1)IMEI(InternationalMobileEquipmentIdentity)是国际移动设备身份码的缩写,国际移动装备辨识码,只有Android手机才获取的到,是由15位数字组成的"电子串号",比如像这样359881030314356,它与每台移动电话机一一对应,而且该码是全世界唯一的。它是GSM设备返......
  • 2022Android设备唯一标识(AndroidID,OAID等 )
    一、ID体系:你只是一串代码想要了解OAID,我们首先需要明白ID体系:想要追踪一个用户就必须先找到用户,在这个过程中,标识符(ID)就像我们的另一张身份证,它们就代表了数字化之后的你和我。不同App可能通过某些唯一标识符对你进行强制跟踪,广告平台则会通过这个唯一标识符对你进行用户画......
  • 方法初学习
    方法学习方法的定义及调用设计原则,一个方法只能有一个功能//自定义方法修饰符+返回值类型/*void是不返回,如int返回数字,需要用return来输出返回值*/+自定义方法名称,或调用Java本来就有的名称+(参数//可不注释){}加法自定义备注:方法包含与类与对象中可将我们自己写的代码作......
  • 没有Android开发的工作经验,该如何求职?
    前言找工作是每一个新毕业生都要面临的难题,尤其是在如今竞争激烈的社会环境下。无工作经验的应届生想要获得心仪Offer无疑更加困难。但是,没有经验并不代表没有机会。推推教你做好以下几点准备,依然可以在求职中脱颖而出!第一,要明确自己的专业方向和职业规划。根据自己的专业知识、技......
  • 金九银十就业季,Android工程师如何在面试中提升印象分?
    又到了金九银十的就业季,在面试过程中提升印象分是非常重要的。想要在面试中脱颖而出吗?下面是几个建议,小编希望大家可以借鉴一下。一、提前做足准备在参加面试之前,你应该做足准备。这包括了解公司的背景、业务模式、文化和价值观,以及与招聘的职位相关的技能和职责。刷刷该公司历年的......