一起来聊聊Android基础之Fragment

一起来聊聊Android基础之Fragment

标签(空格分隔): Android面试知识 Android开发


参考资料

扯闲篇

Fragment的使用非常广泛,是Android中最基础,最重要的概念之一,甚至被称为第五大组件。所以这篇文章就来聊聊Fragment,基本概念和背景什么的都先PASS了,关键是会灵活使用不是吗?

加载Fragment

静态加载Fragment

首先,定义一下Fragment文件:FooFragment.java

import android.support.v4.app.Fragment;

public class FooFragment extends Fragment {
    // The onCreateView method is called when Fragment should create its View object hierarchy,
    // either dynamically or via XML layout inflation. 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        // Defines the xml file for the fragment
        return inflater.inflate(R.layout.fragment_foo, parent, false);
    }

    // This event is triggered soon after onCreateView().
    // Any view setup should occur here.  E.g., view lookups and attaching view listeners.
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        // Setup any handles to view objects here
        // EditText etFoo = (EditText) view.findViewById(R.id.etFoo);
    }
}

然后在要加载Fragment的Activity的布局文件中添加fragment标签:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <fragment
        android:name="com.example.android.FooFragment"
        android:id="@+id/fooFragment"
        android:layout_width="match_parent" 
        android:layout_height="match_parent" />

</LinearLayout>

动态加载Fragment

动态加载方式需要修改Activity布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

  <FrameLayout
       android:id="@+id/your_placeholder"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
  </FrameLayout>
</LinearLayout>

然后通过如下代码进行添加:

// Begin the transaction
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
// Replace the contents of the container with the new fragment
ft.replace(R.id.your_placeholder, new FooFragment());
// or ft.add(R.id.your_placeholder, new FooFragment());
// Complete the changes added above
ft.commit();

注:replace方法就是remove()然后add()的合体。
还有hide方法用来隐藏fragment

添加Fragment的操作还是很简单的,一般动态加载使用的更多一些。

Fragment的生命周期

接下来讲重点,Fragment的生命周期。
Fragment具有自己的生命周期,但Fragment是依赖Activity而存在的,所以需要和Activity的生命周期一起来讨论。

先看一张Activity和Fragment生命周期的对比图:
此处输入图片的描述

  • onAttach() is called when a fragment is connected to an activity.
  • onCreate() is called to do initial creation of the fragment.
  • onCreateView() is called by Android once the Fragment should inflate a view.
  • onViewCreated() is called after onCreateView() and ensures that the fragment’s root view is non-null. Any view setup should happen here. E.g., view lookups, attaching listeners.
  • onActivityCreated() is called when host activity has completed its onCreate() method.
  • onStart() is called once the fragment is ready to be displayed on screen.
  • onResume() - Allocate “expensive” resources such as registering for location, sensor updates, etc.
  • onPause() - Release “expensive” resources. Commit any changes.
  • onStop() - is called when fragment is no invisible
  • onDestroyView() is called when fragment’s view is being destroyed, but the fragment is still kept around.
  • onDestroy() is called when fragment is no longer in use.
  • onDetach() is called when fragment is no longer connected to the activity.

Fragment的生命周期和Activity的生命周期基本是匹配的,但是有自己独特的回调方法:包括onAttach(),onCreatView(),onDestroyView()等。

下面以实际场景来看一下Fragment的生命周期。
场景一:采用静态加载Fragment,首次加载。依次回调如下方法:
Activity.onCreate->Fragment.onAttach->Fragment.onCreate->Fragment.onCreateView->Fragment.onViewCreated->Fragment.onActivityCreated->Fragment.onStart->Activity.onStart->Activity.onResume->Fragment.onResume

场景二:按HOME键,依次回调如下方法:
Fragment.onPause->Activity.onPause->Fragment.onStop->Activity.onStop

场景三:场景二之后,再次进入Activity,依次回调如下方法:
Activity.onRestart->Fragment.onStart->Activity.onStart->Activity.onResume->Fragment.onResume

场景四:退出Activity。依次回调如下方法:
Fragment.onPause->Activity.onPause->Fragment.onStop->Activity.onStop->Fragment.onDestroyView->Fragment.onDestroy->Fragment.onDetach->Activity->onDestroy

下面摘录一段来自codepath上的fragment示例代码:

public class SomeFragment extends Fragment {
    ThingsAdapter adapter;
    FragmentActivity listener;

    // This event fires 1st, before creation of fragment or any views
    // The onAttach method is called when the Fragment instance is associated with an Activity. 
    // This does not mean the Activity is fully initialized.
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof Activity){
            this.listener = (FragmentActivity) context;
        }
    }

    // This event fires 2nd, before views are created for the fragment
    // The onCreate method is called when the Fragment instance is being created, or re-created.
    // Use onCreate for any standard setup that does not require the activity to be fully created
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ArrayList<Thing> things = new ArrayList<Thing>();
        adapter = new ThingsAdapter(getActivity(), things);
    }

    // The onCreateView method is called when Fragment should create its View object hierarchy,
    // either dynamically or via XML layout inflation. 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_some, parent, false);
    }

    // This event is triggered soon after onCreateView().
    // onViewCreated() is only called if the view returned from onCreateView() is non-null.
    // Any view setup should occur here.  E.g., view lookups and attaching view listeners.
    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        ListView lv = (ListView) view.findViewById(R.id.lvSome);
        lv.setAdapter(adapter);
    }

    // This method is called when the fragment is no longer connected to the Activity
    // Any references saved in onAttach should be nulled out here to prevent memory leaks. 
    @Override
    public void onDetach() {
        super.onDetach();
        this.listener = null;
    }

    // This method is called after the parent Activity's onCreate() method has completed.
    // Accessing the view hierarchy of the parent activity must be done in the onActivityCreated.
    // At this point, it is safe to search for activity View objects by their ID, for example.
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }
}

查询Fragment实例

查询Fragment实例有三种
- ID - FragmentManager.findFragmentById

public class MainActivity extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState == null) {
          DemoFragment fragmentDemo = (DemoFragment) 
              getSupportFragmentManager().findFragmentById(R.id.fragmentDemo);
        }
    }
}
  • Tag - FragmentManager.findFragmentByTag
public class MainActivity extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (savedInstanceState == null) {
          // Let's first dynamically add a fragment into a frame container
          getSupportFragmentManager().beginTransaction(). 
              replace(R.id.flContainer, new DemoFragment(), "SOMETAG").
              commit();
          // Now later we can lookup the fragment by tag
          DemoFragment fragmentDemo = (DemoFragment) 
              getSupportFragmentManager().findFragmentByTag("SOMETAG");
        }
    }
}
  • Pager - PagerAdapter中的getRegisteredFragment
    // TODO 待熟悉PagerAdapter再补充

Fragment通信

Fragment进行通信的方式主要有三种:
1.Bundle
首先通过构造fragment实例时将待传输的数据保存在Bundle中,然后调用Fragment的setArguments方法进行传递。
然后在Fragment的onCreate方法取出Bundle数据。具体实现看代码:

public class DemoFragment extends Fragment {
    // Creates a new fragment given an int and title
    // DemoFragment.newInstance(5, "Hello");
    public static DemoFragment newInstance(int someInt, String someTitle) {
        DemoFragment fragmentDemo = new DemoFragment();
        Bundle args = new Bundle();
        args.putInt("someInt", someInt);
        args.putString("someTitle", someTitle);
        fragmentDemo.setArguments(args);
        return fragmentDemo;
    }
}

    @Override
    public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       // Get back arguments
       int SomeInt = getArguments().getInt("someInt", 0);   
       String someTitle = getArguments().getString("someTitle", "");    
    }

    // Within the activity
    FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
    DemoFragment fragmentDemo = DemoFragment.newInstance(5, "my title");
    ft.replace(R.id.your_placeholder, fragmentDemo);
    ft.commit();

2.Fragment Methods
这个就比较直接了,先在Fragment中新建一个方法,然后在Activity中获取到该Fragment实例,最后直接调用方法即可。

public class DemoFragment extends Fragment {
  public void doSomething(String param) {
      // do something in fragment
  }
}

public class MainActivity extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        DemoFragment fragmentDemo = (DemoFragment) 
            getSupportFragmentManager().findFragmentById(R.id.fragmentDemo);
        fragmentDemo.doSomething("some param");
    }
}

3.Fragment Listener
设置一个listener接口,在Activity中实现该接口的方法,然后在Fragment中调用该方法,就可以实现方法回调,这也是程序开发中各个组件相互通信的常用方法。

public class MyListFragment extends Fragment {
  // ...
  // Define the listener of the interface type
  // listener will the activity instance containing fragment
  private OnItemSelectedListener listener;

  // Define the events that the fragment will use to communicate
  public interface OnItemSelectedListener {
    // This can be any number of events to be sent to the activity
    public void onRssItemSelected(String link);
  }

  // Store the listener (activity) that will have events fired once the fragment is attached
  @Override
  public void onAttach(Context context) {
      super.onAttach(context);
      if (context instanceof OnItemSelectedListener) {
        listener = (OnItemSelectedListener) context;
      } else {
        throw new ClassCastException(context.toString()
            + " must implement MyListFragment.OnItemSelectedListener");
      }
  }

  // Now we can fire the event when the user selects something in the fragment
  public void onSomeClick(View v) {
     listener.onRssItemSelected("some link");
  }
}

// Activity implements the fragment listener to handle events
public class RssfeedActivity extends AppCompatActivity implements MyListFragment.OnItemSelectedListener {
    // Can be any fragment, `DetailFragment` is just an example
    DetailFragment fragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rssfeed);
        // Get access to the detail view fragment by id
        fragment = (DetailFragment) getSupportFragmentManager()
            .findFragmentById(R.id.detailFragment);
  }

  // Now we can define the action to take in the activity when the fragment event fires
  // This is implementing the `OnItemSelectedListener` interface methods
  @Override
  public void onRssItemSelected(String link) {
      if (fragment != null && fragment.isInLayout()) {
          fragment.setText(link);
      }
  }
}

管理Fragment的返回栈

通过FragmentManager可以对Fragment transaction进行管理,调用addToBackStack方法可以将fragment transaction进栈,从而按返回键时将销毁添加的fragment,而不是销毁activity。
与之相对应的是popBackStack方法,它会将栈中的fragment transaction出栈。

addToBackStack()
popBackStack()

Fragment切换

Fragment之间的切换常和TabLayout,Fragment Navigation Drawer,ViewPager等控件进行搭配实现。
直接参照这两个实例练习一遍,就可以熟悉Fragment的基本使用了。

TabLayout+ViewPager

Google Play Style Tabs using TabLayout

Fragment Navigation Drawer

Fragment Navigation Drawer

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值