How to queue up data for server dispatch on android
Asked Answered
C

1

6

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
Ceuta answered 6/4, 2014 at 21:38 Comment(8)
@EJP I know exactly how the code should work, as my pseudocode shows. I am not very good with android handlers and checking for network so I ask for help (as I suspect the answer involves handlers). I don't need someone to solve my exact problem. But I also don't want a bunch of non-helpful vague answers, so I set the standard. The working example does not have to solve my particular problem; it simply has to address the gist of the question: i.e. how to queue data for server dispatch.Ceuta
You don't get to set the standard. SO sets the standard. Post your code.Idden
You can check out Path's Priority Job Queue. With some configuration, you should be able use it to achieve what you want.Forever
thanks @corsair992, this does look like what I needed. I will study it a bit deeper and implement it and then let you know. Thanks.Ceuta
You can't assume that your application's process won't be killed so you'll have to persist pending data. You can use Android's SharedPreferences, a SQLite database (and optionally a content provider), or manage files in the app's private storage.Intine
Haha, I like to see the history in reputation changes for Katedral Pillon. After all, not too unclever. ;) But it is fair: Helping people on stackoverflow requires time.Koto
@Forever Using the link you provided I was able to create a solution for my needs. While I like the other answer quite a bit, yours was ultimately what guided me to a solution. As such I would like to accept your answer if you will rewrite it as a response. thanks.Ceuta
@EJP The question and the analogy was helpful to me, so i really don't see your point.. he doesn't understand it so he asked, the analogy really shows he knows what he is doing.Dissepiment
H
10

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.

Hightoned answered 15/4, 2014 at 5:36 Comment(3)
I apologize for the delay in accepting your answer vs @corsair992's. I have been working on other parts of the project and should return to this difficult part soon. Thanks for taking the time to help a stranger.Ceuta
the bounty was for 200 pts, why is it you only received 100? I don't get why.Ceuta
@KatedralPillon if the answer is not accepted by the OP, and is auto selected due to being the answer with the most votes when time expires, the user who answered receives 1/2 points.Hightoned

© 2022 - 2024 — McMap. All rights reserved.