【问题标题】:Drawing fragment over main activity在主要活动上绘制片段
【发布时间】:2016-06-23 12:56:09
【问题描述】:

我是开发 android 应用程序的新手,所以请原谅我可能犯的任何愚蠢的错误。关于这个问题: 我正在制作一个应用程序,它的主要活动布局屏幕包含一些东西,并连接了一个导航抽屉。现在我正在尝试使用导航抽屉中的条目来调用各种片段并将它们显示在我的主要活动上。但是,当我运行我的一段代码时,我收到了 Activity Destroyed 错误,我在下面附上了我的代码以供参考。我认为问题在于我对容器所做的事情。为了让片段覆盖我的主要活动的整个屏幕,我将片段容器作为根布局,因为我不确定如何去做。

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

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);
}

片段代码

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);
}

主要活动的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)

我想知道如何使片段在主要活动布局上绘制而不会造成混乱

提前干杯和感谢

【问题讨论】:

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


    【解决方案1】:
        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);
    

    ad 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 - 这是一个持有的视图:

    • FrameLayout / 带有 id - >content_frame

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

            ( list view for example with  menu entries  )
      

    所以你你需要替换 content_frame

    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. 您还需要将 args 放入片段中:

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

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

    注意: 片段事务只能在活动保存其状态之前创建/提交。

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

    • Activity.onSaveInstanceState()

    和之前的一个

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

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

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

    如果您想立即执行任何此类挂起的操作,您可以调用此函数(仅从主线程)来执行此操作。请注意,所有回调和其他相关行为都将在此调用中完成,因此请注意从何处调用它。

    boolean 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/

    (未重置状态的子片段问题)

    嗨,感谢详细的解释,但它不起作用 – Prejith P

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

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

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

     commitAllowingStateLoss()
    

    嗨,我刚刚自己修好了。我稍微改变了导航抽屉的实现,它才开始工作。我不知道它是如何解决的,这就是为什么我没有在这里发布答案 - Prejith P

    是的 - 问题是您的实现在活动实例被销毁后尝试调用 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() 你应该确保

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

    【讨论】:

    • 您好,感谢您的回答。你说的很有道理,但我仍然遇到和以前一样的错误。我在布局中添加了 content_frame,然后用它替换了片段容器
    • 嗨,感谢详细的解释,但它不起作用
    • @PrejithP - 查看最后一个链接
    • 嗨,我刚刚自己修好了。我稍微改变了导航抽屉的实现,它才开始工作。我不知道它是如何解决的,这就是为什么我没有在这里发布答案
    • @PrejithP - 再读一遍我写的内容,你就会知道问题出在哪里(尤其是粗体部分)
    【解决方案2】:

    问题是您在提交替换后调用transaction.addToBackStack(null);。我建议你这样做:

    getSupportFragmentManager().beginTransaction()
    .replace(R.id.drawer_layout, mFragment).addToBackStack(null).apply();
    

    【讨论】:

    • 嗨,你的 .apply() 是什么意思?
    • 弄糊涂了,直接用 .commit()
    • this 可能有帮助
    • 伙计,这与我面临的问题完全相同。我刚才尝试了所有这些解决方案,但仍然无法正常工作。
    【解决方案3】:

    你需要一个片段来片段通信

      class DetailActivity extends 
    
     AppCompatActivity implements BioDetailClickView {
    @Override
       protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        setContentView(R.layout.activity_detail);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        toolbar.setNavigationIcon(R.drawable.navigation);
        setSupportActionBar(toolbar);
        FragmentManager fm = getSupportFragmentManager();
        Fragment fragment = fm.findFragmentById(R.id.fragment_container);
    
        if (fragment == null) {
            fragment = new Fragment1();
            fm.beginTransaction()
                    .add(R.id.fragment_container, fragment)
                    .commit();
        }
    
    }
    
    public void fragment_transaction(Fragment fragment){
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.fragment_container, fragment);
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.commit();
    }
    
    
    @Override
    public void onClickFragmentQuick() {
    
        Fragment frag= new Fragment1();
      fragment_transaction(frag);
    }
    
    @Override
    public void onClickFragment2() {
    
        Fragment fragment =new Fragment2();
        fragment_transaction(fragment);
    
    }
    
    @Override
    public void onClickFragment3() {
    
        Fragment fragment =new Fragment3();
        fragment_transaction(fragment);
    
    }
    
       public interface BioDetailClickView  {
        void onClickFragment1();
        void onClickFragment2();
         void onClickFragment3();
    
    
     }
    

    【讨论】:

      猜你喜欢
      • 2022-01-25
      • 1970-01-01
      • 2021-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-13
      • 2016-08-17
      相关资源
      最近更新 更多