[android]与 ViewPager fragment里面fragment和 FragmentStatePagerAdapter 的结果,在异常 (与完整的示例)

来源:互联网 发布:辐射3 知乎 编辑:程序博客网 时间:2024/06/05 19:50

我有一个简单的片段与 ViewPager。

我使用最新的支持库、 v4 rev18 !

如果我第一次显示的子片段,一切工作正常,如果回去,并显示它,应用程序崩溃有以下例外:

我有一个完整的示例,其中显示了以下异常时出现:

java.lang.NullPointerException
at android
.support.v4.app.FragmentManagerImpl.getFragment(FragmentManager.java:569)
at android
.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java:211)
at android
.support.v4.view.ViewPager.onRestoreInstanceState(ViewPager.java:1281)
at android
.view.View.dispatchRestoreInstanceState(View.java:12043)
at android
.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2688)
at android
.view.ViewGroup.dispatchRestoreInstanceState(ViewGroup.java:2694)
at android
.view.View.restoreHierarchyState(View.java:12021)
at android
.support.v4.app.Fragment.restoreViewState(Fragment.java:425)
at android
.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:949)
at android
.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
at android
.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
at android
.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1460)
at android
.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440)
at android
.os.Handler.handleCallback(Handler.java:615)
at android
.os.Handler.dispatchMessage(Handler.java:92)
at android
.os.Looper.loop(Looper.java:137)
at android
.app.ActivityThread.main(ActivityThread.java:4800)
at java
.lang.reflect.Method.invokeNative(Native Method)
at java
.lang.reflect.Method.invoke(Method.java:511)
at com
.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:798)
at com
.android.internal.os.ZygoteInit.main(ZygoteInit.java:565)
at dalvik
.system.NativeStart.main(Native Method)

我能够在每个其他的方式,一个孩子片段中使用 ViewPager,但我不能让它工作如果我添加/删除子片段手动和使用 FragmentStatePagerAdapter 中子片段......

下面的示例应正常工作,但这不重要...我已经添加了一些代码,解决了一些问题,但它不能解决所有的问题......

import java.lang.reflect.Field;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.TextView;

public class TestActivity extends FragmentActivity implements OnClickListener
{
   
private Fragment fragment1;
   
private Fragment fragment2;

   
public void onCreate(Bundle savedInstanceState)
   
{
       
super.onCreate(savedInstanceState);
        setContentView
(R.layout.test_main);

        fragment1
= getSupportFragmentManager().findFragmentByTag("fragment1");
        fragment2
= getSupportFragmentManager().findFragmentByTag("fragment2");
   
}

   
@Override
   
public void onClick(View v)
   
{
       
Fragment nextFragment = null;
       
String nextFragmentTag = null;
       
if (v.getId() == R.id.button1)
       
{
           
if (fragment1 == null)
                fragment1
= ContainerFragment.newInstance(1);
            nextFragment
= fragment1;
            nextFragmentTag
= "fragment1";
       
}
       
else if (v.getId() == R.id.button2)
       
{
           
if (fragment2 == null)
                fragment2
= ContainerFragment.newInstance(2);
            nextFragment
= fragment2;
            nextFragmentTag
= "fragment2";
       
}

       
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction
.replace(R.id.main, nextFragment, nextFragmentTag);
        transaction
.addToBackStack(null);
        transaction
.commit();
   
}

   
public static class MainPagerAdapter extends FragmentStatePagerAdapter
   
{
       
public int button;

       
public MainPagerAdapter(FragmentManager fm)
       
{
           
super(fm);
       
}

       
@Override
       
public Fragment getItem(int i)
       
{
           
return SubFragment.newInstance(button, i);
       
}

       
@Override
       
public int getCount()
       
{
           
return 10;
       
}
   
}

   
public static class ContainerFragment extends Fragment
   
{

       
static ContainerFragment newInstance(int pos)
       
{
           
ContainerFragment f = new ContainerFragment();
           
Bundle args = new Bundle();
            args
.putInt("pos", pos);
            f
.setArguments(args);
           
return f;
       
}

       
@Override
       
public View onCreateView(LayoutInflater inflater, ViewGroup container,
               
Bundle savedInstanceState)
       
{
           
View rootView = inflater.inflate(R.layout.view_pager, container, false);
           
ViewPager pager = (ViewPager) rootView.findViewById(R.id.pager);
           
MainPagerAdapter adapter = new MainPagerAdapter(getChildFragmentManager());
            adapter
.button = getArguments().getInt("pos");
            pager
.setAdapter(adapter);
           
return rootView;
       
}

       
// ---------------------------------------------------------------
       
// HACK FIX für java.lang.IllegalStateException: No activity
       
// ---------------------------------------------------------------

       
private static final Field sChildFragmentManagerField;
       
static
       
{
           
Field f = null;
           
try
           
{
                f
= android.support.v4.app.Fragment.class.getDeclaredField("mChildFragmentManager");
                f
.setAccessible(true);
           
}
           
catch (NoSuchFieldException e)
           
{
           
}
            sChildFragmentManagerField
= f;
       
}

       
@Override
       
public void onDetach()
       
{
           
super.onDetach();

           
if (sChildFragmentManagerField != null)
           
{
               
try
               
{
                    sChildFragmentManagerField
.set(this, null);
               
}
               
catch (Exception e)
               
{
               
}
           
}
       
}
   
}

   
public static class SubFragment extends Fragment
   
{
       
static SubFragment newInstance(int button, int pos)
       
{
           
SubFragment f = new SubFragment();
           
Bundle args = new Bundle();
            args
.putString("key", "Button " + button + "Fragment " + pos);
            f
.setArguments(args);
           
return f;
       
}

       
@Override
       
public View onCreateView(LayoutInflater inflater, ViewGroup container,
               
Bundle savedInstanceState)
       
{
           
View rootView = inflater.inflate(R.layout.test_subfragment, container, false);
           
((TextView) rootView.findViewById(R.id.tv1)).setText(getArguments().getString("key"));
           
return rootView;
       
}
   
}
}

为完整起见,我将添加的 xml 文件,以及:

test_main.xml

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

   
<LinearLayout
       
android:layout_width="match_parent"
       
android:layout_height="match_parent"
       
android:orientation="vertical" >

       
<Button
           
android:id="@+id/button1"
           
android:layout_width="wrap_content"
           
android:layout_height="wrap_content"
           
android:onClick="onClick"
           
android:text="Button1" />

       
<Button
           
android:id="@+id/button2"
           
android:layout_width="wrap_content"
           
android:layout_height="wrap_content"
           
android:onClick="onClick"
           
android:text="Button2" />
   
</LinearLayout>

</FrameLayout>

test_subfragment.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
   
android:id="@+id/tv1"
   
android:layout_width="match_parent"
   
android:layout_height="match_parent"
   
android:gravity="center"
   
android:textSize="50sp" />

view_pager.xml

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

   
<android.support.v4.view.ViewPager
       
android:id="@+id/pager"
       
android:layout_width="match_parent"
       
android:layout_height="wrap_content" />

</LinearLayout>

解决方法 1:

添加到您的布局额外 FrameLayout的主要活动。这是你把该片段放哪里。

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

   
<LinearLayout
       
android:layout_width="match_parent"
       
android:layout_height="wrap_content"
       
android:orientation="vertical" >

       
<Button
           
android:id="@+id/button1"
           
android:layout_width="wrap_content"
           
android:layout_height="wrap_content"
           
android:onClick="onClick"
           
android:text="Button1" />

       
<Button
           
android:id="@+id/button2"
           
android:layout_width="wrap_content"
           
android:layout_height="wrap_content"
           
android:onClick="onClick"
           
android:text="Button2" />
 
<!-- add this -->
       
<FrameLayout
           
android:id="@+id/fragment_frame"
           
android:layout_width="match_parent"
           
android:layout_height="match_parent" >

       
</FrameLayout>

   
</LinearLayout>

</FrameLayout>

既然你将你片段添加到BackStack,他们无需为保存一个实例。这是为什么你的应用程序崩溃的原因。调整您 onClick() 方法,如下所示:

    @Override
   
public void onClick(View v)
   
{
       
Fragment nextFragment = null;
       
String nextFragmentTag = null;
       
if (v.getId() == R.id.button1)
       
{
            nextFragment
= ContainerFragment.newInstance(1);
            nextFragmentTag
= "fragment1";
       
}
       
else if (v.getId() == R.id.button2)
       
{
            nextFragment
= ContainerFragment.newInstance(2);
            nextFragmentTag
= "fragment2";
       
}

       
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
        transaction
.replace(R.id.fragment_frame, nextFragment, nextFragmentTag);
        transaction
.addToBackStack(null);
        transaction
.commit();
   
}

我测试的代码。更改按钮工程,而ViewPager 留状态时保留对它麦洁片段。

0 0
原创粉丝点击