I'm creating an app for Android in Java. I can send info to a webservice but when i'm offline i want to store the info and when the phone gets connected to the internet i want to send it to the webservice.
Can anyone help me?
Thanks
Store your data in SQLite data-base. You can read here.
Check in BroadcastReceiver if connectivity changed and update online DB and delete the content from Sqlite DB.
public void onReceive(Context context, Intent intent) {
String s = intent.getAction();
if (s.equals("android.net.conn.CONNECTIVITY_CHANGE")) {
if (IsNetworkAvailable(context)) {
// update your online data-base and delete all rows from SQlite
}
return;
}
}
Method isNetworkAvailable:
public static boolean isNetworkAvailable(Context mContext) {
Context context = mContext.getApplicationContext();
ConnectivityManager connectivity = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity == null) {
return false;
} else {
NetworkInfo[] info = connectivity.getAllNetworkInfo();
if (info != null) {
for (int i = 0; i < info.length; i++) {
if (info[i].getState() == NetworkInfo.State.CONNECTED){
return true;
}
}
}
}
return false;
}
You also need permissions:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Offline storage and sync seem simple at first sight but you need to be careful and consider the following:
First get familiar with the storage options available in the platform and chose the most convenient for your app scenario.
Second, design your sync mechanism in an efficient way so your app won't drain the battery life.
This is a good resource to check the entire structure of an android app that cares about working offline and properly sync with the server as network becomes available.
Save your info to a SQLite database and use a BroadcastReceiver to listen when network connection is available. When connection is available, start a Service that sends the saved data to your webservice.
In the event, where you upload your data, check if Internet connection is available or not, if not, store the data as textfile or object and name it like needToUpload1, 2, 3.
Then, whenever the device is online, check if the there is any file named like that. If so, upload it via service and delete the file.
That's just my opinion how i'll do it but really depends on data.
You can find how to do every step on this site so i hope it will help.
Related
I know there are a few questions similar to this,
ConnectionManager.getRestrictBackgroundStatus() will give me whether background data is disabled for my app.
For my use case I want to know specifically if the Data Saver is enabled for all apps
settings->dataSaver->restrictBackgroundData
or specific app background data is disabled
app_Name->Info->Network->disable_backgroundData
ConnectionManager.getRestrictBackgroundStatus() will give me the same answer in both the cases, how can I know which particular setting is enabled?
Checking if Data Saver is enabled and if your app is whitelisted is possible via ConnectivityManager.getRestrictBackgroundStatus()
public boolean checkBackgroundDataRestricted() {
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
switch (connMgr.getRestrictBackgroundStatus()) {
case RESTRICT_BACKGROUND_STATUS_ENABLED:
// Background data usage and push notifications are blocked for this app
return true;
case RESTRICT_BACKGROUND_STATUS_WHITELISTED:
case RESTRICT_BACKGROUND_STATUS_DISABLED:
// Data Saver is disabled or the app is whitelisted
return false;
}
}
If Data Saver is enabled and your app is not whitelisted, push notifications will only be delivered when your app is in the foreground.
You can also check ConnectivityManager.isActiveNetworkMetered() if you should limit data usage no matter if Data Saver is enabled or disabled or if your app is whitelisted.
Complete example in the docs where you can also learn how to request whitelist permission and listen to changes to Data Saver preferences.
Since Android Lollipop we have isPowerSaveMode() , here is the example-
PowerManager powerManager = (PowerManager)
getActivity().getSystemService(Context.POWER_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
&& powerManager.isPowerSaveMode()) {
// Animations are disabled in power save mode, so just show a toast instead.
Toast.makeText(mContext, getString(R.string.toast), Toast.LENGTH_SHORT).show();
}
I am working on android project, where NFC is used as a communication. I am facing a weird problem, when mobile device has a NFC, it is enabled, but it is not working on some devices (adapter is not enabled when debugging). I am writing logs and it prints, NFC on, adapter disabled.
For example: HTC One m9(os 7.0). Also happens with OnePlus One(os 9)! But again, it works on other devices.
Did you experience the same issue?
Here is some code:
object NfcUtil {
fun getNfcAdapter(c: Context): NfcAdapter? {
val manager = c.getSystemService(Context.NFC_SERVICE) as NfcManager
return manager.defaultAdapter
}
fun doesSupportHce(c: Context): Boolean {
return c.packageManager.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
}
}
val adapter = NfcUtil.getNfcAdapter(this)
if (adapter != null && NfcUtil.doesSupportHce(this)) {
if (adapter.isEnabled) {
tvNfcOff.extHide()
} else {
tvNfcOff.extShow()
}
}
I think that if NFC is supported and enabled but the adapter is disabled (https://developer.android.com/reference/android/nfc/NfcAdapter#isEnabled()) I'll follow the guidelines and redirects the user to the settings screen with the intent mentioned in the documentation.
If the user come back few times you could monitor it and show a different message instead of redirecting to settings, something like: NFC is not working properly on your device. I'd check if you have lots of users using those devices, if yes, I will try to research more on the Operating System and Device having this issue.
And later on I will just try to debug it with that Device and that specific Operating System that is having this kind of issue. I'll try to see if other apps using NFC has same issues or they work fine, and by work fine I mean that the communication happens not that other apps dont show any warning/error popup message.
And if I found out its an issue in a specific OS Version, also with other apps, I'll just try to inform the users and get an update on which version the issue have been fixed. Otherwise if other apps can make a successful NFC communication in that device/OS that is not working for me, I'll just dig deeper.
For now I can say there is nothing wrong in your implementation and looks good.
It might be an issue with the current OS or if you have any Custom ROM that might not fully support or have a functional NFC driver.
Two additional bits of info that might be useful
1) Use a Broadcaster receiver to get notified when the NFC state changes, because using the quick settings pull down does not pause your app, therefore retesting nfc status in onResume does not work (a user changing via the full settings app will pause you App, though)
Example of how to do it in Java
#Override
protected void onCreate(Bundle savedInstanceState) {
// All normal onCreate Stuff
// Listen to NFC setting changes
this.registerReceiver(mReceiver, filter);
}
// Listen for NFC being turned on while in the App
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED)) {
final int state = intent.getIntExtra(NfcAdapter.EXTRA_ADAPTER_STATE,
NfcAdapter.STATE_OFF);
switch (state) {
case NfcAdapter.STATE_OFF:
// Tell the user to turn NFC on if App requires it
break;
case NfcAdapter.STATE_TURNING_OFF:
break;
case NfcAdapter.STATE_ON:
// Do something with this to enable NFC listening
break;
case NfcAdapter.STATE_TURNING_ON:
break;
}
}
}
};
2) Don't assume that the device has a NFC settings page, if your app works with and without NFC, if the adapter is null don't assume you can start an Intent to the NFC settings page as suggested by #denis_lor as this will cause a crash if the OS does not have a NFC adapter to turn on.
I'm using Firebase as my cloud data in my android app. I'm using it's Firestore and Authentication feature. But when I try to signup it is showing me :
"An internal error has occurred. [7:]"
So, to solve this I came to search for the solution so I found that if I update the google_service.json file everything is going to be right. But When I updated it sometimes it is working and after some time it again shows me the same error.
I get this error while testing my app behavior when deliberately disabling my mobile internet connection and trying to login to my app using firebase Auth.
Try testing your network connectivity on Activity launch and display a toast
public static boolean getConnectivityStatus(Context context) {
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
if (null != activeNetwork) {
if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI)
return true;
if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE)
return true;
}
Toast.makeText(context, "No network connection!", Toast.LENGTH_SHORT).show();
return false;
}
I had same problem with authentication via Firebase in my RN iOS project. After some research I found out that "Email/Password" Sign In/Up option was disabled. So I just turned it on. Hope it will help someone with similar issue.
https://i.stack.imgur.com/zoQ6g.png
Please check the internet connection of your device. I make the same mistake after internet connection enables it working.
Same error happened while I tried with network connection off and firebase authentication with email and password. for example,
FirebaseAuth.getInstance().signInWithEmailAndPassword(email, password)... { ... }
If network connection is on, then it works fine.
make sure you run your emulator like this in vs Code
flutter emulators --launch Nexus_6_API_29 -dns-8.8.8.8
this will solve your problem
I am working on an android app with an email feature. I want my users to be able to compose and send emails while in airplane mode. For that I need some sort of queue that can check if there is network and send, etc. I image this must have been done 100s of times. But I am not really sure why my searches aren't turning up much. Does anyone know of a library or git project that I can use to accomplish this? If not, does anyone know how to accomplish this?
I believe it is called the Queue and send pattern.
Update
I am starting a bounty on this question. What I hope for is a working example that does not use SMS. For my particular case I am working on an Appengine Connected Android Project. The client needs to send data (String, Bitmap, etc under a particular POJO say Dog) to the server. I want to be able to queue up these data somehow. I can use Gson to save data to file, etc. The bottom line is that I need to be able to check for network. When there is network I dequeue my queue into the server. If there is no network, I keep saving into the queue.
My queue can be Queue<Dog>, where Dog is my class with fields such as Bitmap (or path to image), String, long, etc.
I am looking for a working example. It can be very simple, but the example must work. A git zip would be great. I am giving up close to half of my points for this question.
class Dog{
String dogname;
String pathToImage;
int dogAge;
//etc.
}
//Design pattern for sending Dog to server
0) Unmarshall queue from file using Gson
1) Add dog to queue
2) If there is network, loop through queue and send data to server
3) if there is no network save queue to file
//Ideally, as soon as there is network, the method should be able to detect so and run to send data to server
First you need to set up a receiver to watch the wifi connection to see when they have data, you could also check for normal 3g/4g connections and make a broadcast receiver for that as well. todo this let use implement a broadcast receiver for connection status changes. put something like this in the manifest in the application tag
<receiver android:name=".NetworkChangeReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
now we need to make the receiver we just defined in the manifest
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//here, check that the network connection is available. If yes, start your email service. If not, stop your email service.
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();
if (info != null) {
if (info.isConnected()) {
//start service
Intent intent = new Intent(this, ItemServiceManager.class);
startService(intent);
}
else {
//stop service
Intent intent = new Intent(this, ItemServiceManager.class);
stopService(intent);
}
}
}
}
What this does is puts a big fat antenna called NetworkChangeReceiver out in android land, that is fine tuned to listen in on when android has something to say about a change in the data connection status.
now you need to build your ItemServiceManager.class which should read from a database (it should also extend Service. It should choose the oldest item in the database, (email it, text it, upload to server, whatever), and if the connection was successful then remove the item from the database, and load the next oldest one. If there is no more then close the service and the broadcast receiver.
If you have a connection and the user needs to send more data, then add it to the database, and then make sure the service is started. Maybe notify it that it should double check the database (after a few seconds) before deciding it can close because nothing is there.
This is how you might disable your broadcast receiver.
PackageManager packageManager = context.getPackageManager();
ComponentName componentName = new ComponentName(context, NetworkChangeReceiver.class);
packageManager.setComponentEnabledSetting(componentName,PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
When a new item is to be uploaded, if there is no web connection, the email should be saved to the database and the broadcast receiver should be started to know when internet is back so it can know when to upload. You might start it up like this.
PackageManager packageManager = context.getPackageManager();
ComponentName componentName = new ComponentName(context, NetworkChangeReceiver.class);
packageManager.setComponentEnabledSetting(componentName,PackageManager.COMPONENT_ENABLED_STATE_ENABLED,PackageManager.DONT_KILL_APP);
The whole point is you only care about connection broadcasts when you have something stored to be uploaded but can not upload it because of no data connection. When you have nothing to upload, don't waste processing and battery by keeping your receiver/service around. And when you do have emails waiting, then start up you broadcastreceiver, to know when you have data connection so that you can start uploading.
I do not think anyone is going to write a whole working solution for you, hopefully this is more than enough to get you on your way.
Edit:
Another thing you can do, is let the server allow acceptance of an array of your items, that way you can just upload it all at once when you get a valid connection. Generally you would do this if each item was decently small. But if you are uploading pictures or videos or anything large, best to do it one at a time probably.
I've been looking into this for a while and have been unable to find a concrete solution.
I'm trying to detect when a user has started using their internet (3G, Wifi). (Or is about to start would be even better).
Does anyone know if there is an Intent that could detect a person is starting to use the network? What I'm trying to do is run some code once the user starts using their internet regardless of whether or not it is 3G or Wifi.
I've been looking into ConnectivityManager, and Trafficstats() but have so far been unable to come up with a solution. I am not simply looking to see if a connection is available.
One solution that I've been thinking would be to create my own intent but I've been unable to find any good documentation on how to create your own intent filter. (most tutorials I've seen say to use/specify your own Intent, but neglect to say how to create the intent) Because of this, I'm assuming it's something simple that people don't feel is worth mentioning.
The idea behind using an intent was so that I could trigger code to execute on the event that the user is using the internet, not just connected to it. This would be preferable to having a continually executing loop that looks for rx/tx bytes sent out.
If anyone has any ideas and sample code that would be really appreciated.
Cheers
I do not know if this helps, but with this code I am trying to find when device goes into no network. I am sure you can modify this to detect if its 3G or WiFi.
no network
Copied from one of my projects http://code.google.com/p/android-menu-navigator/
You can combine it with the connection state changed mentioned by bandaa25 and I think you are done.
public boolean isOnWifi() {
Log.d(TAG, "Checking if we are on wifi");
final ConnectivityManager mgrConn = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
Log.d(TAG, "Retrieved connectivity manager");
final NetworkInfo network = mgrConn.getActiveNetworkInfo();
Log.d(TAG, "Retrieved network info: " + network);
final boolean result = network != null && network.getType() == ConnectivityManager.TYPE_WIFI;
Log.d(TAG, "Result : " + result);
return result;
}