我不明白为什么我的runonUiThread周围的getActivity()返回null。以下是我遇到问题的代码。我认为它与我放置onAttach方法的位置有关,但我不确定。另外请注意所有注释,因为我将在修复此错误时清理代码。另请注意,这是片段的java代码。谢谢。
public void onAttach(Context context){
super.onAttach(context);
Activity a;
if(context instanceof Activity)
{
a=(Activity) context;
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
super.onActivityCreated(savedInstanceState);
//setCont(R.layout.fragment_level_one);
// return inflater.inflate(R.layout.fragment_level_one,container, false);
View view = inflater.inflate(R.layout.fragment_level_one, container, false);
//creating viewables and such
viewer = (ViewGroup) view.findViewById(R.id.view_level);
img = (ImageView) view.findViewById(R.id.imageView);
failButton = (Button) view.findViewById(R.id.failureButton);
countDownMain = (TextView) view.findViewById(R.id.countDownMain);
countDownBeginText = (TextView) view.findViewById(R.id.countDownBeginText);
beginButton = (Button) view.findViewById(R.id.beginButton);
/*if (view != null) {
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null) {
parent.removeView(view);
}
}
try {
view = inflater.inflate(R.layout.fragment_level_one, container, false);
} catch (InflateException e) {
}*/
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(150, 150);
img.setLayoutParams(layoutParams);
img.setOnTouchListener(new LevelOneFragment.ChoiceTouchListener());
//begin random movement
if(isAdded()) {
startRandomButton(img);
}
else
{
Log.d("line 98 is", " is null");
}
//setting up button for failure CORRECT TO TAKE YOU TO THE MAIN MENU
failButton.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
startActivity(new Intent(getActivity(), MainMenu.class));
}
});
//setting countdown text to 3
countDownBeginText.setText(":3");
//begin countdown from three
beginButton.setOnClickListener(new View.OnClickListener(){
public void onClick(View beginT) {
CountDownTimer countDownTimer = new CountDownTimer(3*1000, 3) {
@Override
public void onTick(long millisUntilFinished) {
countDownBeginText.setText(":" + millisUntilFinished/1000);
//add possible sound here every tick
}
@Override
public void onFinish() {
beginButton.setVisibility(View.INVISIBLE);
countDownBeginText.setVisibility(View.INVISIBLE);
//countdown from 60------- change parameters in count down timer to the time desired
CountDownTimer countDownTimer = new CountDownTimer(60*1000, 3) {
@Override
public void onTick(long millisUntilFinishedMain) {
countDownMain.setText(":" + millisUntilFinishedMain/1000);
//add possible sound here every tick
}
@Override
public void onFinish() {
Toast.makeText(getActivity(),"You lose", Toast.LENGTH_LONG).show();
//rest of text in method is trial
startActivity(new Intent(getActivity(), MainMenu.class ));
}
}.start();
}
}.start();
}
});
return view; //inflater.inflate(R.layout.fragment_level_one,container, false);
}
//getting screen size
public static Point getDisplaySize(@NonNull Context context){
Point point = new Point();
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
manager.getDefaultDisplay().getSize(point);
return point;
}
//randomly move
public void randomMovement(ImageView img){
//int x = new Random().nextInt(getDisplaySize(getActivity()).x);
//int y = new Random().nextInt(getDisplaySize(getActivity()).y);
if(isAdded()) {
int x = new Random().nextInt(getDisplaySize(getActivity()).x);
int y = new Random().nextInt(getDisplaySize(getActivity()).y);
img.setY(y);
img.setX(x);
}
else
Log.d("Random mover is null", " is null");
}
//creating timer
public void startRandomButton(final ImageView img){
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
if(isAdded()){
getActivity().runOnUiThread(new Runnable() { //best method in the entire world-- use when trying to update ui in the background
@Override
public void run() {
randomMovement(img);
}
});}else{
Log.d("Fragment one", "Is null");}
}
}, 0, 5000);
}
下面是我的日志猫我得到的地方,空引用就在我的startRandomButton()方法中:
[ 10-22 14:34:13.423 15104:15141 D/ ]
SurfaceInterface::setAsyncMode: set async mode 1
10-22 14:34:13.429 15104-15141/name.inserttitlenameD/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:13.448 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:13.453 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:13.474 15104-15141/name.inserttitlename I/chatty: uid=10083(u0_a83) RenderThread identical 2 lines
10-22 14:34:15.124 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:17.606 15104-15141/name.inserttitlenameD/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:17.628 15104-15141/name.inserttitlename I/chatty: uid=10083(u0_a83) RenderThread identical 1 line
10-22 14:34:17.638 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:18.272 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:18.467 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:18.480 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:18.487 15104-15141/name.inserttitlename D/EGL_emulation: eglMakeCurrent: 0x9bb040c0: ver 3 0 (tinfo 0x9bb03290)
10-22 14:34:20.156 15104-16453/com.example.name.inserttitlename D/Fragment one: Is null
10-22 14:34:25.157 15104-16453/com.example.name.inserttitlename D/Fragment one: Is null
10-22 14:34:50.161 15104-16453/com.example.name.inserttitlename I/chatty: uid=10083(u0_a83) Timer-1 identical 5 lines
完成fragment.java
package com.example.name.insertitlename;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Point;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import android.view.InflateException;
import java.lang.ref.WeakReference;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
/**
* A simple {@link Fragment} subclass.
*/
public class LevelOneFragment extends Fragment {
//creating variables
private ImageView img;
private ViewGroup viewer;
TextView textCount;
Button failButton;
Button beginButton;
TextView countDownBeginText;
private TextView countDownMain;
public int scoreCounter;
public LevelOneFragment() {
// Required empty public constructor
}
@Override
public void onAttach(Context context){
super.onAttach(context);
Activity a;
if(context instanceof Activity)
{
a=(Activity) context;
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
// super.onActivityCreated(savedInstanceState);
//setCont(R.layout.fragment_level_one);
// return inflater.inflate(R.layout.fragment_level_one,container, false);
View view = inflater.inflate(R.layout.fragment_level_one, container, false);
//creating viewables and such
viewer = (ViewGroup) view.findViewById(R.id.view_level);
img = (ImageView) view.findViewById(R.id.imageView);
failButton = (Button) view.findViewById(R.id.failureButton);
countDownMain = (TextView) view.findViewById(R.id.countDownMain);
countDownBeginText = (TextView) view.findViewById(R.id.countDownBeginText);
beginButton = (Button) view.findViewById(R.id.beginButton);
/*if (view != null) {
ViewGroup parent = (ViewGroup) view.getParent();
if (parent != null) {
parent.removeView(view);
}
}
try {
view = inflater.inflate(R.layout.fragment_level_one, container, false);
} catch (InflateException e) {
}*/
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(150, 150);
img.setLayoutParams(layoutParams);
img.setOnTouchListener(new LevelOneFragment.ChoiceTouchListener());
//begin random movement
if(isAdded()) {
startRandomButton(img);
}
else
{
Log.d("line 98 is", " is null");
}
//setting up button for failure CORRECT TO TAKE YOU TO THE MAIN MENU
failButton.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
startActivity(new Intent(getActivity(), MainMenu.class));
}
});
//setting countdown text to 3
countDownBeginText.setText(":3");
//begin countdown from three
beginButton.setOnClickListener(new View.OnClickListener(){
public void onClick(View beginT) {
CountDownTimer countDownTimer = new CountDownTimer(3*1000, 3) {
@Override
public void onTick(long millisUntilFinished) {
countDownBeginText.setText(":" + millisUntilFinished/1000);
//add possible sound here every tick
}
@Override
public void onFinish() {
beginButton.setVisibility(View.INVISIBLE);
countDownBeginText.setVisibility(View.INVISIBLE);
//countdown from 60------- change parameters in count down timer to the time desired
CountDownTimer countDownTimer = new CountDownTimer(60*1000, 3) {
@Override
public void onTick(long millisUntilFinishedMain) {
countDownMain.setText(":" + millisUntilFinishedMain/1000);
//add possible sound here every tick
}
@Override
public void onFinish() {
Toast.makeText(getActivity(),"You lose", Toast.LENGTH_LONG).show();
//rest of text in method is trial
startActivity(new Intent(getActivity(), MainMenu.class ));
}
}.start();
}
}.start();
}
});
return view; //inflater.inflate(R.layout.fragment_level_one,container, false);
}
//getting screen size
public static Point getDisplaySize(@NonNull Context context){
Point point = new Point();
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
manager.getDefaultDisplay().getSize(point);
return point;
}
//randomly move
public void randomMovement(ImageView img){
//int x = new Random().nextInt(getDisplaySize(getActivity()).x);
//int y = new Random().nextInt(getDisplaySize(getActivity()).y);
if(isAdded()) {
int x = new Random().nextInt(getDisplaySize(getActivity()).x);
int y = new Random().nextInt(getDisplaySize(getActivity()).y);
img.setY(y);
img.setX(x);
}
else
Log.d("Random mover is null", " is null");
}
final WeakReference<Activity> activityRef = getActivity();
//creating timer
public void startRandomButton(final ImageView img){
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
if(isAdded()){
activityRef.get().runOnUiThread(new Runnable() { //best method in the entire world-- use when trying to update ui in the background
@Override
public void run()
{
Activity activity = activityRef.get();
randomMovement(img);
}
});}
else
{Log.d("Fragment one", "Is null");}
}
}, 0, 5000);
}
//listener for the moving ball
private final class ChoiceTouchListener implements View.OnTouchListener {
public boolean onTouch(View view, MotionEvent event){
//Calling Counter
textCount = (TextView) getView().findViewById(R.id.textViewCount);
//switch statement for different events
switch (event.getAction() & MotionEvent.ACTION_MASK){
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_UP:
//this is where youre going to generate randmom location with id.setX(randomX) and id.setY(randomY)
randomMovement(img);
//Setting Counter to count when img is clicked
String countValue = textCount.getText().toString();
scoreCounter = Integer.parseInt(countValue);
scoreCounter++;
textCount.setText(String.valueOf(scoreCounter));
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
}
//checking score
if(scoreCounter == 10 )
{
Toast.makeText(getActivity(),"You win", Toast.LENGTH_LONG).show();
}
viewer.invalidate();
return true;
}
}
}
答案 0 :(得分:0)
首先,我看到您从 onCreateView 调用 super.onActivityCreated 。
其次,isAdded()为false并不意味着getActivity()为null。此方法中还有 mAdded 变量。
第三,如果你有一些计时器,CountDownLatch - 你应该在onStop或onDestroy回调中取消订阅或停止它,以防止内存泄漏。
第四,使用Handler#postDelayed发布一些应该稍后在UI线程上完成的操作。
答案 1 :(得分:0)
删除此行:super.onActivityCreated(savedInstanceState);
。由于您已经定义了片段的状态,因此不需要该行。因此不需要超类变体。也不要从onAttach获取上下文引用,在onActivityCreated中执行。只有生命周期方法才能保证上下文实际可用。
答案 2 :(得分:0)
欢迎使用多线程。首先检查是否添加了该片段并且其活动引用不为空(因为getActivity().runOnUiThread
未崩溃),然后您尝试再次调用getActivity()
,希望它仍然不为空。但在第二次拨打getActivity()
之前,它可以在两者之间进行完美修改。
此处的工作解决方案是将活动引用存储在WeakReference<Activity>
中,然后调用其get()
方法以使用Activity检查它不会变为null。
另一个解决方案是将getActivity()
结果存储到某个变量中,但是当删除Activity时,这可能会导致泄漏。