Java Question b4a replaces ContentView when Activity subclass used

Discussion in 'Libraries developers questions' started by warwound, May 19, 2015.

  1. warwound

    warwound Expert Licensed User

    I'm trying to wrap the PanoramaGL library.
    This requires that the PLView class is used instead of the 'standard' android Activity class.
    PLView extends Activity.

    So in my b4a activity module i use the attribute:

    Code:
    #Extends: com.panoramagl.PLView
    I'm unable to get any panorama to display.
    Even reproducing the very simple java example in b4a displays nothing.
    This is the very simple java example:

    Code:
    @Override
    public void onCreate(Bundle savedInstanceState){
         super.onCreate(savedInstanceState);
         PLSpherical2Panorama panorama = new PLSpherical2Panorama();
         panorama.setImage(new PLImage(PLUtils.getBitmap(this, R.raw.spherical_pano), 
    false));
         this.setPanorama(panorama);
    }
    I created a new java android project using Android Studio, imported the android library files and tried the above example.
    I see a panorama displayed.

    I think the problem is that b4a uses the PLView but set's a BALayout as the activity's 'ContentView', my compiled b4a activity source code shows in onCreate():

    Code:
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
    if (isFirst) {
            processBA = new BA(this.getApplicationContext(), 
    nullnull"uk.co.martinpearman.b4a.panoramaglexample""uk.co.martinpearman.b4a.panoramaglexample.main");
            processBA.loadHtSubs(this.getClass());
            float deviceScale = getApplicationContext().getResources().getDisplayMetrics().density;
            BALayout.setDeviceScale(deviceScale);
            
        
    }
        else if (previousOne != null) {
            Activity p = previousOne.get();
            if (p != null && p != this) {
                BA.LogInfo("Killing previous instance (main).");
                p.finish();
            }
        }
        processBA.runHook("oncreate", this, null);
        if (!includeTitle) {
            this.getWindow().requestFeature(android.view.Window.FEATURE_NO_TITLE);
        }
        if (fullScreen) {
            getWindow().setFlags(android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN,   
                    android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN);
        }
        mostCurrent = this;
        processBA.sharedProcessBA.activityBA = null;
        layout = new BALayout(this);
        setContentView(layout);
        afterFirstLayout = false;
        BA.handler.postDelayed(new WaitForLayout(), 5);
    }
    b4a is i think overwriting the GLSurfaceView created by PLView.
    No exceptions are raised and my b4a activity silently fails to render it's panorama.
    Instead i see just the empty BALayout.

    Is there a solution for this?
    Can i prevent b4a from calling setContentView?
     
  2. thedesolatesoul

    thedesolatesoul Expert Licensed User

    Can you try to do it using inline java?
    In Activity_Create call your inline java sub for onCreate?
    I remember there is a hook for oncreate, it seems it runs before contentview is set, so im guessing if you call your java/oncreate sub after this it will override whatever the autogen code did.
     
    NJDude likes this.
  3. Erel

    Erel Administrator Staff Member Licensed User

    I agree. You should call it from the Activity_Create event. You should probably do something as done in the IME library:
    Code:
    ExtendedBALayout e = new ExtendedBALayout(ba.context, eventName, ba);
         ba.activity.setContentView(e);
         BALayout.LayoutParams lp = new BALayout.LayoutParams();
         lp.height = ba.vg.getLayoutParams().height;
         lp.width = ba.vg.getLayoutParams().width;
         ba.vg.setLayoutParams(lp);
         e.addView(ba.vg);
     
    thedesolatesoul likes this.
  4. warwound

    warwound Expert Licensed User

    I couldn't understand where Erel's code was meant to be executed?
    In the inline java _onCreate() callback?

    Anyway i found a better solution...

    PLView extends Activity, and the b4a activity must use PLView.
    I sub-classed PLView overriding it's setContentView method:

    Code:
    public class B4APLView extends PLView {
        
        @Override
        
    public void setContentView(View view) {
            
    if(view instanceof BALayout){
                BA.LogInfo(
    "converting setContentView to addContentView");
                this.addContentView(
    view, new BALayout.LayoutParams(00, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            
    } else {
                //    this never gets executed
                BA.LogInfo("allowing call to setContentView");
                super.setContentView(view);
            }
        }
    }
    My b4a activity now uses B4APLView instead of PLView.
    You can see that i intercept the call which sets the BALayout as the 'content view' and add the BALayout as the content view instead of setting it.
    This leaves the PLView's GLSurfaceView intact and my b4a now correctly displays my panorama image.

    I added a Panel in my b4a activity Activity_Create and sized it using 50%x, 50%y - it properly sizes itself to half of the screen's width and height.
    I added a Button to the Panel and added a Log statement to the Button Click callback - the callback is executed when the Button is clicked.
    So all b4a stuff seems to work normally and the panorama view is working too :).

    Thanks all.

    Martin.
     
  5. thedesolatesoul

    thedesolatesoul Expert Licensed User

    Interesting, informative and clever!
    I feel its a bit convoluted and like the layers of an onion. Had the B4A activity also overrided setContentView you couldnt do this.
    The B4A generated code is just creating a layout and setting it to the contentview, do you think it was necessary to do the 'addContentView'?
    Thanks.
     
  6. warwound

    warwound Expert Licensed User

    LOLS i didn't elaborate in my last post but will do so now...

    If my setContentView() did nothing with the BALayout then the entire b4a activity 'stalls'.

    When the BALayout 'has layout', sometime after it is added to the View hierachy, it's onLayout callback is called.
    When that callback is called, b4a is listening and now continues to initialize the activity.
    b4a waits for that onLayout to be called before it itself calls the Activity_Create callback.

    If my setContentView() method silently ignored the BALayout passed to it then the BALayout's onLayout callback isn't called, the b4a code waiting for the onLayout callback never gets executed and the Activity_Create never gets called.

    Even if Activity_Create was called you'd not be able to display any Views or Layouts as there'd be no BALayout for BA to add them to.

    addContentView so far appears to work perfectly - i have the traditional b4a BALayout to use for any UI elements and my GLSurfaceView accelerated panorama works nice n smooth.
     
  7. thedesolatesoul

    thedesolatesoul Expert Licensed User

    wow what a spaghetti!
    but its really insane how you managed to make it work...im guessing trial and error...but it truly boggles my mind
    i went back to a generated b4a activity to see whats going on...you are right, by the time _activity_create is called we are in afterFirstLayout.

    So what you have done is im guessing that PLView also calls setContentView method but within its own class, so that gets set there. And when B4AActivity calls setContentView the one in B4APLView gets called. Somehow by that time you are sure that the panoramaview has created and been added to the contentView, thats why you use addContentView for the BALayout.

    What I would have thought to do, is to let onCreate run, and in _activity_create, i'd call a native injava method and created and called this.setpanorama there. (with the disadvantage that now this.setpanorama calls this.setContentView thus we lose the BALayout if we dont want to modify the PLView class). But also possibly add another BALayout to the activity as well (although i dont know if that requires some WaitForLayout again).
     
  8. warwound

    warwound Expert Licensed User

    Look at the code in post #4, see the comment "this never gets called"?
    Only b4a calls setContentView, the PanoramaGL libraries doesn't call setContentView.
    I think PanoramaGL simply gets the default content view and makes it into a GLSurfaceView.

    If there was a call to setContentView that i did not want to block then you'll see that super.setContentView is used to call the default super class setContentView method instead of my overridden setContentView method.

    So PanoramaGL at no point overwrites the default android content view, it's only b4a that tries to overwrite the default content view.
     
  9. thedesolatesoul

    thedesolatesoul Expert Licensed User

  10. warwound

    warwound Expert Licensed User

    Ah yes you're right - PLView does call setContentView.

    I was looking in the logs only until the b4a Activity_Create callback had been executed and at that point had not added a panorama to the PLView.
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice