Here is my code
public class MainActivity extends Activity implements GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener {
private GoogleApiClient mGoogleApiClient;
private String TAG = "app comm";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int code = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
if (code == ConnectionResult.SUCCESS) {
Log.d(TAG, "success ");
buildGoogleApiClient();
} else {
Log.d(TAG, "fail ");
}
}
private void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Nearby.CONNECTIONS_API).addConnectionCallbacks(this).addOnConnectionFailedListener(this).build();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Log.d(TAG,"connected");
}
#Override
public void onConnectionSuspended(int i) {
Log.d(TAG,"suspended");
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Log.d(TAG,"failed");
}
}
I am new to this
I run this program in raspberry pi 3
I have checked and internet is working.
isGoogleServicesAvailable is returning true.
but none of the override methods called. I don't know what I am missing.
Here is my log
Connected to process 8191 on device google-iot_rpi3-192.168.1.2:5555
Capturing and displaying logcat messages from application. This behavior can be disabled in the "Logcat output" section of the "Debugger" settings page.
I/zygote: Late-enabling -Xcheck:jni
W/zygote: Using default instruction set features for ARM CPU variant (generic) using conservative defaults
I/InstantRun: starting instant run server: is main process
V/first log: first raspberry log message
D/app comm: success
D/vndksupport: Loading /vendor/lib/hw/android.hardware.graphics.mapper#2.0-impl.so from current namespace instead of sphal namespace.
Looking at your code snippet, you are not calling the connect method after building it, which is what actually starts the connection and gives a callback.
Related
When opening a new dialog, while its loading, you click couple of times on parent shell, apparently the new dialog does not display correctly.
Please see the example below:
Examples
https://i.stack.imgur.com/ZovxE.png (eclipse IDE example)
https://i.stack.imgur.com/5zVar.png
https://i.stack.imgur.com/u86b9.png
https://i.stack.imgur.com/FGaAr.png
Initially I encountered the problem in december 2014, and back then also reported by vaious in house devlopers which were using different development systems and then same problem has been reported by our several customers.
This behavior can be reproduced using following environment:
Windows Version: 7 Pro 64 Bit - 6.1.7601
Java Version: RE 1.8.0_121_b13
SWT Versions
3.8.2
4.6.2
4.7M6
I20170319-2000
I could only reproduce the problem on Windows 7 with the windows basic theme/design/style (not with classic or aero).
On windows 10 its not reproducible.
reproduce
code to reproduce
package test;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class Main {
public static void main(String[] args) {
Display display = new Display();
final Shell shell = createShell(display);
createButton(shell);
shell.open();
eventLoop(display, shell);
display.dispose();
}
private static Shell createShell(Display display) {
final Shell shell = new Shell(display);
shell.setLayout(new RowLayout());
shell.setSize(500, 200);
return shell;
}
private static void createButton(final Shell shell) {
final Button openDialog = new Button(shell, SWT.PUSH);
openDialog.setText("Click here to open Dialog ...");
openDialog.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
TestDialog inputDialog = new TestDialog(shell);
inputDialog.open();
}
});
}
private static void eventLoop(Display display, final Shell shell) {
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
class TestDialog extends Dialog {
public TestDialog(Shell parent) {
super(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.MIN | SWT.MAX | SWT.RESIZE);
setText("Dialog");
}
public void open() {
Shell shell = new Shell(getParent(), getStyle());
shell.setText(getText());
createContents(shell);
shell.pack();
initializeBounds(shell);
shell.open();
eventLoop(shell);
}
private void createContents(final Shell shell) {
shell.setLayout(new GridLayout(2, true));
Label label = new Label(shell, SWT.NONE);
label.setText("Some Label text ...");
final Text text = new Text(shell, SWT.BORDER);
GridData data = new GridData(GridData.FILL_HORIZONTAL);
text.setLayoutData(data);
createCloseButton(shell);
/* time for the user to create the misbehavior */
try {
Thread.sleep(15000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void createCloseButton(final Shell shell) {
Button closeButton = new Button(shell, SWT.PUSH);
closeButton.setText("Close");
GridData data = new GridData(GridData.FILL_HORIZONTAL);
closeButton.setLayoutData(data);
closeButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
shell.close();
}
});
shell.setDefaultButton(closeButton);
}
private void initializeBounds(Shell shell) {
Rectangle bounds = shell.getBounds();
Rectangle parentBounds = getParent().getBounds();
bounds.x = parentBounds.x;
bounds.y = parentBounds.y;
shell.setBounds(bounds);
}
private void eventLoop(Shell shell) {
Display display = getParent().getDisplay();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
steps to reproduce
Start the application
it should look like: https://i.stack.imgur.com/dMJ9e.png
Click on the button.
Keep continuously clicking on right bottom corner of the parent shell (avoid hitting the new opening dialog), till mouse cursor changes to wait icon and parent shell changes its color.
it should look as following: https://i.stack.imgur.com/c1Ikp.png
Wait until the new dialog appears.
it looks likes as following: https://i.stack.imgur.com/kTDgQ.png (incorrectly displayed)
instead: https://i.stack.imgur.com/cHVjn.png (correctly displayed)
steps to reproduce done in video
https://youtu.be/7ukhloCPf0k
When you mouse hover some of the UI elements (the originally not correctly drawn), you can notice some of them to be get painted (e.g. table rows).
https://i.stack.imgur.com/kkMKn.png (before opening the dialog)
https://i.stack.imgur.com/ZXIKc.png (after opening the dialog)
https://i.stack.imgur.com/25M7S.jpg (after mouse over)
Even calling Shell.update() or Shell.redraw() after the Dialog opened does not fix it.
In Windows Performance Options -> Visual Effects -> disable "Use visual styles on windows and buttons" is the only option I found which provides a workaround,
which seems to be the same as changing the design/theme/style to classic.
https://www.sevenforums.com/tutorials/1908-visual-effects-settings-change.html (How to Change Windows Visual Effects)
In the end, I have following questions:
Is it a SWT or Windows problem?
Is there any related topic in bug entries for Windows or in Eclipse Bugzilla?
Is there someone else who experienced the same problem? please share the experience.
Is there any settings in SWT or Windows which could affect its look n feel and fix the problem?
In the end, I have following questions: Is it a SWT or Windows problem?
Neither. As others have mentioned, you certainly should not tie up the UI thread with any long-running task. That work belongs in a background thread.
In regards to using a background thread, there are several ways you could go about this depending on how you want your Dialog to behave.
One option would be to kick off the background thread and then open the dialog when the task is done. I personally don't care for this because while the task is running, a user may think that nothing is happening.
Another option would be to open the dialog but display a "Loading" message, or something to that effect to give meaningful feedback and let a user know that the application isn't frozen (like how it looks/responds in your example).
The strategy would be to:
Create the dialog
Start the long task on a background thread and register a callback
Open the dialog with a "Loading" message
When the task is complete, the dialog will be updated from the callback
If you search around a bit on using Executors, you should find some far better examples and detail on how to use them.
Here's a brief example to illustrate what that might look like:
(Note: There are definitely a few issues with this code, but for the sake of brevity and illustrating the point I opted for a slightly naive solution. Also there are Java 8-esque ways that would be a bit shorter, but again, this illustrates the idea behind using a background thread; the same concepts apply)
Given a Callable (or Runnable if you don't need a return value),
public class LongTask implements Callable<String> {
#Override
public String call() throws Exception {
Thread.sleep(15000);
return "Hello, World!";
}
}
You can use the Executors class to create a thread pool, and then an ExecutorService to submit the Callable for execution. Then, using Futures.addCallback(), you can register a callback which will execute one of two methods depending on whether the task was successful or failed.
final ExecutorService threadPool = Executors.newFixedThreadPool(1);
final ListeningExecutorService executorService = MoreExecutors.listeningDecorator(threadPool);
final ListenableFuture<String> future = executorService.submit(new LongTask());
Futures.addCallback(future, new FutureCallback(){...});
In this case I used the Google Guava implementation ListeningExecutorService which makes things a bit cleaner and simpler, in my opinion. But again, you may not even need this if you opt for a more "Java 8" approach.
As for the callback, when the task is successful, we update the Dialog with the results. If it fails, we can update it with something to indicate failure:
public static class DialogCallback implements FutureCallback<String> {
private final MyDialog dialog;
public DialogCallback(final MyDialog dialog) {
this.dialog = dialog;
}
#Override
public void onSuccess(final String result) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus(result);
}
});
}
#Override
public void onFailure(final Throwable t) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus("Failure");
}
});
}
}
In this case I opted for the Callable to return a String, thus the FutureCallback should be parameterized with String. You may want to use some other class that you created, which will work just as well.
Notice that we use the Display.asyncExec() method to ensure that the code which updates the UI runs on the UI thread, because the callback may execute on the background thread.
Like I said, there are still a few issues here, including what happens when you click the cancel button before the task completes, etc. But hopefully this helps illustrate an approach for handling long-running background tasks without blocking the UI thread.
Full example code:
public class DialogTaskExample {
private final Display display;
private final Shell shell;
private final ListeningExecutorService executorService;
public DialogTaskExample() {
display = new Display();
shell = new Shell(display);
shell.setLayout(new GridLayout());
executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
final Button button = new Button(shell, SWT.PUSH);
button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
button.setText("Start");
button.addSelectionListener(new SelectionAdapter() {
#SuppressWarnings("synthetic-access")
#Override
public void widgetSelected(final SelectionEvent e) {
final MyDialog dialog = new MyDialog(shell);
dialog.setBlockOnOpen(false);
dialog.open();
dialog.setStatus("Doing stuff...");
final ListenableFuture<String> future = executorService.submit(new LongTask());
Futures.addCallback(future, new DialogCallback(dialog));
}
});
}
public void run() {
shell.setSize(200, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
executorService.shutdown();
display.dispose();
}
public static void main(final String... args) {
new DialogTaskExample().run();
}
public static class DialogCallback implements FutureCallback<String> {
private final MyDialog dialog;
public DialogCallback(final MyDialog dialog) {
this.dialog = dialog;
}
#Override
public void onSuccess(final String result) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus(result);
}
});
}
#Override
public void onFailure(final Throwable t) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus("Failure");
}
});
}
}
public static class LongTask implements Callable<String> {
/**
* {#inheritDoc}
*/
#Override
public String call() throws Exception {
Thread.sleep(15000);
return "Hello, World!";
}
}
public static class MyDialog extends Dialog {
private Composite baseComposite;
private Label label;
/**
* #param parentShell
*/
protected MyDialog(final Shell parentShell) {
super(parentShell);
}
/**
* {#inheritDoc}
*/
#Override
protected Control createDialogArea(final Composite parent) {
baseComposite = (Composite) super.createDialogArea(parent);
label = new Label(baseComposite, SWT.NONE);
return baseComposite;
}
public void setStatus(final String text) {
label.setText(text);
baseComposite.layout();
}
}
}
The code seems to be straight forward, only that you are making the main Thread sleep for 15secs hence the delay. If not required remove the sleep or reduce the time for sleep to 5secs or so.
Need to check the bluetooth connection to a remote device exists or got disconnected. Its basically a Forms which mainly targets Android and UWP.
I tried with the Dependency services and made the implementation in Android as below,
_[assembly: Xamarin.Forms.Dependency(typeof(BluetoothListenerActivity))]
namespace demotool.Droid
{
public class BluetoothListenerActivity : Activity,IBluetoothListener
{
public event EventHandler OnDeviceDisconnected;
public static BluetoothListenerActivity mySelf;
//string device;
public void start()
{
mySelf = this;
BluetoothStatusBroadCast mreceiver = new BluetoothStatusBroadCast();
IntentFilter mfilter = new IntentFilter(BluetoothDevice.ActionAclDisconnected);
Forms.Context.RegisterReceiver(mreceiver,mfilter);
}
public void receivedstatuschangd(string devicename,string state)
{
OnDeviceDisconnected(this, new DeviceDisconnectedEventArgs(name: devicename,status: state));
}
}
}_
BroadcastReceiver:
namespace Demo.Droid
{
[BroadcastReceiver]
class BluetoothStatusBroadCast : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
BluetoothDevice device =(BluetoothDevice)intent.GetParcelableExtra(BluetoothDevice.ExtraDevice);
BluetoothListenerActivity.mySelf.receivedstatuschangd(device.Name, intent.Action);
}
}
}
Xamarin Forms Part:
_ protected override void OnStart()
{
IBluetoothListener bluetoothlistener = DependencyService.Get();
bluetoothlistener.start();
bluetoothlistener.OnDeviceDisconnected += Bluetoothlistener_OnDeviceDisconnected;
}
private void Bluetoothlistener_OnDeviceDisconnected(object sender, DeviceDisconnectedEventArgs e)
{
Page page1 = new Page();
page1.DisplayAlert(e.Name+ " " +e.Status, "Alert", "OK");
}_
The Intent Action that I have registered- BluetoothDevice.ActionAclDisconnected, is getting triggered once the Pairing is completed or a connection request is made, which I assume is not the actual Disconnection of the devices
Is there any common plugin which monitors the Bluetooth Connectivity Changes to a remote device. Or could you please tell me the actual Intent Action that I should listen for.
Thanks in Advance !
-------EDIT 2--------
Still using the post of Davidgyoung and these comments, now I have a FatalException :
E/AndroidRuntime﹕ FATAL EXCEPTION:
IntentService[BeaconIntentProcessor]
Process: databerries.beaconapp, PID: 19180
java.lang.NullPointerException
at databerries.beaconapp.MyApplicationName.didEnterRegion(MyApplicationName.java:76)
at org.altbeacon.beacon.BeaconIntentProcessor.onHandleIntent(BeaconIntentProcessor.java:83)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.os.HandlerThread.run(HandlerThread.java:61)
This error is due to the calling of setRangeNotifier()?
-------EDIT--------
After the post of Davidgyoung and these comments, I tried this method, but still not working :
public class MyApplicationName extends Application implements BootstrapNotifier {
private static final String TAG = ".MyApplicationName";
private RegionBootstrap regionBootstrap;
private BeaconManager beaconManager;
List region_list = new ArrayList();
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "App started up");
// wake up the app when any beacon is seen (you can specify specific id filers in the parameters below)
List region_list = myRegionList();
regionBootstrap = new RegionBootstrap(this, region_list);
BeaconManager beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
beaconManager.setBackgroundScanPeriod(3000l);
beaconManager.setBackgroundBetweenScanPeriod(5000l);
}
#Override
public void didDetermineStateForRegion(int arg0, Region arg1) {
// Don't care
}
#Override
public void didEnterRegion(Region region) {
Log.d(TAG, "Got a didEnterRegion call");
// This call to disable will make it so the activity below only gets launched the first time a beacon is seen (until the next time the app is launched)
// if you want the Activity to launch every single time beacons come into view, remove this call.
regionBootstrap.disable();
Intent intent = new Intent(this, MyActivity.class);
// IMPORTANT: in the AndroidManifest.xml definition of this activity, you must set android:launchMode="singleInstance" or you will get two instances
// created when a user launches the activity manually and it gets launched from here.
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(intent);
String zone = region.toString();
Log.d(TAG, "Enter in region");
String text = "Enter in " + zone;
Log.d(TAG, text);
String uuid = "UUID : " + region.getId1();
Log.d(TAG, uuid);
//This part is not working
beaconManager.setRangeNotifier(this);
beaconManager.startRangingBeaconsInRegion(region);
}
#Override
public void didExitRegion(Region arg0) {
// Don't care
}
The errors are about the input in setRangeNotifier and an exception for startRangingBeaconsInRegion
This isn't my main class, my main class :
public class MyActivity extends Activity{
public final static String EXTRA_MESSAGE = "com.example.myapp.MESSAGE";
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d("myActivity","onCreate");
}
}
I want all the IDs of the beacons in the region. With this method if I understand, the app is wake-up in the background when she detected a region and normally the "startRangingBeaconsInRegion" can give me a list of beacons with this one I can take the Ids.
-------Original--------
I would like to know all the beacon around me. I know the UUID of this beacons and I can get it with 'region.toString();'. But, I need the others id of the beacons. And, I don't have "Beacon" on didRangeBeaconsInRegion.
How to know the beacons in the region?
And last question, it's possible to make that in the background?
Thanks
You can see an example of ranging for beacons in the "Ranging Sample Code" section here: http://altbeacon.github.io/android-beacon-library/samples.html
This will allow you to read all the identifiers by looking at each Beacon object returned in the Collection<Beacon> beacons in the callback. Like this:
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
for (Beacon beacon: beacons) {
Log.i(TAG, "This beacon has identifiers:"+beacon.getId1()+", "+beacon.getId2()+", "+beacon.getId3());
}
}
Once you start ranging, it will continue to do so in the background, provided you don't exit the activity that starts the ranging. Under some uses of the library, ranging slows down in the background, but this only happens if using the BackgroundPowerSaver class. If you don't want ranging to slow down in the background, simply don't enable background power saving with the library.
I am making a wear app which fetches data from database(which is on handheld) on launch of app home screen.
So when the homepage activity launches, It sends a message using Wearable.MessageApi.sendMessage function from the android wear to handheld. On the handheld I have the WearableListenerService which receives this message in onMessageReceived function and reads database. After reading database it sends putDatamapRequest to the wear.
Now on the wear side, I have another WearableListenerService. In this service, onDataChanged() function is never invoked. It runs at times, so far it ran for 2-3 times but otherwise it doesn't run. It's very random. Also once the data is received in Wear side, I set a static Arraylist, which I use to display data in Activity. But since the onDataChanged function is not always called, it gives empty array list.
Here is my AndroidManifest file of wear app where I declared the service:
<service
android:name="com.example.deals.DataListenerService"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
</intent-filter>
</service>
Here is my code to send message from wear to handheld:
mGoogleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
#Override
public void onConnected(Bundle bundle) {
Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).setResultCallback(new ResultCallback<NodeApi.GetConnectedNodesResult>() {
#Override
public void onResult(NodeApi.GetConnectedNodesResult getConnectedNodesResult) {
if(!getConnectedNodesResult.getNodes().isEmpty())
{
node = getConnectedNodesResult.getNodes().get(0);
System.out.println("Connected: "+ node.getId());
Wearable.MessageApi.sendMessage(mGoogleApiClient, node.getId(), FETCH_ALL_DEALS, null).setResultCallback(new ResultCallback<MessageApi.SendMessageResult>() {
#Override
public void onResult(MessageApi.SendMessageResult sendMessageResult) {
if (!sendMessageResult.getStatus().isSuccess()) {
Log.e("Wear:", "ERROR: failed to send Message: " + sendMessageResult.getStatus());
}
else
System.out.println("success");
}
});
}
else
System.out.println("Wear not connected to Phone");
}
});
}
#Override
public void onConnectionSuspended(int i) {
}
})
.addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
#Override
public void onConnectionFailed(ConnectionResult result) {
Log.v("Phone to wear connection failed", "onConnectionFailed: " + result);
}
})
.addApi(Wearable.API)
.build();
mGoogleApiClient.connect();
Here is my code for onMessageReceive on Handheld:
public void onMessageReceived(MessageEvent messageEvent) {
System.out.println("Message Received on Phone on launch of wear homepage");
if(messageEvent.getPath().equals(FETCH_ALL_DEALS)) {
sendSavedDeals(); //fetch from db and make a datamap object using PutDataRequest
System.out.println("Message Received on Phone on launch of wear homepage");
}
else {
System.out.println("Unable to recognise action for "+messageEvent.getPath());
}
}
Now on my wear side I have a WearableListenerService but it's onDataChanged method never gets called. Could you please help me with that.
onDataChanged() is only called when the data really did change. If you put the same data into the DataApi multiple times, the method is only called once until you write different data.
To trigger an action on the wear side, even when the data didn't change, send a message after putting data into the DataApi.
Data should be changed or deleted to get call-back to onDataChanged in WearabaleListenerService in your wear.
if you want make changes open APP-info from settings and clear-data then after force stop .
Finally launch your app in phone..but ensure that wearable listener service should be already started in your wear..
When onDataChanged() is not being called :
Firstly, ensure that the handheld activity is connecting to the API at the start :
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
}
otherwise, it fails silently.
If it still doesn't work, to facilitate the debug, add this override method and this class in the handheld activity to generate data every 5 seconds :
#Override
public void onResume() {
super.onResume();
mDataItemGeneratorFuture = mGeneratorExecutor.scheduleWithFixedDelay(
new DataItemGenerator(), 1, 5, TimeUnit.SECONDS
);
}
/** Generates a DataItem based on an incrementing count. */
private class DataItemGenerator implements Runnable {
private int count = 0;
#Override
public void run() {
PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(COUNT_PATH);
putDataMapRequest.getDataMap().putInt(COUNT_KEY, count++);
PutDataRequest request = putDataMapRequest.asPutDataRequest();
Log.d("yourApp", "Generating DataItem: " + request);
if (!mGoogleApiClient.isConnected()) {
return;
}
Wearable.DataApi.putDataItem(mGoogleApiClient, request)
.setResultCallback(new ResultCallback() {
#Override
public void onResult(DataItemResult dataItemResult) {
if (!dataItemResult.getStatus().isSuccess()) {
Log.e("YourApp", "ERROR: failed to putDataItem, status code: "
+ dataItemResult.getStatus().getStatusCode());
}
}
});
}
}
My Android app need the user to create an account to be able to use the app. The account info is stored in SQLite database. When the application starts I check if the user has an account, if not I show a sign up activity for the user.
Now I get reports from users that they sometimes comes to the sign up activity even if they've already created an account. This happens when they've closed the application and reopen it again.
This is the code I'm using and I need to figure out what the problem might be:
//MyApplication.java
public class MyApplication extends Application {
private DataBaseUtility dbu;
public boolean hasAccount;
#Override
public void onCreate() {
super.onCreate();
//Init sqlite database
this.dbu = new DataBaseUtility(this);
//This loads the account data from the database and returns true if the user has already created an account
this.hasAccount = loadAccount();
}
public boolean loadAccount() {
boolean loadedData = false;
String query = "SELECT data FROM tblaccount WHERE tblaccount.deleted=0";
Cursor cursor = this.dbu.getCursor(query);
if (cursor != null) {
while (cursor.moveToNext()) {
loadedData = true;
}
cursor.close();
}
return loadedData;
}
}
//MainActivity.java
public class MainActivity extends TabActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MyApplication application = (MyApplication)getApplication();
if (!application.hasAccount) {
//Take the user to the sign up activity
}
}
My idea is that maybe sometimes MainActivity.onCreate() runs before MyApplication.onCreate(). Can that be the case?
In application's onCreate, you are checking if the user has an account and setting a boolean.
You are checking in the MainActivity's onCreate if the user has an account through the application's boolean.
application's onCreate() executing before MainActivity's onCreate() is always the case! It is impossible for a different execution path to occur and since application's onCreate() does not have a Runnable it is a 100% garantuee.
Please make sure you're DataBaseUtility does not have any Runnables.
Anyway STILL there are several ways to reproduce the error! I will not state these now but you can know them when you see:
SOLUTION
MainActivity You have forgotten to update application.hasAccount upon successfull sign up~
public class MainActivity extends TabActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MyApplication application = (MyApplication)getApplication();
if (!application.hasAccount) {
//Take the user to the sign up activity
//if(successful) application.hasAccount = true
}
}
To avoid database exceptions
I use this:
REMARK It would be much better to use more strong persistent status saving for the database -i.e. SharedPreferences
boolean isOpened = false;
//When I need to open
if(!isOpened){
//open
isOpened = true;
}
//When I need to close
if(isOpened){
//close
isOpened = false;
}
onDestroy() { //every onDestroy
if(isOpened){
//close
}
}