android-fragments 碎片工作不正常(可能发生膨胀错误)(Android)

lymnna71  于 2022-11-13  发布在  Android
关注(0)|答案(1)|浏览(142)

activity_main中,我有一个FrameLayout。我希望当我按下一个按钮时,一个CalcFragment会弹出,当我按下另一个按钮时,一个GraphFragment会弹出。我还希望CalcFragment是应用程序第一次启动时出现的东西。我还没有创建GraphFragment,因为我还在努力使CalcFragment正常工作。
当我使用一个片段而不是FrameLayout,并手动告诉片段显示CalcFragment时,我的所有代码都能正常工作。
下面是CalcFragment.java的代码:

import android.os.Bundle;

import androidx.fragment.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class CalcFragment extends Fragment {

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

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_calc, container, false);
    }
}

下面是MainActivity.javaonCreate函数中的一段代码,它被假定为将CalcFragment放入FrameLayout

Fragment calcFragment = new CalcFragment();
Fragment graphFragment = new GraphFragment();

FragmentTransaction fragTrans = getSupportFragmentManager().beginTransaction();

fragTrans.replace(R.id.frag_container, calcFragment);
fragTrans.addToBackStack(null);
fragTrans.commit();

在这段代码之后是一堆代码,它们设置了CalcFragment中所有按钮的功能。(片段中的元素)不存在。即使如此,如果我删除代码,UI元素显然是存在的。我猜这是一个膨胀错误,并且由于某种原因,代码在使用main Activity中的UI元素填充片段中的UI元素时遇到了问题。我想,我真的不知道。我还尝试将所有这些代码移到CalcFragment.javaonCreate函数中,但这反过来又产生了一系列我甚至无法理解的问题。我只是勉强知道片段是如何工作的,我只是在做2个YouTube教程告诉我的好主意。
请帮帮忙,我不知道发生了什么事。谢谢!
编辑:这里有一个谷歌驱动器的链接,如果你想看到任何其他的项目。
https://drive.google.com/drive/folders/1E3inSfdbKkTFjX44pWBBRt545rs34C4q?usp=sharing
或者,如果你不想使用google drive,这里是整个项目的每一行代码:
MainActivity.java:

package com.example.chrisscalculator2;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;

import android.text.*;
import android.view.inputmethod.InputMethodManager;
import android.widget.*;

import android.view.*;

import java.util.HashMap;

import complexnumbers.*;

//import android.*;

public class MainActivity extends AppCompatActivity {

    public static int historyDepth = 100; //how many entries in equation history
    public static int clearCount = 0;     //how many times we've hit the clear button in a row
    public static boolean dotPress = false; //how many times we've hit the . button in a row (false=even, true=odd)
    public static boolean ePress = false; //how many times we've hit the e button in a row (false=even, true=odd)

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);

        getWindow().setNavigationBarColor(Color.parseColor("#000000"));

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

        //LayoutInflater inflater = getLayoutInflater();
        //View graphLayout = inflater.inflate(R.layout.graph_layout, null);

        Fragment calcFragment = new CalcFragment();
        //Fragment graphFragment = new GraphFragment();

        FragmentTransaction fragTrans = getSupportFragmentManager().beginTransaction();

        fragTrans.replace(R.id.frag_container, calcFragment);
        fragTrans.addToBackStack(null);
        fragTrans.commit();

        final boolean[] secKeys = {false};

        EditText calc_inp = (EditText) findViewById(R.id.calc_input);

        calc_inp.setShowSoftInputOnFocus(false);

    }
}

活动_主.xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main_layout"
    android:layout_width="1080px"
    android:layout_height="2340px"
    android:background="#000000"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/graph_button_1"
        android:layout_width="240px"
        android:layout_height="90px"
        android:backgroundTint="#0000FF"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:paddingLeft="0dp"
        android:paddingTop="0dp"
        android:paddingRight="0dp"
        android:paddingBottom="0dp"
        android:text="Graph"
        android:textAllCaps="false"
        android:textSize="42px"
        app:layout_constraintStart_toEndOf="@+id/equations_button_1"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/calc_button_1"
        android:layout_width="240px"
        android:layout_height="90px"
        android:backgroundTint="#0000FF"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:paddingLeft="0dp"
        android:paddingTop="0dp"
        android:paddingRight="0dp"
        android:paddingBottom="0dp"
        android:text="Calc"
        android:textAllCaps="false"
        android:textSize="42px"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/equations_button_1"
        android:layout_width="240px"
        android:layout_height="90px"
        android:backgroundTint="#0000FF"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:paddingLeft="0dp"
        android:paddingTop="0dp"
        android:paddingRight="0dp"
        android:paddingBottom="0dp"
        android:text="Equations"
        android:textAllCaps="false"
        android:textSize="42px"
        app:layout_constraintStart_toEndOf="@+id/calc_button_1"
        app:layout_constraintTop_toTopOf="parent" />

    <FrameLayout
        android:id="@+id/frag_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/equations_button_1"
        app:layout_constraintVertical_bias="1.0" />

</androidx.constraintlayout.widget.ConstraintLayout>

下面是fragment_calc.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/fragment_calc_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000000"
    tools:context=".CalcFragment">

    <EditText
        android:id="@+id/calc_input"
        android:layout_width="0dp"
        android:layout_height="135px"
        android:layout_marginBottom="30px"
        android:background="@drawable/shape"
        android:ems="10"
        android:inputType="none"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:textColor="#00FFFF"

        android:textSize="54px"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        tools:ignore="SpeakableTextPresentCheck" />

</android.support.constraint.ConstraintLayout>

请访问CalcFragment.java:

package com.example.chrisscalculator2;

import android.os.Bundle;

import androidx.fragment.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class CalcFragment extends Fragment {

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

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_calc, container, false);
    }
}

我知道我用的是像素而不是dp。相信我,我有一个非常非常非常非常非常非常好的理由。

dsekswqp

dsekswqp1#

由于我要求的信息在编辑历史记录中,我将向您说明问题所在:

Fragment calcFragment = new CalcFragment();

FragmentTransaction fragTrans = getSupportFragmentManager().beginTransaction();

fragTrans.replace(R.id.frag_container, calcFragment);
fragTrans.addToBackStack(null);
fragTrans.commit();

...

EditText calc_inp = (EditText) findViewById(R.id.calc_input);
calc_inp.setShowSoftInputOnFocus(false);

关于Fragment有一个很大的指南,这里有一个关于事务的重要信息:
呼叫commit()**不会立即执行交易。相反,交易会排定在主UI执行绪上执行,只要它能够执行即可。**不过,如有必要,您可以呼叫commitNow(),立即在UI执行绪上执行片段交易。
请注意,commitNowaddToBackStack不兼容。或者,您可以通过调用executePendingTransactions()来执行由尚未运行的commit()调用提交的所有挂起的FragmentTransactions。此方法与addToBackStack兼容。
因此,当你调用commit()时,Fragment实际上还没有被添加--它发生在 * 之后 *。如果你立即调用supportFragmentManager.getFragments(),你会得到一个空列表,因为这个片段还没有被添加。
如果你立即调用supportFragmentManager.executePendingTransactions(),那么Fragment * 将被添加,并且它将出现在Fragment的列表中。
但这并不是你唯一的问题--仅仅因为片段已经被添加,它的 * 视图 *(即它的布局层次结构)还没有膨胀。片段有它们自己的生命周期--onCreateonCreateView等,它们必须经历这些生命周期,并且在构建一个片段并将其添加到FragmentManager之后,它还没有处于CREATED状态。
这意味着你不能做findViewById(您在Activity的布局上运行),因为Fragment的视图(它的布局层次结构)还没有膨胀,所以在整个布局中还没有具有该ID的视图。这将在 * 以后 * 发生。我对这一点含糊其辞,因为你不能确定确切的时间,而无需连接到碎片中检查它何时准备好,或者其他类似的复杂事情。
而且,由于ActivitiesFragments具有各自独立的生命周期,因此可以按任意顺序独立地重新创建它们(例如,当你旋转屏幕时,所有的东西都被破坏了),你甚至不能确定什么时候哪个会准备好。你可以观察Lifecycle对象,但是......你根本不需要这样做,它非常高级--尤其是当您只想显示一个Fragment(最基本的东西)时。
如果这听起来很复杂的话,是的--这就是为什么要创建 Navigation 组件的部分原因,这样开发人员就不必担心很多这样的事情了。但是在这种情况下,最简单的方法是将事情分开--Activity不应该 * 需要 * 知道Fragment的视图是什么时候创建的。你应该只需要添加Fragment就可以让它工作了。所以这样:

calc_inp.setShowSoftInputOnFocus(false);

可以进入 * Fragment的 * 设置,onCreate或其他什么。它是Fragment自己初始化的一部分,对吗?让它处理自己的事务,连接自己的视图和侦听器,并设置它们应该如何工作。这样,您只需将Fragment放入Activity中,它就可以正常工作-Activity不需要在那里四处走动来完成设置。
(有些情况下,您可能需要连接一些东西,以便ActivityFragment能够通信-但这是其中之一吗?这里需要涉及Activity吗?这是您需要的心态-使您的Fragment尽可能独立,并使您的Activity尽可能简单。)

相关问题