android - 在主要 Activity 上绘制 fragment

标签 android android-layout android-fragments android-activity navigation-drawer

我是开发 Android 应用程序的新手,所以请原谅我可能犯的任何愚蠢的错误。关于问题: 我正在制作一个应用程序,其主 Activity 布局屏幕包含一些内容,并连接了一个抽屉导航。现在我尝试使用抽屉导航中的条目来调用各种 fragment 并将它们显示在我的主要 Activity 上。但是,当我运行我的代码时,我收到 Activity 被破坏错误,我已在下面附上我的代码以供引用。我认为问题出在我对容器所做的事情上。为了使 fragment 覆盖我的主要 Activity 的整个屏幕,我将 fragment 容器作为根布局,因为我不确定如何进行此操作。

处理抽屉导航中的项目点击的代码

class DrawerItemClickListener extends FragmentActivity implements ListView.OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    selectItem(position);
}

private void selectItem(int position) {
    Fragment mFragment = null;
    switch(position) {
        case 0:
            mFragment = new AnnouncementFragment();
            Bundle args = new Bundle();
            args.putInt(null, position);
            break;
        case 1:
            break;
        case 2:
            break;
        case 3:
            break;
        default:
            break;
    }
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction().replace(R.id.drawer_layout, mFragment);
    transaction.commit();
    transaction.addToBackStack(null);
}

fragment 代码

public class AnnouncementFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_announcement, container, false);
}

主要 Activity 的 XML 布局

<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">

<RelativeLayout
    android:id = "@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/screen_login"
        android:gravity="center"
        android:textColor="@android:color/holo_blue_light"
        android:id="@+id/login_tv"
        android:layout_alignParentTop="true"
        android:layout_marginTop="105dp"
        android:layout_alignParentEnd="true"
        android:layout_alignParentStart="true"
        android:textSize="40sp" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/username_et"
        android:layout_below="@id/login_tv"
        android:layout_alignParentStart="true"
        android:layout_marginTop="45dp"
        android:layout_alignParentEnd="true"
        android:hint="@string/username"/>

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:inputType="textPassword"
        android:ems="10"
        android:id="@+id/editText2"
        android:layout_below="@id/username_et"
        android:layout_alignParentStart="true"
        android:layout_marginTop="30dp"
        android:layout_alignParentEnd="true"
        android:hint="@string/password" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/login"
        android:id="@+id/login_btn"
        android:layout_below="@+id/editText2"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="25dp" />

</RelativeLayout>

<ListView
    android:id="@+id/drawer_list"
    android:layout_width="200dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:background="#ffeeeeee"/>

错误

java.lang.IllegalStateException: Activity has been destroyed
                                                               at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1399)
                                                               at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:637)
                                                               at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:616)
                                                               at com.it.learnera.DrawerItemClickListener.selectItem(DrawerItemClickListener.java:40)
                                                               at com.it.learnera.DrawerItemClickListener.onItemClick(DrawerItemClickListener.java:19)

我想知道如何使 fragment 绘制在主 Activity 布局上而不造成困惑

提前干杯并表示感谢

最佳答案

    FragmentTransaction transaction = getSupportFragmentManager()
              .beginTransaction()
              .replace(R.id.drawer_layout, mFragment);   // < - first problem ( see ad. 1)
              .commit()  // <-  third problem (see ad. 3)

        // second problem ( see ad. 2)
        mFragment = new AnnouncementFragment();
        Bundle args = new Bundle();
        args.putInt(null, position);

广告 1. 替换 DrawerLayout 而不是它的容器

<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- The main content view -->
<FrameLayout
    android:id="@+id/content_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
<!-- The navigation drawer -->
<ListView android:id="@+id/left_drawer"
    android:layout_width="240dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:choiceMode="singleChoice"
    android:divider="@android:color/transparent"
    android:dividerHeight="0dp"
    android:background="#111"/>

drawer_layou - 这是一个包含以下内容的 View :

  • FrameLayout/带 id ->content_frame

           ( container capable to hold "only" one element: fragment / view) 
    
  • ListView/带id->left_drawer

          ( list view for example with  menu entries  )
    

所以你需要替换 content_frame

enter image description here

ps 为了更好地了解交易的目的,您应该在一个语句中调用它 - 在“链/序列”中

    FragmentTransaction transaction = getSupportFragmentManager()
              .beginTransaction()
              .replace(R.id.frame_layout, mFragment)
              .addToBackStack(null)   // add to manager " will remember this fragment  - for navigation purpose"
              .commit()   // commit mean do everything from top to bottom on next pass 

ad 2.您还需要将参数放入 fragment 中:

        mFragment = new AnnouncementFragment();
        Bundle args = new Bundle();
        args.putInt(null, position);
        mFragment.setArguments(args)

ad 3. 当 Activity 在 onSaveInstanceState 之后调用 commit

Note: A fragment transaction can only be created/committed prior to an activity saving its state.

如果您尝试在以下时间后提交事务:

  • Activity.onSaveInstanceState()

以及在以下内容之前

  • Activity.onStart()
  • Activity.onResume()

你会得到一个错误。这是因为框架负责保存状态中当前的 fragment ,如果在保存状态后进行更改,那么它们将会丢失。

使用 FragmentTransaction.commit() 提交 FragmentTransaction 后,计划在进程的主线程上异步执行

If you want to immediately executing any such pending operations, you can call this function (only from the main thread) to do so. Note that all callbacks and other related behavior will be done from within this call, so be careful about where this is called from.

bool 值executePendingTransactions();

  • 如果有任何待执行的交易,则返回 true。

顺便看看这个文档,它指的是扩展 FragmentActivity:

https://developer.android.com/reference/android/support/v4/app/FragmentActivity.html

我不知道您的目标是哪个 api,但您也可以检查此错误:

http://johnfeng.github.io/blog/2015/05/31/fragment-activity-has-been-destoryed-problem/

(子 fragment 的问题,其状态没有被重置)

Hi, appreciate the detailed explanation but it doesnt work – Prejith P

这篇关于状态损失的文章我认为与您的问题有关

http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html

所以你可以尝试调用而不是commit()(但这不是解决方案):

 commitAllowingStateLoss()

Hi, I fixed it myself just now. I changed the implementation of my navigation drawer a bit and it just started working. I have no idea how it got fixed, which is why I haven't posted an answer here – Prejith P

是 - 问题是您在 Activity 实例被销毁后尝试调用 commit() 的实现,堆栈跟踪表明了这一点

java.lang.IllegalStateException: Activity has been destroyed
 at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1399)
 at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:637)
 at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:616)
 at com.it.learnera.DrawerItemClickListener.selectItem(DrawerItemClickListener.java:40)
 at com.it.learnera.DrawerItemClickListener.onItemClick(DrawerItemClickListener.java:19)
                                                 `

当您调用 commit() 时您应该确保:

  • Activity 已附加
  • Activity 可见(在 onSaveInstanceState 之前)

关于android - 在主要 Activity 上绘制 fragment ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37992311/

相关文章:

java - 使用 RecyclerView 在屏幕上显示特定数量的列表

android - 为什么冒号在空格之前被认为是空格但在冒号之后它在 Android 中不被考虑

java - 一个Activity和多个Fragment之间通过接口(interface)进行通信

java - 如何更改Android中的Fragment

android - 我可以对位图进行 Activity 吗?

android - 在没有SIM卡的情况下向本地Android手机发送短信?

java - 某些设备(如 oppo、vivo、MI 等)的前台服务在 Doze 模式下被杀死

android - ActionBarSherlock:如何绕过 4.x 设备的 Holo 主题?

android - RelativeLayout 项目在编辑器和设备上的不同位置

android - Robolectric 不使用 ShadowWebView 作为扩展 WebView 的类的父类(super class)。 MustOverrideException 代替