How can we check if there is Internet connectivity in the application or not in SmartGWT or GWT? I have to determine that whether there is internet connection or not and based on that change the icon for Internet connectivity to either green or red so is there a way to do it in SmartGWT or GWT?
You can create a native method in which you create a new image object (new Image()) and attach handler to it's onload and onerror properties. You can point the image's src property to some URL that you feel indicates being online. Then from your onload and onerror methods you can call methods in your GWT component to update your connectivity indicator. You need to set img.src after you set img.onload and img.onerror.
For example:
native void checkConnectivity(Example obj) /*-{
var img = new Image();
img.onload = function() {
obj.#com.example.client.Example::online()();
}
img.onerror = function() {
obj.#com.example.client.Example::offline()();
}
img.src = "http://exampleapp.com/test.gif";
}-*/;
I think the navigator.onLine will help you:
http://html5demos.com/offline
http://www.html5rocks.com/en/features/offline
You may need to wrap the calls into JSNI and also implement an eventlistener.
public native Boolean isOnline()/*-{
return window.onLine;
}-*/;
Udeleng's solution is the closest i have come to a cross-browser approach. I have been testing it on FF 18 but i believe it will work in any browser.
However, note that the browser pre-loads the image when you call new Image(), caching it such that subsequent calls to the same URL don't make an HTTP call. This kills the effect we want to achieve i.e. transition from offline to online status works but as soon as the browser gets any connection, the image is cached, and end of story, even if you unplug your ethernet cable.
SOLUTION
Add a state parameter to the URL and give it a random number, the idea is to trick the browser into thinking its a new image such that the image is fetched from the server each time, rather than the cache.
Of course you need to add the timer. Here is my code:
import com.google.gwt.core.shared.GWT;
import com.google.gwt.user.client.Timer;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Img;
import com.smartgwt.client.widgets.events.DrawEvent;
import com.smartgwt.client.widgets.events.DrawHandler;
public class WebConnChecker extends Img {
private static final String ONLINE="online_stat.jpg";
private static final String OFFLINE="offline_stat.jpg";
private static final int INTERVAL=10000;
private Timer timer;
public WebConnChecker(){
setSize(16);
timer=new Timer() {
#Override
public void run() {
checkConnectivity(WebConnChecker.this);
}
};
addDrawHandler(new DrawHandler() {
#Override
public void onDraw(DrawEvent event) {
timer.scheduleRepeating(INTERVAL);
}
});
}
private void online(){
log("online detected");
this.setSrc(ONLINE);
}
private void offline(){
log("offline detected");
this.setSrc(OFFLINE);
}
private native void checkConnectivity(WebConnChecker checker) /*-{
var img = new Image();
img.onload = function() {
window.alert("online");
checker.#com.telligent.smap.student.client.util.WebConnChecker::online()();
}
img.onerror = function() {
window.alert("offline");
checker.#com.telligent.smap.student.client.util.WebConnChecker::offline()();
}
img.src = "http://cdn.sstatic.net/stackoverflow/img/apple-touch-icon.png?v=41f6e13ade69&state="+Math.floor(Math.random() * 100);
}-*/;
}
Hope it works for you
Related
This question is a follow up to this problem here: How to make retrofit API call using ViewModel and LiveData
The mistakes 1 and 2 highlighted in that post's response have been fixed. For mistake 3, I haven't yet moved the API call to a repository, but I will once the code start working properly.
So I'm trying to make an API call using Retrofit, using MVVM with LiveData and ViewModel. The API call (which currently is in the ViewModel), is working properly, but the changes is not being picked up by the Observer in the Activity.
I've setup my ViewModel observer as follow:
public class PopularGamesActivity extends AppCompatActivity {
private static final String igdbBaseUrl = "https://api-endpoint.igdb.com/";
private static final String FIELDS = "id,name,genres,cover,popularity";
private static final String ORDER = "popularity:desc";
private static final int LIMIT = 30;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_popular_games);
PopularGamesViewModel popViewModel = ViewModelProviders.of(this).get(PopularGamesViewModel.class);
popViewModel.getGameList().observe(this, new Observer<List<Game>>() {
#Override
public void onChanged(#Nullable List<Game> gameList) {
String firstName = gameList.get(0).getName();
Timber.d(firstName);
}
And my ViewModel code is as follow:
public class PopularGamesViewModel extends AndroidViewModel {
private static final String igdbBaseUrl = "https://api-endpoint.igdb.com/";
private static final String FIELDS = "id,name,genres,cover,popularity";
private static final String ORDER = "popularity:desc";
private static final int LIMIT = 30;
public PopularGamesViewModel(#NonNull Application application) {
super(application);
}
public LiveData<List<Game>> getGameList() {
final MutableLiveData<List<Game>> gameList = new MutableLiveData<>();
// Create the retrofit builder
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(igdbBaseUrl)
.addConverterFactory(GsonConverterFactory.create());
// Build retrofit
Retrofit retrofit = builder.build();
// Create the retrofit client
RetrofitClient client = retrofit.create(RetrofitClient.class);
Call<List<Game>> call = client.getGame(FIELDS,
ORDER,
LIMIT);
call.enqueue(new Callback<List<Game>>() {
#Override
public void onResponse(Call<List<Game>> call, Response<List<Game>> response) {
Timber.d("api call sucesss");
if (response.body() != null) {
Timber.d("First game: " + response.body().get(0).getName());
gameList.setValue(response.body());
}
}
#Override
public void onFailure(Call<List<Game>> call, Throwable t) {
Timber.d("api call failed");
}
});
return gameList;
}
}
When I run the code, the onResponse in the ViewModel class will output the correct response from the API call, so the call is working properly. But the onChanged() in the PopularGamesActivity class will never get called. Can someone shed some light on what I'm doing wrong? Thank you!
Ok, so this turned out to be a weird android studio bug. I was initially running the code on my real nexus 4 device, and the onChange never gets called. However, after running it on an emulated device, it started working immediately. And now, it's working on my real device too.
I don't know the actual reason behind it, but if anyone in the future run into a problem where onChange won't get called, try switching device/emulators.
Cheers.
I debug the code on a device and have the same problem.
M'n solution was simply activate the device screen.
The screensaver was the problem..
we have admin dashboard build in gwt and deployed on google app engine for java. On the dashboard there is a feature called "my card" where a blood donor can see his blood donor registration card with us.
Currently, we are creating and storing this card on google storage and when someone goes to "My Card" we render the card using iFrame in our dashboard.
We want to give the ability to print this card. Please tell how to do it?
just to add on i tried Print.it jar but seems like it is obsolete and does not play nice with gwt anymore
Add this script to the iframe content page's tag
<script type="text/javascript">
function printPage() {focus();print(); }
</script>
Add this native method to your GWT class
public native void printIframeContent(String id)/*-{
var iframe = $doc.getElementById(id);
var ifWin = iframe.contentWindow || iframe;
iframe.focus();
ifWin.printPage();
return false;
}-*/;
The action handler for print button's click event.
public void onClick(ClickEvent event) {
printIframeContent("printiframe"); // Use the correct id for your iframe
}
Code is derived from this discussion
Here is a simple Printer class for GWT. It prints out the page.
import com.google.gwt.user.client.ui.UIObject;
import com.google.gwt.user.client.Element;
public class Printer {
public static native void it(String html) /*-{
var frame = $doc.getElementById('__printingFrame');
if (!frame) {
$wnd.alert("Error: Can't find printing frame.");
return;
}
frame = frame.contentWindow;
var doc = frame.document;
doc.open();
doc.write(html);
doc.close();
frame.focus();
frame.print();
}-*/;
public static void it(UIObject obj) {
it("", obj.getElement().toString());
}
public static void it(Element element) {
it("", element.toString());
}
public static void it(String style, String it) {
it("<it><header>"+style+"</header><body>"+it+"</body></it>");
}
public static void it(String style, UIObject obj) {
it(style, obj.getElement().toString());
}
public static void it(String style, Element element) {
it(style, element.toString());
}
}
I am trying to invoke a Java Method from my Javascript code. This is for a Windows Phone 7 app using Phonegap.
I have the following in my javascript code.
document.addEventListener("backbutton", onBackKeyDown, false);
function onBackKeyDown(){
}
And in my Java code I have the following.
public static native void exportStaticMethod() /*-{
$wnd.onBackKeyDown =
$entry(this.#com.mycompany.myapp.client.MyApp::hideSettingsWidgets());
}-*/;
Then in the on onModuleLoad() I am calling it like so:
MyApp.exportStaticMethod();
It does not work I have an alert in the hideSettingsWidgets() but it never gets shown.
*EDIT*
Here is some more code. The EventListener is not added in the Javascript. It is specifically added withing the java code. I could not get the listeners to register originally so here is what I added.
public static native void removeBackListener() /*-{
$wnd.removeTheListener();
}-*/;
And in my JavaScript
function removeTheListener(){
document.removeEventListener("backbutton", onBackKeyDown, false);
}
Here is my call to hideSettingsWidgets()
public void hideSettingsWidgets(){
for(int i=0;i<settingsScreenWidgets.length;i++){
settingsScreenWidgets[i].setVisible(false);
}
alertString("Working");
removeBackListener();
}
And I am calling the method you gave me inside showSettingsWidgets()
p
rivate void showSettingsWidgets(){
for(int i=0;i<settingsScreenWidgets.length;i++){
settingsScreenWidgets[i].setVisible(true);
}
setCurrentImage();
setOnOffImage();
setupJavaHandler();
}
It does seem to be adding the EventListener that is inside your
public native void setupJavaHandler() /*-{
var app = this;
var onBackKeyDown = $entry(function() {
app.#com.mycompany.myapp.client.MyApp::hideSettingsWidgets();
});
$doc.addEventListener("backbutton", onBackKeyDown, false);
}-*/;
So I am not sure where I am going wrong. I did not add the ArrayList<> you mentioned because was not sure to and the Event Listener was not running when page was Loaded.
Seems like showSettingsWidgets() never gets run
The addEventListener code is probably running when the page loads, right? This will map your empty function onBackKeyDown to the backbutton event. Then, when your module loads, you attempt to redefine the onBackKeyDown function to be a new one - but the old one was already attached to the event you are trying to listen to.
This is roughly the equivalent of this (with strings instead of listener functions):
// first, make the thing to hold the 'listener', and define the first one
List<String> strings = new ArrayList<String>();
String onBackKeyDown = "abcd";
strings.add(onBackKeyDown);
// then, redefine the string, but don't change the list!
onBackKeyDown = "zyxw";
assert strings.contains(onBackKeyDown) : "Whoops, reassigned, but not added!";
To fix this, you need a cross between what you are doing in your other question, Adding Eventlisteners to document with GWT JSNI, and what you are doing here. Wrapping the Java function in an $entry call, and passing that to $doc.addEventListener makes the most logical sense (though I don't know a lot about WP7).
public static native void setupJavaHandler() /*-{
var onBackKeyDown = $entry(this.#com.mycompany.myapp.client.MyApp::hideSettingsWidgets());
$doc.addEventListener("backbutton", onBackKeyDown, false);
}-*/;
One more thing - remembering that we are writing JavaScript in that native code, what is going to be this when that hideSettingsWidgets() method is called? JavaScript doesn't know that all Java instance methods need a this to run on (and JavaScript has no problem running methods for object A on B - A.method.call(B) is totally legal, and often helpful). We need to be sure that this means what we think it does:
public static native void setupJavaHandler() /*-{
var app = this;
var onBackKeyDown = $entry(function() {
app.#com.mycompany.myapp.client.MyApp::hideSettingsWidgets();
});
$doc.addEventListener("backbutton", onBackKeyDown, false);
}-*/;
Edit: Oops, turns out your method was static anyway, so this doesn't actually mean anything! Either change exportStaticMethod/setupJavaHandler to be non static and call it directly (probably in your onModuleLoad as you have it now), or pass in an instance to call hideSettingsWidgets() on, like we are doing with app in the previous sample.
public native void setupJavaHandler() /*-{
var app = this;
var onBackKeyDown = $entry(function() {
app.#com.mycompany.myapp.client.MyApp::hideSettingsWidgets();
});
$doc.addEventListener("backbutton", onBackKeyDown, false);
}-*/;
// in onModuleLoad:
setupJavaHandler();
or
public static native void setupJavaHandler(MpApp app) /*-{
//var app = this;
var onBackKeyDown = $entry(function() {
app.#com.mycompany.myapp.client.MyApp::hideSettingsWidgets();
});
$doc.addEventListener("backbutton", onBackKeyDown, false);
}-*/;
// in onModuleLoad:
MyApp.setupJavaHandler(this);
I am trying to invoke a Java Method from my Javascript code. This is for a Windows Phone 7 app using Phonegap.
I have the following in my javascript code.
document.addEventListener("backbutton", onBackKeyDown, false);
function onBackKeyDown(){
}
And in my Java code I have the following.
public static native void exportStaticMethod() /*-{
$wnd.onBackKeyDown =
$entry(this.#com.mycompany.myapp.client.MyApp::hideSettingsWidgets());
}-*/;
Then in the on onModuleLoad() I am calling it like so:
MyApp.exportStaticMethod();
It does not work I have an alert in the hideSettingsWidgets() but it never gets shown.
*EDIT*
Here is some more code. The EventListener is not added in the Javascript. It is specifically added withing the java code. I could not get the listeners to register originally so here is what I added.
public static native void removeBackListener() /*-{
$wnd.removeTheListener();
}-*/;
And in my JavaScript
function removeTheListener(){
document.removeEventListener("backbutton", onBackKeyDown, false);
}
Here is my call to hideSettingsWidgets()
public void hideSettingsWidgets(){
for(int i=0;i<settingsScreenWidgets.length;i++){
settingsScreenWidgets[i].setVisible(false);
}
alertString("Working");
removeBackListener();
}
And I am calling the method you gave me inside showSettingsWidgets()
p
rivate void showSettingsWidgets(){
for(int i=0;i<settingsScreenWidgets.length;i++){
settingsScreenWidgets[i].setVisible(true);
}
setCurrentImage();
setOnOffImage();
setupJavaHandler();
}
It does seem to be adding the EventListener that is inside your
public native void setupJavaHandler() /*-{
var app = this;
var onBackKeyDown = $entry(function() {
app.#com.mycompany.myapp.client.MyApp::hideSettingsWidgets();
});
$doc.addEventListener("backbutton", onBackKeyDown, false);
}-*/;
So I am not sure where I am going wrong. I did not add the ArrayList<> you mentioned because was not sure to and the Event Listener was not running when page was Loaded.
Seems like showSettingsWidgets() never gets run
The addEventListener code is probably running when the page loads, right? This will map your empty function onBackKeyDown to the backbutton event. Then, when your module loads, you attempt to redefine the onBackKeyDown function to be a new one - but the old one was already attached to the event you are trying to listen to.
This is roughly the equivalent of this (with strings instead of listener functions):
// first, make the thing to hold the 'listener', and define the first one
List<String> strings = new ArrayList<String>();
String onBackKeyDown = "abcd";
strings.add(onBackKeyDown);
// then, redefine the string, but don't change the list!
onBackKeyDown = "zyxw";
assert strings.contains(onBackKeyDown) : "Whoops, reassigned, but not added!";
To fix this, you need a cross between what you are doing in your other question, Adding Eventlisteners to document with GWT JSNI, and what you are doing here. Wrapping the Java function in an $entry call, and passing that to $doc.addEventListener makes the most logical sense (though I don't know a lot about WP7).
public static native void setupJavaHandler() /*-{
var onBackKeyDown = $entry(this.#com.mycompany.myapp.client.MyApp::hideSettingsWidgets());
$doc.addEventListener("backbutton", onBackKeyDown, false);
}-*/;
One more thing - remembering that we are writing JavaScript in that native code, what is going to be this when that hideSettingsWidgets() method is called? JavaScript doesn't know that all Java instance methods need a this to run on (and JavaScript has no problem running methods for object A on B - A.method.call(B) is totally legal, and often helpful). We need to be sure that this means what we think it does:
public static native void setupJavaHandler() /*-{
var app = this;
var onBackKeyDown = $entry(function() {
app.#com.mycompany.myapp.client.MyApp::hideSettingsWidgets();
});
$doc.addEventListener("backbutton", onBackKeyDown, false);
}-*/;
Edit: Oops, turns out your method was static anyway, so this doesn't actually mean anything! Either change exportStaticMethod/setupJavaHandler to be non static and call it directly (probably in your onModuleLoad as you have it now), or pass in an instance to call hideSettingsWidgets() on, like we are doing with app in the previous sample.
public native void setupJavaHandler() /*-{
var app = this;
var onBackKeyDown = $entry(function() {
app.#com.mycompany.myapp.client.MyApp::hideSettingsWidgets();
});
$doc.addEventListener("backbutton", onBackKeyDown, false);
}-*/;
// in onModuleLoad:
setupJavaHandler();
or
public static native void setupJavaHandler(MpApp app) /*-{
//var app = this;
var onBackKeyDown = $entry(function() {
app.#com.mycompany.myapp.client.MyApp::hideSettingsWidgets();
});
$doc.addEventListener("backbutton", onBackKeyDown, false);
}-*/;
// in onModuleLoad:
MyApp.setupJavaHandler(this);
I am wanting to use the phonegap audio api in GWT using JSNI.I cannot figure out how to code the methods in JSNI.
Wondering if anyone know of any tutorials.They javascript methods are really pretty simple.
http://docs.phonegap.com/phonegap_media_media.md.html
Basically it sounds like it would be something like this:
public final class Media extends JavaScriptObject {
protected Media() {}
public static native final Media newInstance(String src, Command command) /*-{
var callback = function() { command.execute(); };
return new Media(src, callback);
}-*/;
public native final void getCurrentPosition(AsyncCallback<String> command) /*-{
var callback = function(position) { command.onSuccess('' + position); };
this.getCurrentPosition(callback);
}-*/;
public native final void play() /*-{
this.play();
}-*/;
//... more methods here
}
Usage:
Media m = Media.newInstance("http://www.example.com/src.mp3", new Command() {
#Override
public void execute() {
// Code executed after Media is created.
}
});
m.getCurrentPosition(new AsyncCallback<String>() {
#Override
public void onSuccess(String position) {
Window.alert(position);
}
});
m.play();
That's a rough sketch, if you know more about what the type being passed to the callback is you can do nicer things like have it be an int or another JS Overlay Type.
The API is kind of weird because everything is apparently asynchronous, but that's life.
Once you've gotten the hang of writing GWT JSNI bindings it's pretty straightforward.
If you end up getting further down this road, it would be awesome if you open-sourced your GWT wrapper library so other GWT developers could write some iPhone/Android apps.
I just need the play method really.I am not quite as knowledgeable to do this correctly I guess.That code looks really foreign to me :-)
Still cannot accept your answer.The site does not recognize me it is strange.
I get the following error when trying to use the media in my onModuleLoad
The constructor TESTPHONEGAP.Media(String, new Command(){}) is undefined
Media m = new Media("test.mp3", new Command() {
#Override
public void execute() {
}
});
m.play()
Using your class as an "inner class" in same file as my main onModuleLoad