Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

the best practice to integrate arFragment (sceneForm) with existing Fragment APP

We have been working on adding AR features to our existing APP for a couple of months with limited progress. Very excited to read the recent development from google on sceneForm and arFragment. our current APP consists three Fragments and one of them will need AR features.

It looks straight forward to us,so We replaced the Fragment in our APP with arFragment. The build is successful and stopped during running with little information for debugging. any suggestion on the proper steps for us to upgrade from Fragment to arFragment? or maybe I missed the points of arFragment here?

in order to show the problem without for you to go through our length code (yet valuable to us), we constructed a dummy project based on the sample project from Google: HelloSceneform. Basically, we changed the static Fragment to dynamic Fragment. Only two files are changed and two files are added, which are attached thereafter. The modified project can be built successfully, but stopped when starting to run.

Thank you

Peter

/////// File modified, HelloSceneformActivity.java:

import android.support.v4.app.FragmentTransaction;

// private ArFragment arFragment;
private ItemOneFragment arFragment;
//arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.ux_fragment);
arFragment =  ItemOneFragment.newInstance();

//Manually displaying the first fragment - one time only
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, arFragment);
transaction.commit();

/////// File modified, activity_ux.xml:

<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=".HelloSceneformActivity">

</FrameLayout>

////// File added fragment_item_one.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/frame_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ItemOneFragment">
</FrameLayout>

/////// File added, ItemOneragment.java:

package com.google.ar.sceneform.samples.hellosceneform;

import android.os.Bundle;    
import android.view.LayoutInflater;
import android.view.View; 
import android.view.ViewGroup;
import com.google.ar.sceneform.ux.ArFragment;

public class ItemOneFragment extends ArFragment {

  public static ItemOneFragment newInstance() {
    ItemOneFragment fragment = new ItemOneFragment();
    return fragment;
  }
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_item_one, container, false);
  }

}

like image 886
Peter Yin Avatar asked Aug 31 '25 22:08

Peter Yin


2 Answers

I have experienced the same when I try to add the ArFragment dynamically to my activity. It is crashing because I was trying to access the ArSceneView right after I commit the fragment which appeared to be null at that point.

The solution that worked for me was to implement a completion listener that will provide a callback in the Activity when the fragment is done configuring the ARSession.

Below is the basic idea.

public class MyActivity implements MyArFragment.OnCompletionListener{

     @Override
     protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);                  
      getSupportFragmentManager().beginTransaction().add(R.id.fragment_holder,  new 
        MyArFragment(), "my_arfragment").commit();
     }

     @Override
     public void onComplete() {
       ArFragment arFragment = (ArFragment) getSupportFragmentManager().findFragmentByTag("my_arfragment");
       ArSceneView view = arFragment.getArSceneView();
       Scene scene = view.getScene();
       scene.addOnUpdateListener(this::onUpdateFrame);
     }
}

And the fragment:

public class MyFragment extends ArFragment{
  public static interface OnCompleteListener {
        public abstract void onComplete();
  }

  private OnCompleteListener mListener;

   @Override
   public void onAttach(Context context) {
      super.onAttach(context);
      try {
         this.mListener = (OnCompleteListener)context;
      }
      catch (final ClassCastException e) {
         throw new ClassCastException(context.toString() + " must implement 
          OnCompleteListener");
      }
   }


   @Override
   protected Config getSessionConfiguration(Session session) {
      //Update session config...
      mListener.onComplete();
      return config;
   }

}
like image 107
kdroider Avatar answered Sep 04 '25 08:09

kdroider


In one of my project I've used the following structure to accomplish the integration of ArFragment. Maybe this will give you some new hints.

I have a root layout with the first element that is a FrameLayout called "body".

This "body" is used as a placeholder to switch the 3 Fragment that exist into the app. One of these 3 is called "SimulationFragment" and extends ArFragment of Sceneform. The corresponding layout is composed by the root FrameLayout with some elements and another nested FrameLayout called "ar_frameLayout".

At Runtime I've changed the implementation of onCreateView for the SimulationFragment with a direct call of super.onCreateView() that gives me the base view of ArFragment (this call initializes also the scene from getArSceneView().getScene()). After that I've added this view into the container view of the simulation fragment that I've previously inflated and then returned it. Something like this:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    View containerView = inflater.inflate(R.layout.fragment_simulation, container, false);
    FrameLayout arCoreFrameLayout = containerView.findViewById(R.id.ar_core_frame_layout);
    // Inflate the layout for this fragment
    View view = super.onCreateView(inflater, container, savedInstanceState);


    arCoreFrameLayout.addView(view);
    return containerView;
}
like image 26
TomD88 Avatar answered Sep 04 '25 09:09

TomD88