有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java片段选项卡未附加到上下文


我目前正在安卓 studio上制作一个音板应用程序,其中有大量的片段。选项卡布局上的第一个页面只是一个普通的按钮视图,但第二个选项卡视图中有另一个片段视图。目标是第一个页面只显示一些正常的声音,第二个选项卡有多个操作员为其选择特定的音板

不管怎样,这个应用程序似乎运行良好。我可以从主选项卡切换到operator选项卡,甚至可以选择operator soundboard页面并移动到它们的片段。但是,当我尝试切换片段(通过我的tabview)时,我的应用程序崩溃,并出现错误:

"Fragment operatorTab{4623fc9} (312d4e58-458c-4f47-8fa3-794fe15f0536)} not attached to a context."**
**at com.jkcarraher.rainbowsixsoundboard.operatorTab.resetAllButtons(operatorTab.java:113)
        at com.jkcarraher.rainbowsixsoundboard.operatorTab.access$000(operatorTab.java:31)
        at com.jkcarraher.rainbowsixsoundboard.operatorTab$2.onScrollChanged(operatorTab.java:107)

我在下面附上了我的代码,如果你有任何想法,请告诉我

主要活动。java

import 安卓.graphics.Color;
import 安卓.os.Bundle;
import 安卓.text.SpannableString;
import 安卓.text.Spanned;
import 安卓.text.style.ForegroundColorSpan;
import 安卓.widget.Adapter;
import 安卓.widget.TextView;

import com.google.安卓.gms.ads.MobileAds;
import com.google.安卓.gms.ads.initialization.InitializationStatus;
import com.google.安卓.gms.ads.initialization.OnInitializationCompleteListener;
import com.google.安卓.material.tabs.TabLayout;
import 安卓x.viewpager.widget.ViewPager;
import 安卓x.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private SectionsPageAdapter mSectionsPageAdapter;
    private ViewPager mViewPager;
    private TabLayout tabLayout;


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

        initializeAds();
        makeSixYellow();

        //Create ViewPager (that houses all fragments)
        mSectionsPageAdapter = new SectionsPageAdapter(getSupportFragmentManager());
        mViewPager = (ViewPager) findViewById(R.id.view_pager);
        setUpViewPager(mViewPager);

        //Add & customize tabs
        tabLayout = (TabLayout) findViewById(R.id.tabs);
        tabLayout.setTabTextColors(Color.WHITE, Color.WHITE);
        tabLayout.setupWithViewPager(mViewPager);
        tabLayout.getTabAt(0).setText("Utility");
        tabLayout.getTabAt(1).setText("Voice Lines");
        checkPageChange();
    }

    private void setUpViewPager(ViewPager viewPager) {
        SectionsPageAdapter adapter = new SectionsPageAdapter(getSupportFragmentManager());
        adapter.addFragment(new utilityTab(), "Utility");
        adapter.addFragment(new voiceLinesView(), "Voice Lines");

        viewPager.setAdapter(adapter);
    }

    private void makeSixYellow(){
        TextView textView = findViewById(R.id.titleText);
        String text = "R6 Soundboard";
        SpannableString ss = new SpannableString(text);
        ForegroundColorSpan fcsYellow = new ForegroundColorSpan(Color.rgb(255,236,141));
        ss.setSpan(fcsYellow, 1,2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        textView.setText(ss);
    }

    private void initializeAds(){
        MobileAds.initialize(this, new OnInitializationCompleteListener() {
            @Override
            public void onInitializationComplete(InitializationStatus initializationStatus) {
            }
        });
    }

    private void checkPageChange(){
        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                utilityTab.resetAllButtons();
            }

            @Override
            public void onPageSelected(int position) {
                utilityTab.resetAllButtons();
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                utilityTab.resetAllButtons();
            }
        });
        }

}

主要活动。xml

<?xml version="1.0" encoding="utf-8"?>
<安卓x.coordinatorlayout.widget.CoordinatorLayout
    xmlns:安卓="http://schemas.安卓.com/apk/res/安卓"
    xmlns:app="http://schemas.安卓.com/apk/res-auto"
    xmlns:tools="http://schemas.安卓.com/tools"
    安卓:layout_width="match_parent"
    安卓:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.google.安卓.material.appbar.AppBarLayout
        安卓:layout_width="match_parent"
        安卓:layout_height="wrap_content"
        安卓:background="@color/colorHeader"
        安卓:theme="@style/AppTheme.AppBarOverlay">

        <TextView
            安卓:id="@+id/titleText"
            安卓:layout_marginLeft="20dp"
            安卓:layout_marginTop="20dp"
            安卓:layout_width="wrap_content"
            安卓:layout_height="wrap_content"
            安卓:fontFamily="@font/avenir"
            安卓:gravity="center_horizontal"
            安卓:text="R6 Soundboard"
            安卓:textColor="#FFF"
            安卓:textSize="30sp" />

        <com.google.安卓.material.tabs.TabLayout
            安卓:id="@+id/tabs"
            安卓:layout_width="match_parent"
            安卓:layout_height="wrap_content"
            app:tabTextColor="#fff"
            安卓:background="@color/colorHeader" />
    </com.google.安卓.material.appbar.AppBarLayout>

    <安卓x.viewpager.widget.ViewPager
        安卓:id="@+id/view_pager"
        安卓:layout_width="match_parent"
        安卓:layout_height="match_parent"
        安卓:background="@color/colorBody"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</安卓x.coordinatorlayout.widget.CoordinatorLayout>

语音线路视图。java(包含片段,因此我可以选择一个操作符,它将带我到他们的音板片段)

package com.jkcarraher.rainbowsixsoundboard;

import 安卓.os.Bundle;

import 安卓x.fragment.app.Fragment;
import 安卓x.fragment.app.FragmentTransaction;
import 安卓x.viewpager.widget.ViewPager;

import 安卓.view.LayoutInflater;
import 安卓.view.View;
import 安卓.view.ViewGroup;

import com.google.安卓.material.tabs.TabLayout;

public class voiceLinesView extends Fragment {

    private SectionsPageAdapter voiceLinesSectionsPageAdapter;
    private ViewPager voiceLinesViewPager;

    public voiceLinesView() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_voice_lines_view, container, false);

        FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
        fragmentTransaction.add(R.id.voiceLinesFrame, new operatorTab());
        fragmentTransaction.commit();


        return view;
    }

}

片段、声音、线条、视图。xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:安卓="http://schemas.安卓.com/apk/res/安卓"
    xmlns:tools="http://schemas.安卓.com/tools"
    安卓:layout_width="match_parent"
    安卓:layout_height="match_parent"
    tools:context=".voiceLinesView">

    <FrameLayout
        安卓:id="@+id/voiceLinesFrame"
        安卓:layout_width="match_parent"
        安卓:layout_height="match_parent"/>

</FrameLayout>

运算符选项卡。java

package com.jkcarraher.rainbowsixsoundboard;

import 安卓.annotation.SuppressLint;
import 安卓.content.Context;
import 安卓.graphics.Rect;
import 安卓.media.MediaPlayer;
import 安卓.net.Uri;
import 安卓.os.Bundle;

import 安卓x.annotation.Nullable;
import 安卓x.fragment.app.Fragment;
import 安卓x.fragment.app.FragmentManager;
import 安卓x.fragment.app.FragmentTransaction;

import 安卓.view.LayoutInflater;
import 安卓.view.MotionEvent;
import 安卓.view.View;
import 安卓.view.ViewGroup;
import 安卓.view.ViewTreeObserver;
import 安卓.widget.RelativeLayout;
import 安卓.widget.ScrollView;

import com.google.安卓.gms.ads.AdRequest;
import com.google.安卓.gms.ads.AdView;

import soup.neumorphism.NeumorphCardView;
import soup.neumorphism.ShapeType;

import static 安卓.view.MotionEvent.ACTION_MOVE;

public class operatorTab extends Fragment {
    private ScrollView scrollView;
    public static RelativeLayout KapkanButton;
    public static RelativeLayout GlazButton;
    public static RelativeLayout FuzeButton;
    public static RelativeLayout TachankaButton;

    voiceLinesView voiceLinesView = new voiceLinesView();


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_operator_tab, container, false);

        //Initialize ScrollView
        scrollView = view.findViewById(R.id.operatorScrollView);

        //Initialize buttons 1-4
        KapkanButton = view.findViewById(R.id.kapkanButton);
        GlazButton = view.findViewById(R.id.glazButton);
        FuzeButton = view.findViewById(R.id.fuzeButton);
        TachankaButton = view.findViewById(R.id.tachankaButton);

        //Make buttons 1-6 pressable
        initPressableButton(KapkanButton);
        initPressableButton(GlazButton);
        initPressableButton(FuzeButton);
        initPressableButton(TachankaButton);

        scrollResetListener();
        return view;
    }

    @SuppressLint("ClickableViewAccessibility")
    private void initPressableButton(final RelativeLayout relativeLayout) {
        relativeLayout.setBackgroundColor(getResources().getColor(R.color.colorBody));
        final Rect r = new Rect();

        relativeLayout.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent event) {
                // get the View's Rect relative to its parent
                view.getHitRect(r);
                // offset the touch coordinates with the values from r
                // to obtain meaningful coordinates
                final float x = event.getX() + r.left;
                final float y = event.getY() + r.top;

                if(event.getAction() == MotionEvent.ACTION_DOWN) {
                    relativeLayout.setBackgroundColor(getResources().getColor(R.color.colorButtonPressed));
                    return true;
                } else if(event.getAction() == MotionEvent.ACTION_UP) {
                    if (r.contains((int) x, (int) y)) {
                        relativeLayout.setBackgroundColor(getResources().getColor(R.color.colorBody));
                        //On Click Up
                        FragmentTransaction fr = getFragmentManager().beginTransaction();
                        fr.replace(R.id.voiceLinesFrame, new kapkanVoiceLines());
                        fr.commit();
                    }

                }else if(event.getAction() == ACTION_MOVE){
                    if (!r.contains((int) x, (int) y)) {
                        relativeLayout.setBackgroundColor(getResources().getColor(R.color.colorBody));
                    }
                    return true;
                }
                return false;
            }
        });
    }

    private void scrollResetListener(){
        scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
            @Override
            public void onScrollChanged() {
                resetAllButtons();
            }
        });
    }

    public void resetAllButtons(){
        KapkanButton.setBackgroundColor(getResources().getColor(R.color.colorBody));
        GlazButton.setBackgroundColor(getResources().getColor(R.color.colorBody));
        FuzeButton.setBackgroundColor(getResources().getColor(R.color.colorBody));
        TachankaButton.setBackgroundColor(getResources().getColor(R.color.colorBody));
    }
}

片段操作符选项卡。xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:安卓="http://schemas.安卓.com/apk/res/安卓"
    xmlns:tools="http://schemas.安卓.com/tools"
    安卓:layout_width="match_parent"
    安卓:layout_height="match_parent"
    xmlns:app="http://schemas.安卓.com/apk/res-auto"
    tools:context=".operatorTab">

    <ScrollView
        安卓:id="@+id/operatorScrollView"
        安卓:layout_width="match_parent"
        安卓:layout_height="wrap_content">
        <RelativeLayout
            安卓:layout_width="match_parent"
            安卓:layout_height="wrap_content"
            安卓:background="@color/colorBody">
            <RelativeLayout
                安卓:id="@+id/kapkanButton"
                安卓:layout_width="match_parent"
                安卓:layout_height="60sp"
                安卓:orientation="horizontal">
                <ImageView
                    安卓:id="@+id/kapkanIcon"
                    安卓:layout_width="50sp"
                    安卓:layout_height="50sp"
                    安卓:layout_marginTop="5sp"
                    安卓:layout_marginLeft="10sp"
                    安卓:src="@drawable/ic_kapkan"/>
                <TextView
                    安卓:layout_width="wrap_content"
                    安卓:layout_height="wrap_content"
                    安卓:layout_toRightOf="@id/kapkanIcon"
                    安卓:layout_marginLeft="10sp"
                    安卓:layout_marginTop="15sp"
                    安卓:layout_gravity="center"
                    安卓:fontFamily="@font/avenir"
                    安卓:text="Kapkan"
                    安卓:textColor="#ffffff"
                    安卓:textSize="25dp" />

                <ImageView
                    安卓:layout_width="40sp"
                    安卓:layout_height="40sp"
                    安卓:layout_alignParentEnd="true"
                    安卓:layout_marginTop="10sp"
                    安卓:layout_marginEnd="10dp"
                    安卓:src="@drawable/ic_arrow_right" />
            </RelativeLayout>
            <RelativeLayout
                安卓:id="@+id/glazButton"
                安卓:layout_below="@+id/kapkanButton"
                安卓:layout_width="match_parent"
                安卓:layout_height="60sp"
                安卓:orientation="horizontal">
                <ImageView
                    安卓:id="@+id/glazIcon"
                    安卓:layout_width="50sp"
                    安卓:layout_height="50sp"
                    安卓:layout_marginTop="5sp"
                    安卓:layout_marginLeft="10sp"
                    安卓:src="@drawable/ic_glaz"/>
                <TextView
                    安卓:layout_width="wrap_content"
                    安卓:layout_height="wrap_content"
                    安卓:layout_toRightOf="@id/glazIcon"
                    安卓:layout_marginLeft="10sp"
                    安卓:layout_marginTop="15sp"
                    安卓:layout_gravity="center"
                    安卓:fontFamily="@font/avenir"
                    安卓:text="Glaz"
                    安卓:textColor="#ffffff"
                    安卓:textSize="25dp" />

                <ImageView
                    安卓:layout_width="40sp"
                    安卓:layout_height="40sp"
                    安卓:layout_alignParentEnd="true"
                    安卓:layout_marginTop="10sp"
                    安卓:layout_marginEnd="10dp"
                    安卓:src="@drawable/ic_arrow_right" />
            </RelativeLayout>
            <RelativeLayout
                安卓:id="@+id/fuzeButton"
                安卓:layout_below="@+id/glazButton"
                安卓:layout_width="match_parent"
                安卓:layout_height="60sp"
                安卓:orientation="horizontal">
                <ImageView
                    安卓:id="@+id/fuzeIcon"
                    安卓:layout_width="50sp"
                    安卓:layout_height="50sp"
                    安卓:layout_marginTop="5sp"
                    安卓:layout_marginLeft="10sp"
                    安卓:src="@drawable/ic_fuze"/>
                <TextView
                    安卓:layout_width="wrap_content"
                    安卓:layout_height="wrap_content"
                    安卓:layout_toRightOf="@id/fuzeIcon"
                    安卓:layout_marginLeft="10sp"
                    安卓:layout_marginTop="15sp"
                    安卓:layout_gravity="center"
                    安卓:fontFamily="@font/avenir"
                    安卓:text="Fuze"
                    安卓:textColor="#ffffff"
                    安卓:textSize="25dp" />

                <ImageView
                    安卓:layout_width="40sp"
                    安卓:layout_height="40sp"
                    安卓:layout_alignParentEnd="true"
                    安卓:layout_marginTop="10sp"
                    安卓:layout_marginEnd="10dp"
                    安卓:src="@drawable/ic_arrow_right" />
            </RelativeLayout>
            <RelativeLayout
                安卓:id="@+id/tachankaButton"
                安卓:layout_below="@+id/fuzeButton"
                安卓:layout_width="match_parent"
                安卓:layout_height="60sp"
                安卓:orientation="horizontal">
                <ImageView
                    安卓:id="@+id/tachankaIcon"
                    安卓:layout_width="50sp"
                    安卓:layout_height="50sp"
                    安卓:layout_marginTop="5sp"
                    安卓:layout_marginLeft="10sp"
                    安卓:src="@drawable/ic_tachanka"/>
                <TextView
                    安卓:layout_width="wrap_content"
                    安卓:layout_height="wrap_content"
                    安卓:layout_toRightOf="@id/tachankaIcon"
                    安卓:layout_marginLeft="10sp"
                    安卓:layout_marginTop="15sp"
                    安卓:layout_gravity="center"
                    安卓:fontFamily="@font/avenir"
                    安卓:text="Tachanka"
                    安卓:textColor="#ffffff"
                    安卓:textSize="25dp" />

                <ImageView
                    安卓:layout_width="40sp"
                    安卓:layout_height="40sp"
                    安卓:layout_alignParentEnd="true"
                    安卓:layout_marginTop="10sp"
                    安卓:layout_marginEnd="10dp"
                    安卓:src="@drawable/ic_arrow_right" />
            </RelativeLayout>

        </RelativeLayout>
    </ScrollView>

</FrameLayout>

共 (2) 个答案

  1. # 1 楼答案

    当片段被销毁时,尝试删除ViewTreeObserver.OnScrollChangedListener,这将避免任何可以附加到已销毁片段上下文的侦听器在您离开并返回该片段时不会被触发

    第一:为侦听器创建一个全局字段

    public class operatorTab extends Fragment {
    
        ...
    
        ViewTreeObserver.OnScrollChangedListener  mScrollListener = new ViewTreeObserver.OnScrollChangedListener() {
            @Override
            public void onScrollChanged() {
                resetAllButtons();
            }
        };
    

    然后使用创建的字段设置侦听器

    private void scrollResetListener(){
        scrollView.getViewTreeObserver().addOnScrollChangedListener(mScrollListener);
    }
    

    然后删除侦听器。。我认为它通常应该在onDestroyView()>&燃气轮机;但是如果它不起作用,也可以在{}或{}中尝试

    这也将解决这个侦听器在片段视图被破坏后触发回调时的内存泄漏问题

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        scrollView.getViewTreeObserver().removeOnScrollChangedListener(mScrollListener);
    }
    

    更新

    onStop()/onPause() worked for me

    它不能处理onDestroyView()的原因是OperatorTab片段是ViewPager页面的一部分;默认情况下ViewPager在后台加载许多关闭的页面,以便为下一页滚动做好准备;加载此页面包括一些片段生命周期回调,如onCreateViewonStart,但不包括onResume

    当您通过将ViewPager滚动到下一个选项卡/页面来离开OperatorTab^如果ViewPager决定OperatorTab是用户稍后可能返回的缓存/关闭页面的一部分,则不会创建{};因此,监听器仍然在那里,在轻击寻呼机几下之后,OperatorTab片段可以从上下文中分离出来,从而使监听器出现内存泄漏

    因此,在ViewPager片段(或任何提前加载其片段的视图)中,最好的方法是在您离开页面时停止任何侦听器,即在onPauseonStop回调中,不要等待它们被销毁

  2. # 2 楼答案

    此错误的一个可能原因是,您在未使用上下文的活动中调用getResources()。因此,您需要使用上下文。getResources()而不是上下文可能是这些here之一。在您的例子中,我认为getContext()可以工作

    因此,我认为您应该搜索所有调用getResources的时间,看看是否使用上下文

    这个错误的简单解释是,在实例化片段之前,您试图访问getResources()中所需的上下文