CefBrowser createBrowser issue

Having problems with building or using the JCEF Java binding? Ask your questions here.

CefBrowser createBrowser issue

Postby chandan » Thu Jul 02, 2020 11:17 am

Hi,

we are trying to replace JXBrowser with JCEF in our application. We are using JCEF in such a way that we will create only one instance of cefBrowser and the same browser instance will be used to load different urls. The URLs will be loaded in different swing modals, tabs etc. But, only one cefBrowser instance will be created. We have few scenarios where the browser UI needs to be shown when the URL is loaded completely. We are trying to use the browser as shown in the following sample program.

Code: Select all
package test;

import org.cef.CefApp;
import org.cef.CefApp.CefAppState;
import org.cef.CefApp.CefVersion;
import org.cef.CefClient;
import org.cef.CefSettings;
import org.cef.OS;
import org.cef.browser.CefBrowser;
import org.cef.handler.CefAppHandlerAdapter;
import org.cef.handler.CefDisplayHandlerAdapter;
import org.cef.handler.CefLifeSpanHandlerAdapter;
import org.cef.handler.CefLoadHandlerAdapter;
import java.awt.*;



/**
 * @author Chandan Talukdar
 */

public class JCEFBrowser {
    private static final String[] COMMAND_LINE_ARGS ={};
    private CefClient cefClient ;
    private boolean browserCreated;
    private CefBrowser cefBrowser;
    private static JCEFBrowser jcefBrowser;


    static JCEFBrowser getBrowserInstance() {
        if(jcefBrowser == null) {
            jcefBrowser = new JCEFBrowser();
        }
        return jcefBrowser;
    }

    JCEFBrowser() {
        initializeCefClient();
        createBrowser("", true); //create immediately
    }


    private void initializeCefClient() {

        cefClient = getCefApp().createClient();

        // The different life span phases can be captured with LifeSpanHandler
        cefClient.addLifeSpanHandler(new CefLifeSpanHandlerAdapter() {
            @Override
            public void onAfterCreated(CefBrowser browser) {
                // Browser is created and ready to load a URL
                System.out.println("Browser Created: " + browser.getIdentifier());
                browserCreated = true;
            }

            @Override
            public void onAfterParentChanged(CefBrowser browser) {
                System.out.println("Browser onAfterParentChanged: " + browser.getIdentifier());
            }

            @Override
            public boolean doClose(CefBrowser browser) {
                boolean result = browser.doClose();
                return result;
            }

            @Override
            public void onBeforeClose(CefBrowser browser) {
                browserCreated = false;
                cefBrowser = null;
            }
        });

        cefClient.addLoadHandler(new CefLoadHandlerAdapter() {
            @Override
            public void onLoadingStateChange(CefBrowser browser, boolean isLoading,
                                             boolean canGoBack, boolean canGoForward) {
                if (!isLoading) {
                    System.out.println("Browser loaded: " + browser.getIdentifier());
                }
            }


        });

        cefClient.addDisplayHandler(new CefDisplayHandlerAdapter() {
            @Override
            public boolean onConsoleMessage(CefBrowser browser, CefSettings.LogSeverity level,
                                            String message, String source, int line) {
                return true;
            }
        });
    }

    private CefApp getCefApp() {
        if (CefApp.getState() != CefApp.CefAppState.INITIALIZED) {
             CefSettings settings = new CefSettings();
            settings.windowless_rendering_enabled = OS.isLinux();
            CefApp cefApp = CefApp.getInstance(COMMAND_LINE_ARGS, settings);
            CefVersion version = cefApp.getVersion();
            System.out.println("Using CEF version:\n" + version);
            CefApp.addAppHandler(new CefAppHandlerAdapter(COMMAND_LINE_ARGS) {
                @Override
                public void stateHasChanged(CefAppState cefAppState) {
                    if (cefAppState == CefAppState.TERMINATED) {
                        System.out.println("State is TERMINATED");
                        System.exit(0);
                    }
                }
            });
            return cefApp;
        } else {
            return CefApp.getInstance();
        }
    }


    private void createBrowser(String url, boolean createImmediately) {
        cefBrowser = cefClient.createBrowser(url,  OS.isLinux(), false);
        if(createImmediately) {
            cefBrowser.createImmediately();
        }
    }

    Component getComponent() {
        return cefBrowser.getUIComponent();
    }



    void loadURLAndWait(String url) {
        cefBrowser.loadURL(url);
        // We want to wait here till URL is loaded completely.
        //Need to implement this as a blocking API.
        //if we wait here then the processing itself is block as we are inside an event dispatcher thread
    }

}


We are calling this code from a modal window in following way:
Code: Select all
 
package test;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/**
 * @author Chandan Talukdar
 */

class JCEFModal extends JFrame {

    JCEFModal( String title) {
        setName(title);
        Component component = createUIComponents();
        add(component);
        setSize(800, 600);
        setVisible(true);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                dispose();
            }
        });

    }

    private Component createUIComponents() {

        JCEFBrowser jcefBrowser = JCEFBrowser.getBrowserInstance();

        String htmlUrl = "www.google.com";

            jcefBrowser.loadURLAndWait(htmlUrl);

        jcefBrowser.getComponent().setVisible(true);

        return jcefBrowser.getComponent();

    }


}


Code: Select all
package test;

import org.cef.CefApp;
import javax.swing.*;
import java.awt.event.*;


/**
 * @author Chandan Talukdar
 */

public class JCefExample extends JFrame {


    private JCefExample(String title) {
        setTitle(title);
        setName(title);

        JButton button = new JButton("click");
        button.addActionListener(
            e -> new JCEFModal("JCEFExampleModal")
        );
        button.setBounds(165, 135, 115, 55);
        add(button);
        setSize(500, 400);
        setLayout(null);
        setVisible(true);
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                CefApp.getInstance().dispose();
                dispose();
            }
        });
    }

    public static void main(String[] args) {
        new JCefExample("JCEF Example");
    }
}




In class JCEFBrowser we are trying to create the cef browser from JCEFBrowser constructor. Due to this we are facing the following issues.
1. We are creating browser with createImmediately so that the browser is created immediately and doesn't wait for a view to be attached. when we call loadURLAndWait from the modal, the browser is not crated at the time when loadUrl is called and hence loadUrl fails for the first time.
2. Also we cannot wait for the browser to be created under JCEFBrowser.createBrowser() as the call is made from an Event dispatcher thread and a wait will block the whole thread.
3. We also want to wait till the url is loaded completely on the browser in the method JCEFBrowser.loadURLAndWait()

Basically we want to make the JCEFBrowser.loadURLAndWait() a synchronous call. Any suggestion will be much appreciated.

We are using Using:
JCEF Version = 81.2.24.251
CEF Version = 81.2.24
Chromium Version = 81.0.4044.113
2. Java version used is 1.8.0_201-b09 and OS is Windows 7 x64 bit

Thanks
Chandan
chandan
Techie
 
Posts: 10
Joined: Wed May 27, 2020 4:41 am

Re: CefBrowser createBrowser issue

Postby magreenblatt » Thu Jul 02, 2020 11:24 am

Synchronous calls are generally a bad idea, as most things work asynchronously. What thread were you planning to block with JCEFBrowser.loadURLAndWait()?
magreenblatt
Site Admin
 
Posts: 12408
Joined: Fri May 29, 2009 6:57 pm

Re: CefBrowser createBrowser issue

Postby chandan » Thu Jul 02, 2020 11:34 am

Thanks Marshall for the quick reply.

I want to block the thread called from the method JCEFModal.createUIComponents(). I know this is an event dispatcher thread. The idea is to not complete the call till loadUrl is completed. the other issue is that I am facing is browser is not created when the first call to JCEFBrowser.loadURLAndWait() is made.
chandan
Techie
 
Posts: 10
Joined: Wed May 27, 2020 4:41 am

Re: CefBrowser createBrowser issue

Postby magreenblatt » Thu Jul 02, 2020 11:42 am

chandan wrote:I want to block the thread called from the method JCEFModal.createUIComponents(). I know this is an event dispatcher thread.

You should not block the event dispatcher thread.

chandan wrote:the other issue is that I am facing is browser is not created when the first call to JCEFBrowser.loadURLAndWait() is made.

This is quite possibly because you're blocking the event dispatcher thread.
magreenblatt
Site Admin
 
Posts: 12408
Joined: Fri May 29, 2009 6:57 pm


Return to JCEF Forum

Who is online

Users browsing this forum: No registered users and 26 guests