I am trying to perform an asynchronous GET-request on my openHAB-project. I have done it before and reused parts of my code to create a new Android app, but it is not working.
In theory I want the state of the "GastSwitch"-item to be written into a String (gastSwitchState) to then be used as a trigger for opening a different activity. If the result of the request is "OFF" the app is supposed to keep running, but stay in the MainActivity.
When debugging it seems like the getGastSwitchState-method is jumped entirely after the enqeue-Method is called. Can someone explain to me, why my code seems to leave out half of the method?
I know that this way of doing it should work, but I can't find where I went wrong.
//connect with REST-API in openHAB :
// GET Status GastSwitch: if Switch = "ON" go to MeetingActivity
//Timer to GET the GastSwitch-status every 30 seconds:
TimerTask gastSwitchTimerTask = new TimerTask() {
public void run() {
try {
getGastSwitchState("myURLforOpenHABGastSwitchState", new Callback() {
#Override
public void getParameter(String string) {
if (gastSwitch.equals("ON")) {
Intent activityIntent = new Intent(getApplicationContext(), MeetingActivity.class);
startActivity(activityIntent);
}
}
});
} catch (IOException e) {
e.printStackTrace();
tvLog.setText(e.toString());
}
}
};
// Timer for GETting the GastSwitch-state every 30 seconds
long emergencyDelay = 1000 * 30 * 1;
Timer gastSwitchTimer = new Timer();
gastSwitchTimer.schedule(gastSwitchTimerTask, 0, emergencyDelay);
}
//Method for GETting the GastSwitch-state from REST-API:
void getGastSwitchState(String url, final Callback callback) throws IOException {
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
okhttp3.Request request = new okhttp3.Request.Builder()
.url(url)
.method("GET", null)
.addHeader("AuthToken", "")
.build();
client.newCall(request)
.enqueue(new okhttp3.Callback() {
#Override
public void onResponse(#NotNull okhttp3.Call call, #NotNull Response response) throws IOException {
if (response.isSuccessful()) {
final String res = response.body().string();
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
gastSwitch = res;
tvLog.setText(gastSwitch);
callback.getParameter(gastSwitch);
}
});
}
}
#Override
public void onFailure(#NotNull okhttp3.Call call, #NotNull IOException e) {
runOnUiThread(new Runnable() {
#Override
public void run() {
}
});
}
});
Related
I'm implementing in a LauncherActivity (with just a loading indicator) an Observable (Single) from RxJava library to login with the previously recorded users credentials.
The activity is very very simple, and yet I get a skipped frames warning (40ish), both on my phone and on emulator, and I can't figure out why (though sometimes it doesn't show up).
Here is the code :
public class LauncherActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launcher);
mProgressBar = findViewById(R.id.progress_bar);
mProgressBar.setVisibility(View.VISIBLE);
if (UsersUtils.hasCredentialsRecorded(this)) {
getAccessToken();
} else {
login();
}
}
public void getAccessToken() {
Callable<Token> callable = new Callable<Token>() {
#Override
public Token call() throws Exception {
final Map<String, byte[]> credentials = UsersUtils.getCredentials(getApplicationContext());
Token token = OauthCalls.getToken(new String(credentials.get(UsersUtils.PREFERENCES_USER_KEY)),
new String(credentials.get(UsersUtils.PREFERENCES_PASS_KEY)));
return token;
}
};
Single.fromCallable(callable)
.subscribeOn(Schedulers.io())
.subscribe(new DisposableSingleObserver<Token>() {
#Override
public void onSuccess(Token token) {
if (token == null) {
login();
} else {
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
}
}
#Override
public void onError(Throwable e) {
login();
}
});
}
public void login() {
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
}
}
Thanks a lot for your help !
I am trying to create textview in android which display the remaining time(seconds).
Have used runOnUiThread and Hadnler for this and everything seems working fine(sysout and debug shows that both threads are executed and value is updated properly).
However, on UI the textview value is not updated properly. It gets updated with last value when the thread completes.
I am writing the below code inside private method of the fragment.
final TextView timerText = (TextView) mainView.findViewById(R.id.timerText);
timerText.setText(R.string.maxAllowedSeconds);
handler.post(new Runnable() {
#Override
public void run() {
while(true)
{
System.out.println("Text:"+ ""+maxAllowedSeconds);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
maxAllowedSeconds--;
if(maxAllowedSeconds <= 0)
break;
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
System.out.println("Running on UI Thread : " + maxAllowedSeconds);
timerText.setText("" + maxAllowedSeconds);
}
});
}
}
});
Gone through many of the previous questions in this area but none seems to have concrete solutions for this problem.
Thanks in advance.
SOLUTOIN:
Finally I used AsynchTask which worked perfectly as expected.
private class RapidFireAsyncTimerTask extends AsyncTask<Integer, Integer, Void> {
private Context context;
private View rootView;
public RapidFireAsyncTimerTask(Context ctx, View rootView) {
this.context = ctx;
this.rootView = rootView;
}
#Override
protected Void doInBackground(Integer... params) {
int maxSec= params[0];
while (true) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress(--maxSec);
if (maxSec <= 0)
break;
}
return null;
}
#Override
protected void onProgressUpdate(final Integer... values) {
((TextView) rootView.findViewById(R.id.timerText)).setText("" + values[0]);
}
#Override
protected void onPostExecute(Void aVoid) {
//next task
}
}
Instead of Handler, it worked with AsynchTask(No runOnUiThread needed).
public RapidFireAsyncTimerTask(Context ctx, View rootView) {
this.context = ctx;
this.rootView = rootView;
}
#Override
protected Void doInBackground(Integer... params) {
int maxSec= params[0];
while (true) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
publishProgress(--maxSec);
if (maxSec <= 0)
break;
}
return null;
}
#Override
protected void onProgressUpdate(final Integer... values) {
((TextView) rootView.findViewById(R.id.timerText)).setText("" + values[0]);
}
#Override
protected void onPostExecute(Void aVoid) {
//next task
}
}
It is possible to show progress dialog when loading the .obj model. I tried to call the ProgressDialog in RajawaliVuforiaExampleRenderer.java but it said "Can't create handler inside thread that has not called Looper.prepare()"
I have pasted part of the code here:
protected void initScene() {
mLight = new DirectionalLight(.1f, 0, -1.0f);
mLight.setColor(1.0f, 0, 0);
mLight.setPower(1);
getCurrentScene().addLight(mLight);
LoaderOBJ objParser = new LoaderOBJ(mContext.getResources(),
mTextureManager, R.raw.wall_obj);
try {
// Load model
objParser.parse();
wall = objParser.getParsedObject();
addChild(wall);
} catch (Exception e) {
e.printStackTrace();
}
}
EDITED:
I have read the comment from Abhishek Agarwal and updated the code for Renderer part, now i having problem on calling the ProgressDialog when loading the model, here is my code for the UI thread.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// receive file path
String filePath = this.getIntent().getStringExtra("FullFilePath");
Log.i(filePath, "FullFilePath:" + filePath);
waitDialog = ProgressDialog.show(this, "", "Loading", true);
waitDialog.show();
new ModelLoader().execute();
}
#Override
protected void setupTracker() {
int result = initTracker(TRACKER_TYPE_MARKER);
if (result == 1) {
result = initTracker(TRACKER_TYPE_IMAGE);
if (result == 1) {
super.setupTracker();
} else {RajLog.e("Couldn't initialize image tracker.");
}
} else {
RajLog.e("Couldn't initialize marker tracker.");
}}
protected void initApplicationAR() {
super.initApplicationAR();
createImageMarker("marker.xml");
}
protected void initRajawali() {
super.initRajawali();
mRenderer = new ModelRenderer(this);
mRenderer.setSurfaceView(mSurfaceView);
super.setRenderer(mRenderer);
mUILayout = this;
mUILayout.setContentView(mLayout, new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
private class ModelLoader extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
startVuforia();
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
waitDialog.dismiss();
}
}
Progress Dialog can be shown on the UIThread. So show progress dialog on the main thread not under GLThread
You can use Handler to be on threadUI :
`private Handler mHandler = new Handler();
...
mHandler.post(new Runnable() {
#Override
public void run() {
view_progressBar.setProgress(val);
}
});`
I'm trying to create an application which is able to work even when network is down.
The idea is to store data returned from RequestFactory on the localStorage, and to use localStorage when network isn't available.
My problem - I'm not sure exactly how to differentiate between server errors(5XX, 4XX, ...) and network errors.
(I assume that on both cases my Receiver.onFailure() would be called, but I still don't know how to identify this situation)
Any help would be appreciated,
Thanks,
Gilad.
The response code when there is no internet connection is 0.
With RequestFactory to identify that the request was unsuccessful because of the network the response code has to be accessed. The RequestTransport seems like the best place.
Here is a rough implementation of an OfflineAwareRequestTransport.
public class OfflineAwareRequestTransport extends DefaultRequestTransport {
private final EventBus eventBus;
private boolean online = true;
public OfflineAwareRequestTransport(EventBus eventBus) {
this.eventBus = eventBus;
}
#Override
public void send(final String payload, final TransportReceiver receiver) {
// super.send(payload, proxy);
RequestBuilder builder = createRequestBuilder();
configureRequestBuilder(builder);
builder.setRequestData(payload);
builder.setCallback(createRequestCallback(receiver, payload));
try {
builder.send();
} catch (RequestException e) {
}
}
protected static final int SC_OFFLINE = 0;
protected RequestCallback createRequestCallback(final TransportReceiver receiver,
final String payload) {
return new RequestCallback() {
public void onError(Request request, Throwable exception) {
receiver.onTransportFailure(new ServerFailure(exception.getMessage()));
}
public void onResponseReceived(Request request, Response response) {
if (Response.SC_OK == response.getStatusCode()) {
String text = response.getText();
setOnline(true);
receiver.onTransportSuccess(text);
} else if (response.getStatusCode() == SC_OFFLINE) {
setOnline(false);
boolean processedOk = processPayload(payload);
receiver.onTransportFailure(new ServerFailure("You are offline!", OfflineReceiver.name,
"", !processedOk));
} else {
setOnline(true);
String message = "Server Error " + response.getStatusCode() + " " + response.getText();
receiver.onTransportFailure(new ServerFailure(message));
}
}
};
}
I had an rcp application which runs for only first run, when a user attempts to re-execute the application, second instance behaves as a client which encodes and sends its arguments over the socket to the first instance which acts as a server and then exits silently. The first instance receives and decodes that message, then behaves as if it had been invoked with those arguments.
so far so good i made internal protocol specification for passing arguments between two instances.
I could not bring the first instance(RCP application) to front. It is in minimized state only,
this is in continuation to my previous question
the change i made to previous post is start method of application class
public Object start(IApplicationContext context) throws Exception {
if (!ApplicationInstanceManager.registerInstance()) {
return IApplication.EXIT_OK;
}
ApplicationInstanceManager
.setApplicationInstanceListener(new ApplicationInstanceListener() {
public void newInstanceCreated() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
System.out.println("New instance detected...");
//Display.getCurrent().getActiveShell()
.forceActive();// this gives null
// pointer exception
// hence commented
}
});
}
});
Display display = PlatformUI.createDisplay();
try {
int returnCode = PlatformUI.createAndRunWorkbench(display,
new ApplicationWorkbenchAdvisor());
if (returnCode == PlatformUI.RETURN_RESTART)
return IApplication.EXIT_RESTART;
else
return IApplication.EXIT_OK;
} finally {
display.dispose();
}
}
below line is stopping me to bring Application to front
Display.getCurrent().getActiveShell().forceActive();
generates null pointer exception at getActiveShell()
how can i maximize the previous instance or bring it to front
I wrote an instance manager to restrict my RCP to a single instance.
Here's the code that goes in Application.java, in the start method:
if (!ApplicationInstanceManager.registerInstance()) {
return IApplication.EXIT_OK;
}
ApplicationInstanceManager
.setApplicationInstanceListener(new ApplicationInstanceListener() {
public void newInstanceCreated() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
if (DEBUG)
System.out.println("New instance detected...");
Display.getCurrent().getActiveShell().forceActive();
}
});
}
});
Here's the listener interface:
public interface ApplicationInstanceListener {
public void newInstanceCreated();
}
And here's the Manager class:
public class ApplicationInstanceManager {
private static final boolean DEBUG = true;
private static ApplicationInstanceListener subListener;
/** Randomly chosen, but static, high socket number */
public static final int SINGLE_INSTANCE_NETWORK_SOCKET = 44331;
/** Must end with newline */
public static final String SINGLE_INSTANCE_SHARED_KEY = "$$RabidNewInstance$$\n";
/**
* Registers this instance of the application.
*
* #return true if first instance, false if not.
*/
public static boolean registerInstance() {
// returnValueOnError should be true if lenient (allows app to run on
// network error) or false if strict.
boolean returnValueOnError = true;
// try to open network socket
// if success, listen to socket for new instance message, return true
// if unable to open, connect to existing and send new instance message,
// return false
try {
final ServerSocket socket = new ServerSocket(
SINGLE_INSTANCE_NETWORK_SOCKET, 10, InetAddress
.getLocalHost());
if (DEBUG)
System.out
.println("Listening for application instances on socket "
+ SINGLE_INSTANCE_NETWORK_SOCKET);
Thread instanceListenerThread = new InstanceListenerThread(socket);
instanceListenerThread.start();
// listen
} catch (UnknownHostException e) {
EclipseLogging.logError(RabidPlugin.getDefault(),
RabidPlugin.PLUGIN_ID, e);
return returnValueOnError;
} catch (IOException e) {
return portTaken(returnValueOnError, e);
}
return true;
}
private static boolean portTaken(boolean returnValueOnError, IOException e) {
if (DEBUG)
System.out.println("Port is already taken. "
+ "Notifying first instance.");
try {
Socket clientSocket = new Socket(InetAddress.getLocalHost(),
SINGLE_INSTANCE_NETWORK_SOCKET);
OutputStream out = clientSocket.getOutputStream();
out.write(SINGLE_INSTANCE_SHARED_KEY.getBytes());
out.close();
clientSocket.close();
System.out.println("Successfully notified first instance.");
return false;
} catch (UnknownHostException e1) {
EclipseLogging.logError(RabidPlugin.getDefault(),
RabidPlugin.PLUGIN_ID, e);
return returnValueOnError;
} catch (IOException e1) {
EclipseLogging
.logError(
RabidPlugin.getDefault(),
RabidPlugin.PLUGIN_ID,
"Error connecting to local port for single instance notification",
e);
return returnValueOnError;
}
}
public static void setApplicationInstanceListener(
ApplicationInstanceListener listener) {
subListener = listener;
}
private static void fireNewInstance() {
if (subListener != null) {
subListener.newInstanceCreated();
}
}
public static void main(String[] args) {
if (!ApplicationInstanceManager.registerInstance()) {
// instance already running.
System.out.println("Another instance of this application "
+ "is already running. Exiting.");
System.exit(0);
}
ApplicationInstanceManager
.setApplicationInstanceListener(new ApplicationInstanceListener() {
public void newInstanceCreated() {
System.out.println("New instance detected...");
// this is where your handler code goes...
}
});
}
public static class InstanceListenerThread extends Thread {
private ServerSocket socket;
public InstanceListenerThread(ServerSocket socket) {
this.socket = socket;
}
#Override
public void run() {
boolean socketClosed = false;
while (!socketClosed) {
if (socket.isClosed()) {
socketClosed = true;
} else {
try {
Socket client = socket.accept();
BufferedReader in = new BufferedReader(
new InputStreamReader(client.getInputStream()));
String message = in.readLine();
if (SINGLE_INSTANCE_SHARED_KEY.trim().equals(
message.trim())) {
if (DEBUG)
System.out.println("Shared key matched - "
+ "new application instance found");
fireNewInstance();
}
in.close();
client.close();
} catch (IOException e) {
socketClosed = true;
}
}
}
}
}
}
After your IApplication start up, you can also check and lock the OSGi instance location using org.eclipse.osgi.service.datalocation.Location.isSet() and org.eclipse.osgi.service.datalocation.Location.lock()
The location is usually retrieved from your Activator using code like:
public Location getInstanceLocation() {
if (locationTracker == null) {
Filter filter = null;
try {
filter = context.createFilter(Location.INSTANCE_FILTER);
} catch (InvalidSyntaxException e) {
// ignore this. It should never happen as we have tested the
// above format.
}
locationTracker = new ServiceTracker(context, filter, null);
locationTracker.open();
}
return (Location) locationTracker.getService();
}