【问题标题】:Black Screen is visible after switching to another Fragment切换到另一个 Fragment 后黑屏可见
【发布时间】:2020-10-05 04:31:01
【问题描述】:

我正在尝试使用产品列表和产品主详细信息创建一个简单的应用程序。 至于我最初的尝试,我使用 BottomNavigationView 创建了应用程序,其中底部有小图标,您可以通过单击其中一个来切换片段。我目前在底部导航栏中有 4 个图标,这是 4 个图标:

  • 产品(ProductsFragment)
  • 收藏夹(FavoritesFragment)
  • 配置文件(ProfileFragment)
  • 购物车(CartFragment)

这 4 个片段在我的 HomeActivity 中切换,这就是我切换它们的方式:

HomeActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);

        bottomNavbar = findViewById(R.id.nav_view);
        bottomNavbar.setOnNavigationItemSelectedListener(navListener);
        homeContainer = findViewById(R.id.homeContainer);
        createSnackbar(homeContainer);
        viewModel = new HomeViewModel();
        viewModel.getCartCounterLiveData().observe(this, CartCounterObserver);
        createBadges(bottomNavbar);
}    

private BottomNavigationView.OnNavigationItemSelectedListener navListener = new BottomNavigationView.OnNavigationItemSelectedListener() {

        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            BaseRTFFragment selectedFragment = null;
            String stackName;

            switch(item.getItemId()) {
                case R.id.nav_home:
                    selectedFragment = new ProductsFragment();
                    break;

                case R.id.nav_favorites:
                    selectedFragment = new FavoritesFragment();
                    break;

                case R.id.nav_profile:
                    selectedFragment = new ProfileFragment();
                    break;

                case R.id.nav_cart:
                    selectedFragment = new CartFragment();
                    break;
            }

            navigateToFragment(selectedFragment);
            return true;
        }
    };

    private void navigateToFragment(BaseRTFFragment selectedFragment) {
        FragmentTransaction fTrans = getSupportFragmentManager().beginTransaction();
        // fTrans.addToBackStack(selectedFragment.getFragmentName());
        fTrans.replace(R.id.nav_host_fragment, selectedFragment).commit();
    }

所以这只是一个简单的replace()调用。此时它工作正常,片段切换时没有黑屏

顺便说一下,ProductsFragment 有一个 searchText、类别过滤按钮和一个分页的 recyclerView 来显示产品列表。请看下面的代码:

ProductsFragment.java

public class ProductsFragment extends BaseRTFFragment<FragmentProductsBinding>
        implements Observer<PagedList<Product>>, ProductsAdapter.OnProductClickListener, CategoryAdapter.OnCategoryClickListener {

    ProductsViewModel viewModel;
    ProductsAdapter productsAdapter;
    int selectedCategory;
    String currentSearchText;
    ProductsEventsListener listener;

    private CategoryAdapter categoryAdapter;
    private String fragmentName = "Products";

    @Override
    protected int getFragmentLayout() {
        return R.layout.fragment_products;
    }

    @Override
    public String getFragmentName() { return fragmentName; }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        viewModel = new ProductsViewModel();
        initProductsAdapter();
        initCategoryAdapter();
        initializeSearch();
        loadProducts();
    }

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        try {
            listener = (ProductsEventsListener) context;
        } catch (ClassCastException castException) {
            throw new Error("The activity does not implement the listener");
        }
    }

    private void initProductsAdapter() {
        productsAdapter = new ProductsAdapter(this);
        dataBinding.productsRecyclerView.setAdapter(productsAdapter);
    }

    private void initCategoryAdapter() {
        Query cQuery = initCategoryQuery();
        cQuery.get().addOnCompleteListener(categoryListener);
    }

    private OnCompleteListener<QuerySnapshot> categoryListener = new OnCompleteListener<QuerySnapshot>() {
        @Override
        public void onComplete(@NonNull Task<QuerySnapshot> task) {
            if(task.isSuccessful()) {
                List<Category> categories = task.getResult().toObjects(Category.class);
                categoryAdapter = getCategoryAdapter(categories);
                dataBinding.categoryRecyclerView.setAdapter(categoryAdapter);
            }
        }
    };

    private CategoryAdapter getCategoryAdapter(List<Category> categories) {
        return new CategoryAdapter(categories, this);
    }

    private Query initCategoryQuery() {
        FirebaseFirestore mFirestore = FirebaseFirestore.getInstance();
        return mFirestore.collection("categories")
                .orderBy("name", Query.Direction.ASCENDING);
    }

    private void loadProducts() {
        viewModel.pagedListLiveData.observe(getViewLifecycleOwner(), this);
    }

    private void reloadProducts() {
        viewModel.replaceSubscription(this, null, 0);
        loadProducts();
    }

    private void loadSearchedProducts(String searchText, int category) {
        viewModel.replaceSubscription(this, searchText, category);
        loadProducts();
    }

    @Override
    public void onChanged(PagedList<Product> products) {
        productsAdapter.submitList(products);
        hideProgressBar();
        // toggleEmptyLayout(products.size());
    }

    private void toggleEmptyLayout(int count) {
        if(count > 0) {
            dataBinding.productsRecyclerView.setVisibility(View.VISIBLE);
            dataBinding.emptyResultLayout.setVisibility(View.GONE);
        } else {
            dataBinding.productsRecyclerView.setVisibility(View.GONE);
            dataBinding.emptyResultLayout.setVisibility(View.VISIBLE);
        }
    }

    private void hideProgressBar() {
        dataBinding.progressBar.setVisibility(View.GONE);
    }

    public int getSelectedCategory() {
        return selectedCategory;
    }

    @Override
    public void onProductClick(Product product) {
        displayProductName(product.getName() + " has been clicked!");
        listener.OnProductClick(product);
    }

    @Override
    public void onAddProductToCart(Product product) {
        // displayProductName(product.getName() + " has been added to cart");
        listener.OnAddProductToCart(product);
    }

    @Override
    public void onFavoriteProduct(Product product) {
        listener.OnFavoriteProduct(product);
    }

    private void displayProductName(String name) {
        Toast.makeText(getActivity(), name, Toast.LENGTH_SHORT).show();
    }

    private void initializeSearch() {
        dataBinding.searchInput.addTextChangedListener(searchTextWatcher);
    }

    private TextWatcher searchTextWatcher = new TextWatcher() {
        @Override
        public void afterTextChanged(Editable searchText) {
            String sText = searchText.toString().toLowerCase();;
            if (sText != currentSearchText) {
                currentSearchText = sText;
                loadSearchedProducts(currentSearchText, selectedCategory);
            }
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start,
                                      int count, int after) {
        }

        @Override
        public void onTextChanged(CharSequence s, int start,
                                  int before, int count) {
        }
    };

    @Override
    public void onCategoryClick(int selectedCategoryId) {
        selectedCategory = selectedCategoryId;
        loadSearchedProducts(currentSearchText, selectedCategory);
    }
}

我所有的 Fragment 都继承了一个自定义的基本 Fragment,它只是继承自 android Fragment,请参见下面的代码:

BaseRTFFragment.java

public abstract class BaseRTFFragment<T extends ViewDataBinding> extends Fragment {
    protected T dataBinding;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle bundle) {
        dataBinding = DataBindingUtil.inflate(inflater, getFragmentLayout(), null, false);
        return dataBinding.getRoot();
    }

    protected abstract int getFragmentLayout();
    public abstract String getFragmentName();

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        dataBinding = null;
    }
}

所以现在一切都很好,现在是时候添加产品详细信息页面了。 为此,我创建了一个新的 ProductFragment(注意名称中没有“s”:))

ProductFragment.java


public class ProductFragment extends BaseRTFFragment<FragmentProductBinding> implements Observer<Product> {

    ProductViewModel viewModel;
    ProductEventsListener listener;
    private String fragmentName = "Product";

    @Override
    protected int getFragmentLayout() {
        return R.layout.fragment_product;
    }

    @Override
    public String getFragmentName() { return fragmentName; }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle bundle) {
        int productId = getArguments().getInt("productId");
        viewModel = new ProductViewModel(productId);
        viewModel.getProduct(productId).observe(getViewLifecycleOwner(), this);
        return super.onCreateView(inflater, container, bundle);
    }

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

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        try {
            listener = (ProductEventsListener) context;
        } catch (ClassCastException castException) {
            throw new Error("The activity does not implement the listener");
        }
    }

    @Override
    public void onChanged(Product product) {
        dataBinding.productTitle.setText(product.getName());
    }

}

关于这个片段的布局,请看下面的代码:

fragment_product.xml

<?xml version="1.0" encoding="utf-8"?>
<layout 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">
    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:id="@+id/productFragmentLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <com.google.android.material.appbar.AppBarLayout
            android:id="@+id/productAppBar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:fitsSystemWindows="true">
            <com.google.android.material.appbar.CollapsingToolbarLayout
                android:id="@+id/productCollapseToolbar"
                android:layout_width="match_parent"
                android:layout_height="256dp"
                android:fitsSystemWindows="true"
                app:contentScrim="?attr/colorPrimary"
                app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
                app:titleEnabled="false">

                <ImageView
                    android:id="@+id/htab_header"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@drawable/ic_default_product"
                    android:fitsSystemWindows="true"
                    android:scaleType="centerCrop"
                    app:layout_collapseMode="parallax"/>

                <View
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:alpha="0.3"
                    android:background="@android:color/black"
                    android:fitsSystemWindows="true"/>

                <ImageButton
                    android:id="@+id/backBtn"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:background="@color/colorPrimary"
                    android:tint="@color/colorSecondary"
                    android:padding="@dimen/btn_padding"
                    android:layout_margin="@dimen/btn_padding"
                    android:onClick="OnNavigateBack"
                    android:src="@drawable/ic_previous"/>

            </com.google.android.material.appbar.CollapsingToolbarLayout>
        </com.google.android.material.appbar.AppBarLayout>
        <androidx.core.widget.NestedScrollView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="@dimen/default_page_padding"
                android:orientation="vertical">
                <TextView
                    android:id="@+id/productTitle"
                    style="@style/ProductTitle"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:layout_marginBottom="@dimen/btn_padding"
                    android:text="Growers Mix"/>
                <TextView
                    android:id="@+id/productDescription"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:text="Test"/>
            </LinearLayout>
        </androidx.core.widget.NestedScrollView>
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>

注意 ImageButton,我在 HomeActivity.java 中声明了 OnNavigateBack 方法,因为在 ProductFragment.java 上声明它会导致一些错误,说它找不到这样的方法,所以我在家庭活动。看起来是这样的:

HomeActivity.java:OnNavigateBack

@Override
public void OnNavigateBack() {
   navigateToFragment(new ProductsFragment());
}

private void navigateToFragment(BaseRTFFragment selectedFragment) {
        FragmentTransaction fTrans = getSupportFragmentManager().beginTransaction();
        // fTrans.addToBackStack(selectedFragment.getFragmentName());
        fTrans.replace(R.id.nav_host_fragment, selectedFragment).commit();
    }
@Override
    public void OnProductClick(Product product) {
        // displayProductName(product.getName() + " should be viewed in a separate fragment");
        Bundle bundle = new Bundle();
        bundle.putInt("productId", product.getId());
        ProductFragment productFragment = new ProductFragment();
        productFragment.setArguments(bundle);
        navigateToFragment(productFragment);
    }

它只是调用之前的 navigateToFragment() 方法。但是这次每次我从 ProductFragment 中单击后退按钮时,它都会呈现至少 1 秒的黑屏并加载产品列表。我不确定似乎有什么问题,因为我只是以与其他片段相同的方式加载片段。有什么我错过的吗?还是我采取的方法是错误的?我该怎么办?请帮忙。提前致谢。

【问题讨论】:

    标签: java android android-fragments fragment


    【解决方案1】:

    找到了一个解决方案,似乎绑定在片段布局中使用 android:onClick 属性无法正常工作。所以我通过在后退按钮上设置一个 onClickListener 来绑定它,从而返回绑定点击事件的旧方式:

    做:

    ProductFragment.java

     @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            bindEvents();
        }
    
        private void bindEvents() {
            dataBinding.backBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    listener.onNavigateBack();
                }
            });
        }
    

    从现在开始我永远不会这样做:

    fragment_product.xml

    ...
    <ImageButton
        ....
        android:id="@+id/backBtn"
        android:onClick="onProductClick"
        ... />
    ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多