0

Here is my simplified setup

//--- sample.com app ---//

async fetchFromServer() {
    // return promise..
}

function App() {
    const [sampleState, setSampleState] = React.useState(null)

    React.useEffect(() => {
        fetchFromServer().then((data) => {
            setSampleState(data)
        })
    }, [])

  return (
    <p>{JSON.stringify(sampleState)}</p>
  );
}

//--- android app ---//

public class SampleWebActivity extends Activity {
    SamleWebInterface mWebInterface;
    WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        mWebView = new WebView(this);
        setContentView(mWebView);
    
        mWebInterface = new SamleWebInterface();
        mWebView.addJavascriptInterface(mWebInterface, "Native");
        //...
        mWebView.loadUrl("https://sample.com");
    }
}

// Somewhere in another activity
private void showWebScreen() {
    Intent intent = new Intent(this, SampleWebActivity.class);
    // use existing activity if present
    intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
    startActivity(intent);
}

//--- Question ---//

How can I re-fetch sampleState from server every time SampleWebActivity is shown without reloading the whole page? I want to aviod reloading because the actual web app is much bigger than the sample. Also I don't know the exact state of the web app so it's not clear which url to load. I want to show whetever whas shown before the activity was switched but with updated data.

I'm aware of WebView.evaluateJavascript() but don't know how to interact with the react app after it's compiled into vanilla js.

1 Answer 1

1

Using the Webview (browser) itself:

You could just use the webview's built in event system, i.e. When the webview returns from being backgrounded for instance you can leverage the document.visibilityState API (https://developer.mozilla.org/en-US/docs/Web/API/Document/visibilityState):

async fetchFromServer() {
  // return promise..
}

function App() {
  const [sampleState, setSampleState] = React.useState(null)

  React.useEffect(() => {
      const fetchData = () => {
        if (document.visibilityState !== "hidden") {
          fetchFromServer().then((data) => {
              setSampleState(data)
          })
        }
      }
      fetchData();
      document.addEventListener("visibilitychange", fetchData);
      return () => document.removeEventListener("visibilitychange", fetchData);
  }, [])

return (
  <p>{JSON.stringify(sampleState)}</p>
);
}

Injecting/Calling from Java:

async fetchFromServer() {
  // return promise..
}
  
function App() {
  const [sampleState, setSampleState] = React.useState(null)

  React.useEffect(() => {
      const fetchData = () => {
        fetchFromServer().then((data) => {
            setSampleState(data)
        })
      }
      /**
       * Make some globals
       */
      window.__triggerRefetch__ = fetchData;
      window.__setState__ = setSampleState;
      fetchData();
      return () => {
        /**
         * Remove the globals
         */
        delete window.__triggerRefetch__;
        delete window.__setState__;
      }
  }, [])

  return (
    <p>{JSON.stringify(sampleState)}</p>
  );
}

You trigger a refetch with WebView.evaluateJavascript("window.__triggerRefetch__()") or you can inject data with something like WebView.evaluateJavascript("window.__setState__({foo: "bar"})")

Sign up to request clarification or add additional context in comments.

4 Comments

Is there a way to create and trigger a custom event where I can pass some data from java? So even a trip to the server may not be needed.
I've updated the answer to support both methods: browser event and injecting view Java
Thanks, this works! I actually oversimplified the example. The real app is written in typestript which doesn't allow assignment to non-existing properties of 'window'. So I did the assignment in a separate javascript module which I imported into typestript. Just wonder if there is a better workaround.
Quick and dirty: (window as any).__triggerRefetch__ or extend the window interface: declare global { interface Window { __triggerRefetch__?: () => void } }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.