欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

一起来聊聊Android基础之Fragment

程序员文章站 2022-09-30 08:57:14
一起来聊聊Android基础之Fragment Fragment的使用非常广泛,是Android中最基础,最重要的概念之一,甚至被称为第五大组件。所以这篇文章就来聊聊Fragme...

一起来聊聊Android基础之Fragment

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标签:




    

动态加载Fragment

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




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

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

// 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生命周期的对比图:
一起来聊聊Android基础之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 things = new ArrayList();
        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的基本使用了。