[英]Fragment tab not attached to a context
Anyways, the app seems to work fine.无论如何,该应用程序似乎运行良好。 I can switch from the main tab to the operator tab, and even select operator soundboard pages and be moved to their fragments.
我可以从主选项卡切换到操作员选项卡,甚至 select 操作员音板页面并移动到它们的片段。 However as soon as I try to switch fragments (through my tabview) my app crashes and I get the error:
但是,一旦我尝试切换片段(通过我的 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)
I attached my code below, please let me know if you have any ideas!我在下面附上了我的代码,如果您有任何想法,请告诉我!
MainActivity.java MainActivity.java
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".voiceLinesView">
<FrameLayout
android:id="@+id/voiceLinesFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
activity_main.xml activity_main.xml
package com.jkcarraher.rainbowsixsoundboard;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Rect;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import soup.neumorphism.NeumorphCardView;
import soup.neumorphism.ShapeType;
import static android.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));
}
}
voiceLinesView.java (contains fragments so I can select an operator and it will take me to their soundboard fragment) voiceLinesView.java (包含片段,所以我可以 select 操作员,它会带我到他们的音板片段)
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".operatorTab">
<ScrollView
android:id="@+id/operatorScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorBody">
<RelativeLayout
android:id="@+id/kapkanButton"
android:layout_width="match_parent"
android:layout_height="60sp"
android:orientation="horizontal">
<ImageView
android:id="@+id/kapkanIcon"
android:layout_width="50sp"
android:layout_height="50sp"
android:layout_marginTop="5sp"
android:layout_marginLeft="10sp"
android:src="@drawable/ic_kapkan"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/kapkanIcon"
android:layout_marginLeft="10sp"
android:layout_marginTop="15sp"
android:layout_gravity="center"
android:fontFamily="@font/avenir"
android:text="Kapkan"
android:textColor="#ffffff"
android:textSize="25dp" />
<ImageView
android:layout_width="40sp"
android:layout_height="40sp"
android:layout_alignParentEnd="true"
android:layout_marginTop="10sp"
android:layout_marginEnd="10dp"
android:src="@drawable/ic_arrow_right" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/glazButton"
android:layout_below="@+id/kapkanButton"
android:layout_width="match_parent"
android:layout_height="60sp"
android:orientation="horizontal">
<ImageView
android:id="@+id/glazIcon"
android:layout_width="50sp"
android:layout_height="50sp"
android:layout_marginTop="5sp"
android:layout_marginLeft="10sp"
android:src="@drawable/ic_glaz"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/glazIcon"
android:layout_marginLeft="10sp"
android:layout_marginTop="15sp"
android:layout_gravity="center"
android:fontFamily="@font/avenir"
android:text="Glaz"
android:textColor="#ffffff"
android:textSize="25dp" />
<ImageView
android:layout_width="40sp"
android:layout_height="40sp"
android:layout_alignParentEnd="true"
android:layout_marginTop="10sp"
android:layout_marginEnd="10dp"
android:src="@drawable/ic_arrow_right" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/fuzeButton"
android:layout_below="@+id/glazButton"
android:layout_width="match_parent"
android:layout_height="60sp"
android:orientation="horizontal">
<ImageView
android:id="@+id/fuzeIcon"
android:layout_width="50sp"
android:layout_height="50sp"
android:layout_marginTop="5sp"
android:layout_marginLeft="10sp"
android:src="@drawable/ic_fuze"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/fuzeIcon"
android:layout_marginLeft="10sp"
android:layout_marginTop="15sp"
android:layout_gravity="center"
android:fontFamily="@font/avenir"
android:text="Fuze"
android:textColor="#ffffff"
android:textSize="25dp" />
<ImageView
android:layout_width="40sp"
android:layout_height="40sp"
android:layout_alignParentEnd="true"
android:layout_marginTop="10sp"
android:layout_marginEnd="10dp"
android:src="@drawable/ic_arrow_right" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/tachankaButton"
android:layout_below="@+id/fuzeButton"
android:layout_width="match_parent"
android:layout_height="60sp"
android:orientation="horizontal">
<ImageView
android:id="@+id/tachankaIcon"
android:layout_width="50sp"
android:layout_height="50sp"
android:layout_marginTop="5sp"
android:layout_marginLeft="10sp"
android:src="@drawable/ic_tachanka"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/tachankaIcon"
android:layout_marginLeft="10sp"
android:layout_marginTop="15sp"
android:layout_gravity="center"
android:fontFamily="@font/avenir"
android:text="Tachanka"
android:textColor="#ffffff"
android:textSize="25dp" />
<ImageView
android:layout_width="40sp"
android:layout_height="40sp"
android:layout_alignParentEnd="true"
android:layout_marginTop="10sp"
android:layout_marginEnd="10dp"
android:src="@drawable/ic_arrow_right" />
</RelativeLayout>
</RelativeLayout>
</ScrollView>
</FrameLayout>
fragment_voice_lines_view.xml fragment_voice_lines_view.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".voiceLinesView"> <FrameLayout android:id="@+id/voiceLinesFrame" android:layout_width="match_parent" android:layout_height="match_parent"/> </FrameLayout>
operatorTab.java运算符Tab.java
package com.jkcarraher.rainbowsixsoundboard; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Rect; import android.media.MediaPlayer; import android.net.Uri; import android.os.Bundle; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.RelativeLayout; import android.widget.ScrollView; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.AdView; import soup.neumorphism.NeumorphCardView; import soup.neumorphism.ShapeType; import static android.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)); } }
fragment_operator_tab.xml fragment_operator_tab.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" tools:context=".operatorTab"> <ScrollView android:id="@+id/operatorScrollView" android:layout_width="match_parent" android:layout_height="wrap_content"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorBody"> <RelativeLayout android:id="@+id/kapkanButton" android:layout_width="match_parent" android:layout_height="60sp" android:orientation="horizontal"> <ImageView android:id="@+id/kapkanIcon" android:layout_width="50sp" android:layout_height="50sp" android:layout_marginTop="5sp" android:layout_marginLeft="10sp" android:src="@drawable/ic_kapkan"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/kapkanIcon" android:layout_marginLeft="10sp" android:layout_marginTop="15sp" android:layout_gravity="center" android:fontFamily="@font/avenir" android:text="Kapkan" android:textColor="#ffffff" android:textSize="25dp" /> <ImageView android:layout_width="40sp" android:layout_height="40sp" android:layout_alignParentEnd="true" android:layout_marginTop="10sp" android:layout_marginEnd="10dp" android:src="@drawable/ic_arrow_right" /> </RelativeLayout> <RelativeLayout android:id="@+id/glazButton" android:layout_below="@+id/kapkanButton" android:layout_width="match_parent" android:layout_height="60sp" android:orientation="horizontal"> <ImageView android:id="@+id/glazIcon" android:layout_width="50sp" android:layout_height="50sp" android:layout_marginTop="5sp" android:layout_marginLeft="10sp" android:src="@drawable/ic_glaz"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/glazIcon" android:layout_marginLeft="10sp" android:layout_marginTop="15sp" android:layout_gravity="center" android:fontFamily="@font/avenir" android:text="Glaz" android:textColor="#ffffff" android:textSize="25dp" /> <ImageView android:layout_width="40sp" android:layout_height="40sp" android:layout_alignParentEnd="true" android:layout_marginTop="10sp" android:layout_marginEnd="10dp" android:src="@drawable/ic_arrow_right" /> </RelativeLayout> <RelativeLayout android:id="@+id/fuzeButton" android:layout_below="@+id/glazButton" android:layout_width="match_parent" android:layout_height="60sp" android:orientation="horizontal"> <ImageView android:id="@+id/fuzeIcon" android:layout_width="50sp" android:layout_height="50sp" android:layout_marginTop="5sp" android:layout_marginLeft="10sp" android:src="@drawable/ic_fuze"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/fuzeIcon" android:layout_marginLeft="10sp" android:layout_marginTop="15sp" android:layout_gravity="center" android:fontFamily="@font/avenir" android:text="Fuze" android:textColor="#ffffff" android:textSize="25dp" /> <ImageView android:layout_width="40sp" android:layout_height="40sp" android:layout_alignParentEnd="true" android:layout_marginTop="10sp" android:layout_marginEnd="10dp" android:src="@drawable/ic_arrow_right" /> </RelativeLayout> <RelativeLayout android:id="@+id/tachankaButton" android:layout_below="@+id/fuzeButton" android:layout_width="match_parent" android:layout_height="60sp" android:orientation="horizontal"> <ImageView android:id="@+id/tachankaIcon" android:layout_width="50sp" android:layout_height="50sp" android:layout_marginTop="5sp" android:layout_marginLeft="10sp" android:src="@drawable/ic_tachanka"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/tachankaIcon" android:layout_marginLeft="10sp" android:layout_marginTop="15sp" android:layout_gravity="center" android:fontFamily="@font/avenir" android:text="Tachanka" android:textColor="#ffffff" android:textSize="25dp" /> <ImageView android:layout_width="40sp" android:layout_height="40sp" android:layout_alignParentEnd="true" android:layout_marginTop="10sp" android:layout_marginEnd="10dp" android:src="@drawable/ic_arrow_right" /> </RelativeLayout> </RelativeLayout> </ScrollView> </FrameLayout>
Try to remove the ViewTreeObserver.OnScrollChangedListener
when the fragment is destroyed this will avoid any listener that can be attached to a destroyed fragment context not to be triggered whenever you leave and come back to this fragment.尝试在片段被销毁时删除
ViewTreeObserver.OnScrollChangedListener
这将避免任何可以附加到已销毁片段上下文的侦听器在您离开并返回此片段时不会被触发。
First: make a global field for the listener第一:为监听器创建一个全局字段
public class operatorTab extends Fragment {
...
ViewTreeObserver.OnScrollChangedListener mScrollListener = new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
resetAllButtons();
}
};
Then set the listener wit the created field然后用创建的字段设置监听器
private void scrollResetListener(){
scrollView.getViewTreeObserver().addOnScrollChangedListener(mScrollListener);
}
Then remove the listener.. I believe it's typically should be in onDestroyView()
>> but also try it in onStop()
or onPause
if it didn't work然后删除监听器。我相信它通常应该在
onDestroyView()
>> 但如果它不起作用,也可以在onStop()
或onPause
中尝试
This also will solve memory leak of this listener whenever its callback is triggered after the Fragment's view is destroyed这也将解决此侦听器的 memory 泄漏,只要在 Fragment 的视图被销毁后触发其回调
@Override
public void onDestroyView() {
super.onDestroyView();
scrollView.getViewTreeObserver().removeOnScrollChangedListener(mScrollListener);
}
UPDATE更新
onStop()/onPause() worked for me
onStop()/onPause() 为我工作
The reason that it didn't work with onDestroyView()
because the OperatorTab
fragment is a part of one of the ViewPager
pages;它不能与
onDestroyView()
一起使用的原因是OperatorTab
片段是ViewPager
页面之一的一部分; and by default ViewPager
loads a number of close pages in the background to be ready for the next page scroll;默认情况下,
ViewPager
会在后台加载一些关闭页面,为下一页滚动做好准备; loading this pages include some of the fragment lifecycle callbacks like onCreateView
, onStart
, but not onResume
.加载此页面包括一些片段生命周期回调,如
onCreateView
、 onStart
,但不包括onResume
。
When you leave the OperatorTab
by scrolling the ViewPager
to the next tab/page;当您通过滚动
ViewPager
到下一个选项卡/页面离开OperatorTab
时; onDestroyView()
won't be created if the ViewPager
decides that OperatorTab
is a part of the cached/close pages that the user might return back to it later;如果
ViewPager
决定OperatorTab
是用户稍后可能返回的缓存/关闭页面的一部分,则不会创建onDestroyView()
; and therefore the listener still there and after a few swipes of the pager, the OperatorTab
fragment can be detached from the context leaving the listener there with memory leaks...因此侦听器仍然存在,并且在寻呼机滑动几次之后,
OperatorTab
片段可以从上下文中分离出来,使侦听器留在那里 memory 泄漏...
So, the best way in ViewPager
fragment (or any View that loads its fragments in advance) is to stop any listeners once you leave the page, ie in onPause
or onStop
callbacks and not waiting until they are destroyed.因此,在
ViewPager
片段(或任何预先加载其片段的视图)中的最佳方法是在您离开页面后停止任何侦听器,即在onPause
或onStop
回调中,而不是等到它们被销毁。
A possible reason for this error is that you are calling getResources() NOT in an Activity without using a context.此错误的一个可能原因是您在没有使用上下文的情况下在 Activity 中调用 getResources() 。 So, you need to use context.getResources() instead where context may be one of these here .
因此,您需要使用context.getResources()而不是 context 可能是其中之一。 In you instance, I think getContext() will work.
在你的例子中,我认为 getContext() 会起作用。
So, I think you should search for all the times you are calling getResources and see if you are using a context or not.所以,我认为你应该搜索你调用 getResources 的所有时间,看看你是否使用了上下文。
The explanation for this error in a simple way is that you are trying to access the context required in getResources() before the fragment is instantiated.对此错误的简单解释是,您试图在片段实例化之前访问 getResources() 中所需的上下文。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.