片段未创建视图

18

MyFragment.java

public class MyFragment extends Fragment {
    private onItemSelectedListener listener;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment, container,
                false);
        btn_myButton = (Button) view.findViewById(R.id.btn_new_client);
        btn_myButton .setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                updateDetail("New Layout");
            }
        });
        return view;
    }

    Button btn_myButton;

    public interface onItemSelectedListener {
        public void onItemSelected(String link);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        if (activity instanceof onItemSelectedListener) {
            listener = (onItemSelectedListener) activity;
        } else {
            throw new ClassCastException(activity.toString()
                    + " must implemenet OnItemSelectedListener");
        }
    }
    public void updateDetail(String s) {
        listener.onItemSelected(s);
    }
}

MainActivity.java

public class MainActivity extends Activity implements
    onItemSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.main_activity);
    super.onCreate(savedInstanceState);
}

public void onItemSelected(String link) {
    FragmentManager manager = getFragmentManager();
    FragmentTransaction transaction = manager.beginTransaction();
    Fragment fragment;
    if ("New Layout".equals(link)) {
        fragment = new Fragment1();
        transaction.replace(R.id.detailFragment, fragment);
        transaction.commit();
    }
}
}

Fragment1.java

public class Fragment1 extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.newfragmentt, container,
                false);
        return v;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
    }
}

fragment.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" >

    <Button
        android:id="@+id/btn_new_client"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:ems="8"
        android:gravity="center|center_vertical"
        android:padding="2dp"
        android:text="@string/new_client"
        android:textColor="#FFFFFF" >
    </Button>

</LinearLayout>

主活动界面布局文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#4B6C9E"
    android:baselineAligned="false"
    android:orientation="horizontal" >

    <fragment        
        android:id="@+id/FragmentId"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="1"
        class="com.examples.MyProject.MyFragment" >
    </fragment>
    <FrameLayout
        android:id="@+id/detailFragment"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="2" >
    </FrameLayout>

</LinearLayout>

LogCat 错误:

 FATAL EXCEPTION: main
 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.elintsys.iCaseDiary/com.examples.MyProject.MainActivity}: android.view.InflateException: Binary XML file line #8: Error inflating class fragment
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
    at android.app.ActivityThread.access$600(ActivityThread.java:123)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4424)
    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:784)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
    at dalvik.system.NativeStart.main(Native Method)
 Caused by: android.view.InflateException: Binary XML file line #8: Error inflating class fragment
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:697)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:739)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:251)
    at android.app.Activity.setContentView(Activity.java:1862)
    at com.examples.MyProject.MainActivity.onCreate(CaseEntryActivity.java:15)
    at android.app.Activity.performCreate(Activity.java:4492)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1049)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1920)
    ... 11 more
 Caused by: java.lang.IllegalStateException: Fragment com.elintsys.iCaseDiary.CaseEntryFragment did not create a view.
    at android.app.Activity.onCreateView(Activity.java:4293)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:673)
    ... 21 more
 Sending signal. PID: 16275 SIG: 9

请朋友们帮帮我。


你需要反转这个 setContentView(R.layout.main_activity); super.onCreate(savedInstanceState)。先调用super,然后再调用setContentView。 - Raghunandan
4个回答

17

你需要将这个反转:

setContentView(R.layout.main_activity); 
super.onCreate(savedInstanceState). 

变成这样:

super.onCreate(savedInstanceState). 
setContentView(R.layout.main_activity); 

在您的活动的onCreate方法中。


有什么想法为什么会这样吗?我总是把super.onCreate(savedInstanceState)放在我的Activities的onCreate方法的最后一个语句。 - Jason Oviedo
@Mark 这里有一个链接 https://groups.google.com/forum/#!msg/android-developers/wGt4qiwLy3Y/BwRGmRgDX08J,还有一个链接 https://dev59.com/fmw05IYBdhLWcg3whCJn。一定要看看 Dianne Hackborn 的评论。 - Raghunandan

3
即使我在super.onCreate之后调用了setContentView,我仍然遇到了这个错误。在我的情况下,我在父类的onCreate方法中设置了一个工作片段,它在调用setContentView之前被调用,并触发了此处记录的错误:https://code.google.com/p/android/issues/detail?id=22564
为了解决这个问题,我不得不将工作片段的初始化移动到稍后在活动生命周期中调用的单独方法中。
按照要求,以下是该代码的样子:
public class BaseActivity extends ActionBarActivity {

    private static final String TAG_TASK_FRAGMENT = "task_fragment";

    protected TaskFragment taskFragment; // Used to hold a reference to the active activity between config changes

    protected void setupTaskFragment() {
        // It would be great if we could just do this in onCreate, but setting up the task fragment
        // before calling setContentView() triggers the bug described here:
        //
        // https://code.google.com/p/android/issues/detail?id=22564
        //
        // So we just need to make sure Activities that run async tasks call this setup function
        // before they do.

        FragmentManager fm = getSupportFragmentManager();
        taskFragment = (TaskFragment) fm.findFragmentByTag(TAG_TASK_FRAGMENT);

        // If the Fragment is non-null, then it is currently being
        // retained across a configuration change.
        if (taskFragment == null) {
            taskFragment = new TaskFragment();
            fm.beginTransaction().add(taskFragment, TAG_TASK_FRAGMENT).commit();
            fm.executePendingTransactions();
        }

    }

}

public class ChildActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);  // If this call adds a fragment, you will have problems
        setContentView(R.layout.activity_child);
        setupTaskFragment(); // So we have to add our task fragment here, after we've called setContentView()

        // further initialization here
    }

}

/**
 *
 *  TaskFragment
 *
 * We use this fragment to manage async tasks between configuration changes.  The fragment calls
 * setRetainInstance(true) in its constructor, which makes it so that it will not be recreated
 * between configuration events (like screen rotation).  Async tasks running from the fragment 
 * can then be kept up to date on which activity they belong to.
 */

public class TaskFragment extends Fragment {

    private ArrayList<AsyncTask> asyncTasks = new ArrayList<AsyncTask>();

    public TaskFragment() {
        super();
        setRetainInstance(true);
    }

    public void addTask(AsyncTask task) {
        asyncTasks.add(task);
    }

    public void removeTask(AsyncTask task) {
        asyncTasks.remove(task);
    }

    public Application getApplication() {
        Activity activity = getActivity();
        if (activity != null)
            return activity.getApplication();
        else
            return null;
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        for (AsyncTask task : asyncTasks) {
            task.onAttach(activity);
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        for (AsyncTask task : asyncTasks) {
            task.onDetach();
        }
    }
}

我添加了一个代码示例,展示了我所做的事情。 - Mel Stanley

1

我遇到了同样的问题,但已经使用了 setContentViewsuper.onCreate。在我的片段活动中添加以下内容可以解决这个问题:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
   super.onActivityCreated(savedInstanceState);
}

在我进一步开展项目时,这个问题仍然存在,第二次修复是替换:
    <fragment
    android:id="@+id/output"
    class=".Fragment_1"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

带有:

    <FrameLayout
    android:id="@+id/fragment_frame_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name=".Fragment_1"
        android:id="@+id/fragment"
        tools:layout="@layout/fragment_two" />
    </FrameLayout>

显然,“您无法替换在xml布局文件中静态放置的片段”,如在这个问题的答案中发现:Android - fragment .replace() doesn't replace content - puts it on top

1
除了Mel Stanley所说的,您还需要确保在加载片段的xml活动中添加android:tag:
<fragment
android:id="@+id/fragment_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:name="com.your_app.name.fragments.NameOfFragment"
android:tag="fragment_tag"
tools:layout="@layout/layout_fragment" 
/>

这样做可以确保在使用xml首次加载片段时,不会使用Mel的代码重新加载。如果您省略此步骤,则在第一次运行时会有两次片段加载 - 如果您有异步请求在完成后更改布局,这将是一个问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接