一、先记录一个问题:Fragment和Activity之间的通信。
(1)在Activity中操作Fragment
在activity中取得fragment的实例,通过这个实例进行通信,比如调用fragment中的方法等;
(2)在Fragment中操作Activity
通过getActivity()得到Activity的实例,进行操作。其中,必须记住的是接口回调的使用。
例:
Fragment1:
package com.wy.fragmentpractice.fragment;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import com.wy.fragmentpractice.R;
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class Fragment1 extends Fragment {
MClickListener mClickListener;
@Bind(R.id.btnAdd)
Button btnAdd;
@Bind(R.id.btnDelete)
Button btnDelete;
//方法1:在onAttach()中实例化mClickListener
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mClickListener = (MClickListener) activity;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment1, container, false);
ButterKnife.bind(this, view);
Log.i("TAG","onCreateView--Fragment1");
return view;
}
@Override
public void onDestroyView() {
super.onDestroyView();
ButterKnife.unbind(this);
}
@OnClick({R.id.btnAdd, R.id.btnDelete})
public void onClick(View view) {
switch (view.getId()) {
case R.id.btnAdd:
mClickListener.setOnAddClick();
break;
case R.id.btnDelete://方法2:通过getActivity()得到宿主Activity,让Activity调用接口方法
if (getActivity() instanceof MClickListener){
((MClickListener) getActivity()).setOnDeleteClick();
}
break;
}
}
public interface MClickListener {
void setOnAddClick();
void setOnDeleteClick();
}
}
Fragment1中有横向排列的2个Button。
其中使用了一个强大的库:ButterKnife,用来简化findViewById()的代码,以后再记录着个库的详情。
Fragment2:
package com.wy.fragmentpractice.fragment;
import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import com.wy.fragmentpractice.R;
import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class Fragment2 extends Fragment {
@Bind(R.id.btnToast)
Button btnToast;
MyToastListener myToastListener;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment2, container, false);
ButterKnife.bind(this, view);
Log.i("TAG","onCreateView--Fragment2");
return view;
}
@Override
public void onDestroyView() {
super.onDestroyView();
ButterKnife.unbind(this);
}
//方法3:通过fragment实例调用其公共方法,并且在activity中传入myToastListener实例。
@OnClick(R.id.btnToast)
public void onClick() {
if (myToastListener==null) return;
myToastListener.onToastClick();
}
public void setOnMyToastListener(MyToastListener m){
this.myToastListener=m;
}
public interface MyToastListener{
void onToastClick();
}
}
Fragment2中只有一个Button。通过点击这个Button与Activity通信。
最后,Activity:
package com.wy.fragmentpractice.activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import android.widget.Toast;
import com.wy.fragmentpractice.R;
import com.wy.fragmentpractice.fragment.Fragment1;
import com.wy.fragmentpractice.fragment.Fragment2;
import butterknife.Bind;
import butterknife.ButterKnife;
public class MainActivity extends AppCompatActivity implements Fragment1.MClickListener {
@Bind(R.id.tvText)
TextView tvText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
FragmentManager fm=getFragmentManager();
FragmentTransaction transaction=fm.beginTransaction();
Fragment2 fragment2=new Fragment2();
transaction.add(R.id.lnToast,fragment2);
transaction.commit();
fragment2.setOnMyToastListener(new Fragment2.MyToastListener() {
@Override
public void onToastClick() {
Toast.makeText(MainActivity.this,"现在的大小是:"+tvText.getText().toString(),
Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void setOnAddClick() {
int a = Integer.parseInt(tvText.getText().toString()) - 1;
String res = String.valueOf(a);
tvText.setText(res);
}
@Override
public void setOnDeleteClick() {
int a = Integer.parseInt(tvText.getText().toString()) + 1;
String res = String.valueOf(a);
tvText.setText(res);
}
}
activity的布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.MainActivity">
<TextView
android:id="@+id/tvText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:layout_centerHorizontal="true"
android:textStyle="bold"
android:text="1" />
<fragment
android:id="@+id/fragment1"
android:name="com.wy.fragmentpractice.fragment.Fragment1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:layout="@layout/fragment1"
android:layout_below="@+id/tvText"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
/>
<LinearLayout
android:id="@+id/lnToast"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_below="@+id/fragment1"
>
</LinearLayout>
</RelativeLayout>
Activity中从上到下是:一个显示数字的TextView,一个静态的Fragment1,一个用来动态显示Fragment2的线性布局。点击Fragment1中的左边按钮,TextView显示数字-1,点击右边的按钮,TextView显示数字+1,点击Fragment2的按钮,弹出Toast,说明当前TextView中的数字是多少。
二、关于savedInstanceState
在测试的时候,多次旋转手机屏幕,会发现在AS打印出的Log信息中,onCreateView–Fragment1只会出现一次,而onCreateView–Fragment2会随着旋转的次数增加而增加,每转一次,增加一条。出现这种情况的原因是:当屏幕旋转时,MainActivity会重新启动,其中已存在的默认Fragment2也会随之重启,这就造成了当存在的Fragment2重启时,会在MainActivity中的onCreate()方法中创建一个Fragment2实例。不断旋转屏幕,Fragment2实例越来越多。静态使用的Fragment1为什么不会出现这种问题呢?我得想想。
解决办法是,在activity中的onCreate()方法中,判断savedInstanceState是否为null,从而决定是否创建Fragment实例。
修改MainActivity:
package com.wy.fragmentpractice.activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import android.widget.Toast;
import com.wy.fragmentpractice.R;
import com.wy.fragmentpractice.fragment.Fragment1;
import com.wy.fragmentpractice.fragment.Fragment2;
import butterknife.Bind;
import butterknife.ButterKnife;
public class MainActivity extends AppCompatActivity implements Fragment1.MClickListener {
@Bind(R.id.tvText)
TextView tvText;
Fragment2 fragment2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
if (savedInstanceState==null) {
FragmentManager fm = getFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
fragment2=new Fragment2();
transaction.add(R.id.lnToast, fragment2);
transaction.commit();
}
if (fragment2!=null){
setOnClick(fragment2);
}else{
fragment2= (Fragment2) getFragmentManager().findFragmentById(R.id.lnToast);
setOnClick(fragment2);
}
}
private void setOnClick(Fragment2 fragment){
fragment.setOnMyToastListener(new Fragment2.MyToastListener() {
@Override
public void onToastClick() {
Toast.makeText(MainActivity.this,"现在的大小是:"+tvText.getText().toString(),
Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void setOnAddClick() {
int a = Integer.parseInt(tvText.getText().toString()) - 1;
String res = String.valueOf(a);
tvText.setText(res);
}
@Override
public void setOnDeleteClick() {
int a = Integer.parseInt(tvText.getText().toString()) + 1;
String res = String.valueOf(a);
tvText.setText(res);
}
}
代码能实现旋转屏幕正确显示,点击事件正确调用。