Android学习第十二篇——Fragment基础学习

原创 2016年08月31日 11:11:22

今天要讲的是Fragment(意思是“碎片片段”),这是在Android3.0中引入的,主要目的是用在大屏幕设备上——例如平板电脑上,支持更加动态和灵活的UI设计。平板电脑的屏幕要比手机的大得多,有更多的控件来放更多的UI组件,并且这些组件之间会产生更多的交互。


通过这张图片我们就可以明显的对比一下了。


接下来分四部分进行学习!


Part 1. 静态加载Fragment


所谓的静态加载就是我们直接在一个布局文件中添加<fragment/>标签,例如下面代码

pageone.xml

<?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:id="@+id/frag_one"
        android:name="com.example.fragmentdemo.Fragment1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>
当我们这样使用<fragment/>的时候,必须添加android:name=""这个属性,而该属性的值就是我们自己创建的一个类(继承了Fragment的类)

我们来看一下这个类

Fragment1.java

package com.example.fragmentdemo;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class Fragment1 extends Fragment {

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		
		View view = inflater.inflate(R.layout.fragment_one, container,false);
		TextView tv_one = (TextView) view.findViewById(R.id.tv_one);
		tv_one.setText("靜態加載Fragment");
		return view;
	}
}
在这个类中我们只实现了一个方法onCreateView()方法,通过这个方法,每次创建都会绘制Fragment的View组件时回调该方法。我们具体来看一下该方法内部的代码,看到第一行代码的时候,我们发现,这里我们居然又一次出现一个布局,这个布局是干嘛的呢??

我们先把问题放一下,之前讲到过,Fragment的意思是碎片和片段,这个是相对于整个Activity来说是零碎的一部分,但是自己内部又是一个完整的,举个例子:Activity好比是一套房,Fragment好比是这套房里的某个房间,一套房存在许多房间,而一个房间里又可以存放很多东西,所有的房间+房间内的东西 = 一套房子。想必讲到这里,前面的问题就应该明白了吧!最开始的时候,我们只是给了一个房间,现在我们是在给房间里添东西。

fragment_one.xml

<?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" >

    <TextView
        android:id="@+id/tv_one"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/btn_one"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

看完这些小的以后,我们回到大的来看MainActivity

activity_main.xml(MainActivity的布局文件)

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    
    <Button 
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="静态加载Fragment"/>
    <Button 
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="动态加载Fragment"/>
    <Button 
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Fragment生命周期"/>
    <Button 
        android:id="@+id/btn4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Fragment传值通信"/>
    
</LinearLayout>


MainActivity.java

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

		button1 = (Button) findViewById(R.id.btn1);
		button1.setOnClickListener(new btn1Click());
	}
	
	class btn1Click implements OnClickListener{

		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			Intent intent = new Intent(MainActivity.this,PageOne.class);
			startActivity(intent);
		}
	}
	

我们点击了第一个按钮后跳转到PageOne.class页面上,这个页面就是我们之前存放Fragment的页面

PageOne.java

package com.example.fragmentdemo;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class PageOne extends Activity {

	Button btn_one;
	TextView tv_one;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.pageone);
		btn_one = (Button) findViewById(R.id.btn_one);
		btn_one.setText("改变TextView的内容");
		tv_one = (TextView) findViewById(R.id.tv_one);
		btn_one.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				tv_one.setText("TextView改变了!");
			}
		});
	}
}

在这个代码中我们可以发现,我们居然可以在这里直接通过findViewById()获取到fragment_one.xml上的组件,而不需要通过view.findViewById()这样,这是因为我们先加载了整个布局文件,也就是说我们已经加载了<fragmeng/>,因此我们可以直接访问fragment_one.xml中的组件,这个与fragment的生命周期有关,我们后面讲到生命周期的时候可以自己去看看。


效果显示



可能我上面讲的比较凌乱,没有一个调理,这里我把一个流程捋一捋。


首先创建项目 -->在主布局上放置四个Button -->在创建一个类PageOne.java(继承Activity,记得添加到AndroidManifest中)--> 为刚才的类创建布局pageone.xml,在这个布局中放置<fragmeng/>--> 因为这个布局中需要一个name属性,因此我们需要在创建一个类Fragment1.java(继承自Fragment),然后实现OnCreateView()方法--> 这里我们有需要创建一个布局fragment_one.xml--> 这些好了以后把之前的name属性补全,然后把页面跳转代码和按钮点击事件代码完成就差不多了。


Part 2. 动态加载Fragment


动态添加是指我们不再把Fragment固定的写在XML布局中,而是我们通过FragmentManager和FragmentTransaction来动态创建。

同样的,我们需要一个Fragment2.java(可以直接复制之前的Fragment1.java)

button2 = (Button) findViewById(R.id.btn2);
		button2.setOnClickListener(new btn2Click());//放在MainActivity的OnCreate中
……
class btn2Click implements OnClickListener{

		@Override
		public void onClick(View v) {
			Fragment2 frag = new Fragment2();
			FragmentManager fragmentManager = getFragmentManager();
			FragmentTransaction beginTransaction = fragmentManager.beginTransaction();
			//把我们的Fragment放到一个容器中(放到一个布局中去)
			beginTransaction.add(R.id.container, frag);
			//使得我们的后退点击后,可以看到之前的状态,放到一个后退栈中
			beginTransaction.addToBackStack(null);
			//最后必须提交事务(Transaction)
			beginTransaction.commit();
		}
	}





在这里我有一个疑问还没解决,就是之前我们看到在PageOne中,我们可以直接获取那些组件,在这里我们该怎么获取上面的组件呢??



Part 3. Fragment生命周期


我们先来看一下在在开发者文档中给出的生命周期图

                                       


查看生命周期的方法就是通过打印log日志,在控制台中查看输出

MainActivity

class btn3Click implements OnClickListener{

		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			Intent intent = new Intent(MainActivity.this,PageTwo.class);
			startActivity(intent);
		}
	}

PageTwo

package com.example.fragmentdemo;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class PageTwo extends Activity {

	private Button button;
	private Fragment frag;
	private boolean flag = true;

	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.pagetwo);
		init();
		button = (Button) findViewById(R.id.button);
		button.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				FragmentManager fragmentManager = getFragmentManager();
				FragmentTransaction beginTransaction = fragmentManager
						.beginTransaction();
				
				if (flag) {
					Fragment4 frag4=new Fragment4();
					beginTransaction.replace(R.id.layout, frag4);
					flag=false;

				} else {
					Fragment3 frag3=new Fragment3();
					beginTransaction.replace(R.id.layout, frag3);
					flag=true;

				}
				
			   beginTransaction.commit();
			}
		});

	}

	private void init() {
		// TODO Auto-generated method stub

		FragmentManager fragmentManager = getFragmentManager();
		FragmentTransaction beginTransaction = fragmentManager
				.beginTransaction();
		Fragment3 frag3 = new Fragment3();
		beginTransaction.add(R.id.layout,frag3);
		beginTransaction.commit();
	}

}


Fragment3.java

package com.example.fragmentdemo;

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class Fragment3 extends Fragment {

	private TextView tv;

	// 启动Fragment——>屏幕锁屏——>屏幕解锁——>
	//切换到其他的Fragment——>回到桌面——>回到应用——>退出Fragment
	/**
	 * 每次创建都会绘制Fragment的View组件时回调该方法
	 */
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		View view = inflater.inflate(R.layout.fragment2, container, false);
		TextView tv = (TextView) view.findViewById(R.id.text);
		tv.setText("第一个Fragment");
		Log.i("Main", "Fragment1---onCreateView()");
		return view;
	}

	/**
	 * 当Fragment被添加到Activity时候会回调这个方法,并且只调用一次
	 */
	@Override
	public void onAttach(Activity activity) {
		// TODO Auto-generated method stub
		super.onAttach(activity);
		Log.i("Main", "Fragment1---onAttach()");

	}

	/**
	 * 创建Fragment时会回调,只会调用一次
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		Log.i("Main", "Fragment1---onCreate()");

	}

	/**
	 * 当Fragment所在的Activty启动完成后调用
	 */
	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onActivityCreated(savedInstanceState);
		Log.i("Main", "Fragment1---onActivityCreated()");

	}

	/**
	 * 启动Fragment
	 * 
	 */
	@Override
	public void onStart() {
		// TODO Auto-generated method stub
		super.onStart();
		Log.i("Main", "Fragment1---onStart()");

	}

	/**
	 * 恢复Fragment时会被回调,调用onStart()方法后面一定会调用onResume()方法
	 */
	@Override
	public void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		Log.i("Main", "Fragment1---onResume()");

	}

	/**
	 * 暂停Fragment
	 */
	@Override
	public void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		Log.i("Main", "Fragment1---onPause()");

	}

	/**
	 * 停止Fragment
	 */
	@Override
	public void onStop() {
		// TODO Auto-generated method stub
		super.onStop();
		Log.i("Main", "Fragment1---onStop()");

	}

	/**
	 * 销毁Fragment所包含的View组件时
	 */
	@Override
	public void onDestroyView() {
		// TODO Auto-generated method stub
		super.onDestroyView();
		Log.i("Main", "Fragment1---onDestroyView()");

	}

	/**
	 * 销毁Fragment时会被回调
	 */
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		Log.i("Main", "Fragment1---onDestroy()");

	}

	/**
	 * Fragment从Activity中删除时会回调该方法,并且这个方法只会调用一次
	 */
	@Override
	public void onDetach() {
		// TODO Auto-generated method stub
		super.onDetach();
		Log.i("Main", "Fragment1---onDetach()");
	}
}

Fragment4.java

package com.example.fragmentdemo;

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class Fragment4 extends Fragment {

	private TextView tv;

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		View view = inflater.inflate(R.layout.fragment2, container, false);
		TextView tv = (TextView) view.findViewById(R.id.text);
		tv.setText("第二个Fragment");
		Log.i("Main", "Fragment2---onCreateView()");
		return view;
	}

	@Override
	public void onAttach(Activity activity) {
		// TODO Auto-generated method stub
		super.onAttach(activity);
		Log.i("Main", "Fragment2---onAttach()");
	
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		Log.i("Main", "Fragment2---onCreate()");

	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onActivityCreated(savedInstanceState);
		Log.i("Main", "Fragment2---onActivityCreated()");
	
	}

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

	@Override
	public void onResume() {
		// TODO Auto-generated method stub
		super.onResume();
		Log.i("Main", "Fragment2---onResume()");
		
	}
	
	@Override
	public void onPause() {
		// TODO Auto-generated method stub
		super.onPause();
		Log.i("Main", "Fragment2---onPause()");
	
	}
	
	@Override
	public void onStop() {
		// TODO Auto-generated method stub
		super.onStop();
		Log.i("Main", "Fragment2---onStop()");
		
	}
	
	@Override
	public void onDestroyView() {
		// TODO Auto-generated method stub
		super.onDestroyView();
		Log.i("Main", "Fragment2---onDestroyView()");

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


接下来依据这样的步骤来查看生命周期


启动Fragment(点击主布局的第三个按钮)——>屏幕锁屏——>屏幕解锁——>切换到其他的Fragment——>回到桌面——>回到应用——>退出Fragment










Part 4. Fragment和Activity的传值通信


Activity -->  Fragment : 在Activity中创建Bundle数据包,并且调用Fragment的setArguments(Bundle bundle)方法


Fragment  -->  Activity : 需要在Fragment中定义一个内部回调接口,让包含该Fragment的Activity实现该回调接口,这样Fragment可调用该回调方法将数据传递给Activity


一下这是开发文档中的两句话

All Fragment-to-Fragment communication is done through the associated Activity. Two Fragments should never communicate directly.

Fragment和Fragment之间的通信需要通过Activity的协助,两个Fragment之间不能直接通信。


Fragment -->  Activity的实现方法

To allow a Fragment to communicate up to its Activity, you can define an interface in the Fragment class and implement it within the Activity. The Fragment captures the interface implementation during its onAttach() lifecycle method and can then call the Interface methods in order to communicate with the Activity.


要使得Fragment能够和Activity通信,我们可以在Fragment类中声明一个接口,然后让Activity实现这个接口,Fragment可以捕捉这个接口在它的onAttach()方法中实现,调用这个接口方法完成和Activity的通信。


接下来我们按照下面的流程来实现上面的通信

第一步:Activity发送信息给Fragment(动态添加Fragment)

第二步:Fragment接受信息并且显示在TextView中

第三步:Fragment发送确认收到信息并且给Activity发送感谢

第四步:Activity吐司表示“不客气”

第五步:静态在Activity中添加Fragment,并且给Fragment发送信息(吐司显示信息)


最后我们来看一下代码(我把所有的代码都贴出了,看的时候可以根据上面的步骤来看)

在MainActivity中知识添加了一个按钮的监听事件,实现跳转,不多讲。


先看布局文件pagethird.xml

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

    <EditText
        android:id="@+id/etText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/btnSend"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="发送" />

    <fragment
        android:id="@+id/fragthird"
        android:name="com.example.fragmentdemo.Fragment1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>


PageThird.java

public class PageThird extends Activity implements MyListener {

	private EditText etText;
	private Button btnSend;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.pagethrid);
		
		etText = (EditText) findViewById(R.id.etText);
		btnSend = (Button) findViewById(R.id.btnSend);
		
		btnSend.setOnClickListener(new OnClickListener() {
			//这部分是动态添加Fragment
			@Override
			public void onClick(View v) {
				String message = etText.getText().toString();
				Bundle bundle = new Bundle();
				bundle.putString("message", message);
				Fragment55 fragment = new Fragment55();
				fragment.setArguments(bundle);
				
				FragmentManager fragmentManager = getFragmentManager();
				FragmentTransaction beginTransaction = fragmentManager.beginTransaction();
				beginTransaction.add(R.id.third, fragment, "fragment5");
				beginTransaction.commit();
				Toast.makeText(PageThird.this, "向Fragment发送数据" + message,
						Toast.LENGTH_SHORT).show();
			}
		});
		
		
		/*
		 * 这部分是静态添加Fragment
		 */
		FragmentManager fragmentManager = getFragmentManager();
		Fragment findFragmentById = fragmentManager.findFragmentById(R.id.fragthird);
		Fragment1 frag = (Fragment1) findFragmentById;
		frag.setAaa("fragment静态传值");
	
	}
	
	//实现Fragment55中的接口
	@Override
	public void thank(String code) {
		// TODO Auto-generated method stub
		Toast.makeText(PageThird.this, "已成功接收到" + code + ",客气了!",
				Toast.LENGTH_SHORT).show();
	}
}

Fragment55.java

public class Fragment55 extends Fragment {

	private String code="Thank you,Activity!";
	
	public interface MyListener{
		public void thank(String code); 
	}
	
	public MyListener listener;
	@Override
	public void onAttach(Activity activity) {
		// TODO Auto-generated method stub
		listener = (MyListener) activity;
		super.onAttach(activity);
	}
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		View view = inflater.inflate(R.layout.fragment2, container, false);
		TextView tv = (TextView) view.findViewById(R.id.text);
		String message = getArguments().getString("message");
		tv.setText(message);
		Toast.makeText(getActivity(), "已成功接收到"+message, Toast.LENGTH_SHORT).show();
		Toast.makeText(getActivity(), "向Activity发送"+code, Toast.LENGTH_SHORT).show();
		listener.thank(code);
		return view;
	}
}

我们还会对之前的Fragment1.java做一些修改

public class Fragment1 extends Fragment {

	private String aaa;

	public String getAaa() {
		return aaa;
	}

	public void setAaa(String aaa) {
		this.aaa = aaa;
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {

		View view = inflater.inflate(R.layout.fragment_one, container, false);
		TextView tv_one = (TextView) view.findViewById(R.id.tv_one);
		Button button = (Button) view.findViewById(R.id.btn_one);
		tv_one.setText("静态加载Fragment");
		button.setText("获取内容");
		button.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				// TODO Auto-generated method stub
				String value = getAaa();
				Toast.makeText(getActivity(), "value=" + value,
						Toast.LENGTH_SHORT).show();
			}
		});
		return view;
	}
}


我在弄的时候出现了这么一个异常:android.view.InflateException: Binary XML file line #19: Error inflating class fragment

后来找了一下代码,发现在Fragment1.java中的Button的id获取错了,所以大家在编写的时候一定要仔细



Demo资源下载




版权声明:本文为博主原创文章,未经博主允许不得转载。 举报

相关文章推荐

黑马程序员_java的IO流(第二十课总结)

------- android培训、java培训、期待与您交流! ---------- 通过今天对java语言IO流的学习,我来给自己的学习内容做下简单直白的总结: 首先,我来总结下学习IO流...

黑马程序员_java的多线程进阶(对第十二课等待唤醒机制和生产消费总结)

------- android培训、java培训、期待与您交流! ---------- 通过今天对java语言多线程的学习,我来给自己的学习内容做下简单直白的总结: 首先,我来总结下什...

精选:深入理解 Docker 内部原理及网络配置

网络绝对是任何系统的核心,对于容器而言也是如此。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker的网络一直以来都比较薄弱,所以我们有必要深入了解Docker的网络知识,以满足更高的网络需求。

1、(一)学习如何Debug

一、原因 工作以来,发现最大的难题不是写代码,而是找代码中的错误。大多数程序猿写的代码都不可能是最终版,都需要不断的调试,更正。所以学习Debug在我看来是仅次于编程的一个能力,可惜的是无论是在学校...

android基础学习之Fragment

android、Fragment

Linux学习基础篇(十)

一、权限管理 1.1ACL权限 1.2文件特殊权限 1.3文件系统属性权限 1.4系统命令sudo权限

一篇告诫正在学习以及将要学习计算机的同学的文章【找不到原作者及出处非常抱歉】

我始终认为,对一个初学者来说,IT界的技术风潮是不可以追赶的,而且也没有能力去追赶。 我时常看见自己的DDMM们把课本扔了,去卖些价格不菲的诸如C#, VB.Net 这样的大部头,这让我感到非常痛心。...

记录学习第一天-c#

方法的内容要单一 方法最忌讳的就是提示用户输入信息  用户输入信息应该在Main()方法中写 使用out参数 当使用一个方法时 需要返回多个相同类型的值时 可以考虑使用数组 当时当方法需要返回多...

Fragment学习基础

Fragment的设计哲学: Fragment是从 Android 3.0开始引入的,主要用于大屏幕设备,如平板电脑。 以一个新闻应用在小屏和大屏设备上的设计来阐述Fragment的设计哲学。 对...

正则表达式(Regex)

定义:是指一个用来描述或者匹配一系列符合某个语法规则字符串的字符串 ,其实就是一种规则。、 字符类:   []代表单个字符            &...

多态

多态           里氏转换原则:              &#...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)