在主要活动上绘制片段

时间:2016-06-23 12:56:10

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

我是开发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)

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

欢呼并提前致谢

3 个答案:

答案 0 :(得分:3)

    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 / with id - &gt; content_frame

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

          ( list view for example with  menu entries  )
    

所以你你需要替换content_frame

enter image description here

ps更好地了解交易的目的,你应该在一个声明中调用它 - 在&#34;链/序列&#34;

    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.当活动在onSaveInstanceState

之后调用commit
  

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

如果您尝试在以下情况后提交交易:

  • Activity.onSaveInstanceState()

以及之后的

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

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

在使用FragmentTransaction.com传递 FragmentTransaction之后,计划在进程的主线程上异步执行

  

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

布尔值executePendingTransactions();

  • 如果有待执行的待处理事务,则返回true。

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

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

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

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之前)

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

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

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


 }