【问题标题】:Why is my getActivity() null in this situation?为什么在这种情况下我的 getActivity() 为空?
【发布时间】:2017-10-22 20:43:20
【问题描述】:

我不明白为什么我的 runonUiThread 周围的 getActivity() 会返回 null。下面是我遇到问题的代码。我认为这与我放置 onAttach 方法的位置有关,但我不确定。另外请忽略所有 cmets,因为修复此错误后我将清理我的代码。另请注意,这是片段的 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

完整的片段.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;
        }
    }
}

【问题讨论】:

  • 有一个名为“onActivityCreated”的特定片段生命周期方法,可确保已调用活动“onCreate”方法。不要假设它是在此方法之外正确创建的。
  • 能否请您完成您的片段代码,以便我们可以看到您在哪里初始化isAdded()
  • 是的,我现在会对其进行编辑。
  • 好的,编辑已完成,整个片段已发布。
  • 那你怎么称呼这个片段?

标签: java android fragment


【解决方案1】:

首先,我看到您从 onCreateView 调用 super.onActivityCreated

其次,isAdded() 为假并不意味着 getActivity() 为空。此方法中还有 mAdded 变量。

第三,如果您有一些计时器,CountDownLatch - 您应该在 onStop 或 onDestroy 回调中取消订阅或停止它,以防止内存泄漏。

第四,使用Handler#postDelayed 发布一些稍后应在 UI 线程上完成的操作。

【讨论】:

  • 我如何确保它被添加。据我了解,我收到此错误是因为活动未正确添加到片段中吗?如果正确,如何将活动添加到片段中?
  • 使用 onActivityCreated 或 onStart 回调。
【解决方案2】:

删除此行:super.onActivityCreated(savedInstanceState);。不需要该行,因为您已经定义了片段的状态。因此不需要超类变体。也不要从 onAttach 获取上下文引用,在 onActivityCreated 中进行。只有该生命周期方法才能保证上下文实际可用。

【讨论】:

  • 所以要做到这一点,我只需将我的 onAttatch 更改为 onActivityCreated 并保持 on attatch 方法中的所有其他内容相同?我把那个方法放在哪里?在我的 onCreateView 旁边还是什么?
【解决方案3】:

欢迎使用多线程。首先,您检查是否添加了片段并且其活动引用不为空(因为getActivity().runOnUiThread 没有崩溃),然后您尝试再次调用getActivity(),希望它仍然不为空。但在您第二次调用 getActivity() 之前,可以在两者之间进行完美修改。

这里的工作解决方案是将活动引用存储在WeakReference&lt;Activity&gt; 中,然后调用其get() 方法与活动一起检查它是否不会变为空。

另一种解决方案是将getActivity() 结果存储到某个变量中,但这可能会导致泄漏,因为无法删除 Activity。

【讨论】:

  • 我喜欢你的工作解决方案。我该怎么做呢?
  • runOnUiThread 之前添加final WeakReference&lt;Activity&gt; activityRef = getActivity() 然后在runOnUiThread 的runnable 中添加Activity activity = activityRef.get();,检查它是否为null,如果它不为null - 传递给randomMovement 作为第二个参数。
  • 我要不要把final WeakReference&lt;Activity&gt; activityRef = getActivity()直接放在runOnUIThread之前,如下...final WeakReference&lt;Activity&gt; activityRef = getActivity().runonUiThread(new Runnable(){
  • 不,只是final WeakReference&lt;Activity&gt; activityRef = getActivity(); 然后你可以在 onRunUiThread 中使用activityRef 可以称为activityRef.get().runOnUiThread(...
  • 好的,我现在在 final WeakReference&lt;Activity&gt; activityRef = getActivity() 中这样做了,我遇到了类型不兼容的错误
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-04
  • 1970-01-01
  • 2013-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-24
相关资源
最近更新 更多