0

When returning to IpFragment via navigateUp() it sometimes is blank, when it should be showing a couple simple textviews. Sometimes it renders correctly, but when it fails, the only error seems unrelated.

The fragment which appears blank when returning to it:

public class IpFragment extends Fragment implements ...{
    private static final String TAG = "IpFragment";

    private NavController navController;
    private Context context;
    private TextView tvIp;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        navController = NavHostFragment.findNavController(this);
        View v = inflater.inflate(R.layout.fragment_ip, container, false);
        context = v.getContext();
        return v;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        Log.d(TAG, "onViewCreated");

        ConnectivitySingleton.getInstance().registerCallback(this);

        tvIp = view.findViewById(R.id.tvIp);
        tvIp.setText(getDeviceIp());
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();

        ConnectivitySingleton.getInstance().unregisterCallback(this);
    }

    ...
}

The fragment we return from:

public class InterviewFragment extends Fragment implements ConnectionCallback, StreamStatusCallback, TextureView.SurfaceTextureListener, SpeakCallback {
    private static final String TAG = "InterviewFragment";

    private NavController navController;
    private AutoFitDrawableView autoFitDrawableView;
    private Context context;
    public boolean isStreaming;
    private MessageConnection messageConnection;

    private TextView tvQuestion;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "onCreateView");
//        return super.onCreateView(inflater, container, savedInstanceState);
        navController = NavHostFragment.findNavController(this);
        View v = inflater.inflate(R.layout.fragment_interview, container, false);
        context = v.getContext();
        return v;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "onViewCreated");
        super.onViewCreated(view, savedInstanceState);
        ConnectivitySingleton.getInstance().registerCallback(this);
        VisionSingleton.getInstance().registerCallback(this);
        SpeakSingleton.getInstance().registerCallback(this);

        autoFitDrawableView = view.findViewById(R.id.autofit);
        // need to set autoFitDrawableView's display size / rotation
        int rotation = ((Activity) context).getWindowManager().getDefaultDisplay().getRotation();
        autoFitDrawableView.setPreviewSizeAndRotation(800, 600, rotation); // w 800 h 600
        // set listener to stream frames
        autoFitDrawableView.setSurfaceTextureListenerForPreview(this);

        tvQuestion = view.findViewById(R.id.question);
    }

    @Override
    public void onDestroyView() {
        Log.d(TAG, "onDestroyView");
        super.onDestroyView();
        ConnectivitySingleton.getInstance().unregisterCallback(this);
        VisionSingleton.getInstance().unregisterCallback(this);
        SpeakSingleton.getInstance().unregisterCallback(this);
    }

    @Override
    public void onConnected() {
    }

    @Override
    public void onDisconnected() {
        navController.navigateUp();
    }

    @Override
    /**
     * Passes surfaceTexture to VisionSingleton once ST is available. VisionSingleton then sets up
     * DTS camera to stream to surfaceTexture.
     */
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
        Log.d(TAG, "onSurfaceTextureAvailable");
        VisionSingleton.getInstance().initPreview(surfaceTexture);
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) { }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
        Log.d(TAG, "onSurfaceTextureDestroyed");
        VisionSingleton.getInstance().stopPreview();
        return false;
    }

    @Override
    /**
     * If a 'vision start' command has been received, then surfaceTexture's frame should be sent to
     * the phone app via messageConnection.
     */
    public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
        if(isStreaming) {
            try {
                int tvWidth = autoFitDrawableView.getPreview().getWidth();
                int tvHeight = autoFitDrawableView.getPreview().getHeight();

                // Get bitmap from TextureView
                Bitmap bm = Bitmap.createBitmap(tvWidth, tvHeight, Bitmap.Config.ARGB_8888);
                autoFitDrawableView.getPreview().getBitmap(bm);

                // Compress via JPG
                ByteArrayOutputStream os = new ByteArrayOutputStream();
                bm.compress(Bitmap.CompressFormat.JPEG, 50, os);
                byte[] byteArray = os.toByteArray();

                Log.d(TAG, "Byte size: " + byteArray.length);
                if (byteArray.length > 1000000) {
                    Log.w(TAG, "Byte size is > 1 MB! Exceeds max sending size.");
                } else {
                    messageConnection.sendMessage(new BufferMessage(byteArray));
                }
            } catch (Exception e) {
                e.printStackTrace();
                Log.e(TAG, e.getMessage());
            }
        }

    }

    @Override
    public void onStartStream(final MessageConnection messageConnection) {
        Log.d(TAG, "onStartStream");
        isStreaming = true;
        this.messageConnection = messageConnection;
    }

    @Override
    public void onStopStream() {
        Log.d(TAG, "onStopStream");
        isStreaming = false;
    }

    @Override
    public void onSpeakCommandReceived(String question) {
        tvQuestion.setText(question);
    }
}

Sometimes in InterviewFragment I get this caught error, which doesn't break anything at the time, but later when returning to IpFragment, it appears blank.

08-07 22:45:54.921 5196-5275/edu.unc.etlab.robojloomo W/MessageListener: Exception occured during command launch
    android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
        at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6357)
        at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:874)
        at android.view.View.requestLayout(View.java:17476)
        at android.view.View.requestLayout(View.java:17476)
        at android.view.View.requestLayout(View.java:17476)
        at android.view.View.requestLayout(View.java:17476)
        at android.view.View.requestLayout(View.java:17476)
        at android.view.View.requestLayout(View.java:17476)
        at android.support.constraint.ConstraintLayout.requestLayout(ConstraintLayout.java:3172)
        at android.view.View.requestLayout(View.java:17476)
        at android.view.View.requestLayout(View.java:17476)
        at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:360)
        at android.view.View.requestLayout(View.java:17476)
        at android.widget.TextView.checkForRelayout(TextView.java:6865)
        at android.widget.TextView.setText(TextView.java:4057)
        at android.widget.TextView.setText(TextView.java:3915)
        at android.widget.TextView.setText(TextView.java:3890)
        at edu.unc.etlab.robojloomo.InterviewFragment.onSpeakCommandReceived(InterviewFragment.java:168)
        at edu.unc.etlab.robojloomo.loomo_services.SpeakSingleton.speak(SpeakSingleton.java:69)
        at edu.unc.etlab.robojloomo.listeners.SpeakCommand.execute(SpeakCommand.java:14)
        at edu.unc.etlab.robojloomo.listeners.MessageListener.onMessageReceived(MessageListener.java:85)
        at com.segway.robot.sdk.connectivity.RobotMessageConnection.handleMessage(RobotMessageConnection.java:219)
        at android.os.Handler.dispatchMessage(Handler.java:98)
        at android.os.Looper.loop(Looper.java:135)
        at android.os.HandlerThread.run(HandlerThread.java:61)

This error happens when I set the text of a textView within InterviewFragment:

    public void onSpeakCommandReceived(String question) {
        tvQuestion.setText(question);
    }
mhudnell
  • 121
  • 1
  • 8

1 Answers1

0

Ok, so quickly after posting this question I fixed it. I referred to this post to fix the error I was getting: Android "Only the original thread that created a view hierarchy can touch its views.". and I changed onSpeakCommandReceived() to:

    public void onSpeakCommandReceived(final String question) {
        getActivity().runOnUiThread(new Runnable() {
            @Override
            public void run() {
                tvQuestion.setText(question);
            }
        });
    }

Still not sure how this error caused the next screen to be blank, since they occur at different times, but now the error is fixed everything seems to work.

mhudnell
  • 121
  • 1
  • 8