Android Parse. Getting Data More Efficiently? - android

I am Creating a small app, where each owner of the app can tap a button and increment the number on screen by one. The idea is that each app is connected and each user can see the same number so it updates on all devices. I decided to use the Parse SDK to store the Number online to be accessible on all devices. I have a simple button, that uses the following code when pressed:
button.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
query.getInBackground("SQrRpfRBZW",
new GetCallback<ParseObject>() {
#Override
public void done(ParseObject num, ParseException e) {
if (e == null) {
taps.setText(String.valueOf(num
.getInt("Num") + 1));
count = num.getInt("Num");
num.put("Num", count + 1);
num.saveInBackground();
} else {
// ERROR
}
}
});
return false;
}
});
Then, I have a runnable, that is supposed to get the current value that is stored online every 500ms and update it on screen:
// RUNNABLE FOR UPDATES
handler = new Handler();
final Runnable r = new Runnable() {
public void run() {
query.getInBackground("SQrRpfRBZW",
new GetCallback<ParseObject>() {
#Override
public void done(ParseObject num, ParseException e) {
if (e == null) {
taps.setText(String.valueOf(num
.getInt("Num")));
} else {
// ERROR
}
}
});
handler.postDelayed(this, 200);
}
};
handler.postDelayed(r, 100);
}
When I run the app, the number updates when I press the Button, but it is extremely slow, and the Garbage Collector is doing a lot of work.
Is there a more efficient way to Send and Retrieve the Data more quickly using Parse? And what am I doing wrong in regards to the Garbage Collector? I don't think im creating many new Objects.
Thank You Very Much for your time.

The garbage collection issues may be coming from the fact that you are creating a new runnable object every 200 milliseconds and then putting it on the android message queue.
And I think a much more efficient way of notifying users when the number has been updated is to force the server to push notifications instead of having the phone query the server. You should use GCM for this. Parse even has built in ability for it.
I think ultimately, you should create a parse cloud function that you call every time a user presses the button, and in that cloud function, you push down a notification to all the other users that the number has updated and that they need to query the server.

Everytime you call new Runnable or new Handler, or new GetCallback you are creating a new Object. A better way to do this is to create all of your callbacks ONCE in onCreate of your activity or fragment and reuse them over and over.
so your code would look something like
private Runnable mRunnable;
#Override
public void onCreate(Bundle mBundle)
{
super.onCreate(mBundle);
mRunnable = new Runnable() {
public void run() {...}};
//create all of your callbacks here and reuse them
}
And when you get ready to use that runnable you would do
handler.postDelayed(mRunnable, 100);
You never want to create objects outside of onCreate. Object memory allocation and creation is an expensive operation.

Related

runOnUiThread updates wrongly

While update UI using runOnUiThread new value is replaced old value.
#Override
public void onBackgroundRequestCompleted(final String layoutID) {
((Activity) ctContext)
.runOnUiThread(new Runnable() {
public void run() {
reDesignLayout(layoutID);
}
});
}
Here layoutID will be get from server. I will send 10 to 40 request at a time. So 40 response will be received in sequence. But the problem is when 1 response received runOnUiThread will start. before it completes it work I will receive 2nd response. So what happening is redesingLayout() receives 2nd layout id instead of 1st layout id. It is happening for multiple times. So UI is not updated fully. Can any one give idea to solve the issue?
Thank you #Maxim Firsoff. Implemented your idea and issue solved. I added the code for future use..!!
private Queue<String> LayoutsToRedesign = new LinkedList<>();
#Override
public void onBackgroundRequestCompleted(final String layoutID) {
gridsToRedesign.add(layoutID);
((Activity) ctContext)
.runOnUiThread(new Runnable() {
public void run() {
String layoutIdToDesign = gridsToRedesign.peek();
gridsToRedesign.remove(layoutIdToDesign);
reDesignLayout(layoutIdToDesign);
}
});
}
Some strategies:
"takeLast", drops all incoming values and takes only the last one for reDesignLayout;
"takeFirst", is the same as above, but takes the first value;
"serial", collects all values in a queue, execute reDesignLayout while the queue isn't empty.

Show multiple TextView changes during OnClick

I am currently working on an app which uses Bluetooth, GPS and uploads data to a remote server. I have a simple button which launches a series of events and threads in order to let everything work together.
I am now adding TextView components on the screen, which show the user a more detailed process of what is happening. Is the GPS running? Is my Bluetooth device connected? Etc. This process can take up to 10 seconds, this is why I am adding some more information on what is happening on the background.
However, when I click my button, only the last change will be visible. I suppose the TextView components are rendered AFTER the Onclick?
An example:
#Override
public void onClick(View view) {
textView.setText(R.string.launching_text);
// start a thread
textView.setText(R.string.start_new_thread);
// start another thread
textView.setText(R.string.almost_there);
// start last thread
textView.setText(R.string.done);
}
Imagine this process taking about 10 seconds. It will look like the app "freezes", but the changes are not visible till after the OnClick finishes.
How can I show my information realtime, during the OnClick event? Is there perhaps a better practice? Is it possible to do some sort of way to asynchronously push TextView changes?
I’d suggest you first check this Android Performance Patterns video, to see some of the options at your disposal. I’d also advise to not perform multithreading in a lifecycle environment (e.g. Activities, Fragments) as this is just asking for trouble.
In your onClick example, R.string.done could (and most likely will) be displayed before the first thread has done its work. I’m assuming that’s not really what you want.
I have no knowledge of the problem you’re tackling, tools you’re using or the architecture you’re following, so here’s one slightly generic way to make it work. Each Thread in your onClick implementation comes with a status of sorts. You could represent this in code with a simple abstraction:
class Holder {
#StringRes int status;
Runnable runnable;
Holder(#StringRes int status, #NonNull Runnable runnable) {
this.status = status;
this.runnable = runnable;
}
}
Notice Runnable is used instead of Thread.
You’re also executing things in sequence. You could represent this in code with a simple List or a Queue, providing a fluid, expressive API, for example:
class StatusRunnableBuilder {
private final WeakReference<TextView> viewRef;
private final Queue<Holder> queue;
#StringRes private int finalStatus;
StatusRunnableBuilder(#NonNull TextView view) {
viewRef = new WeakReference<>(view);
queue = new ArrayDeque<>();
}
StatusRunnableBuilder addStep(#StringRes int status,
#NonNull Runnable runnable) {
queue.add(new Holder(status, runnable));
return this;
}
StatusRunnableBuilder withFinalStatus(#StringRes int status) {
finalStatus = status;
return this;
}
Runnable build() {
return new Runnable() {
#Override
public void run() {
for (Holder item: queue) {
updateStatus(item.status);
item.runnable.run();
}
if (finalStatus != 0) {
updateStatus(finalStatus);
}
}
};
}
private void updateStatus(#StringRes final int status) {
final TextView view = viewRef.get();
if (view != null) {
view.post(new Runnable() {
#Override
public void run() {
// As this has been posted to a queue,
// it could have been processed with some delay,
// so there is no guarantee the view is still present.
// Let's check again.
final TextView v = viewRef.get();
if (v != null) {
v.setText(status);
}
}
});
}
}
}
Then your onClick becomes something like:
#Override
public void onClick(View v) {
final Runnable runnable = new StatusRunnableBuilder(view)
.addStep(R.string.launching_text, launchingRunnable)
.addStep(R.string.almost_done, almostDoneRunnable)
.withFinalStatus(R.string.finally_done)
.build();
service.execute(runnable);
}
where service is an ExecutorService which allows you to create/shutdown on any lifecycle event, e.g.:
#Override
protected void onStart() {
super.onStart();
service = Executors.newSingleThreadExecutor();
}
#Override
protected void onStop() {
super.onStop();
service.shutdownNow();
}
You can use a Runnable with Handler. Handler will post updates to Runnable after certain intervals.
For Bluetooth connectivity you can go for Broadcast receivers as well.
You can try using an AsyncTask. It's pretty simple and it handles all the background threading as well as inter-thread communication for you. There are several considerations with it, to avoid memory leaks you can use EventBus or similar mechanics. Here's an article I found very useful:
http://simonvt.net/2014/04/17/asynctask-is-bad-and-you-should-feel-bad/

How to call method in thread time after time?

I have a method that loads data from Firebase into ArrayList. After this,I use that ArrayList to construct RecyclerView. I've decided to load data on another thread. Below is my code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_just);
citiesRecyclerView =
(RecyclerView)findViewById(R.id.recyclerView);
handler = new Handler()
{
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what==1)
{
cityAdapter = new
CityAdapter(MainActivity.this,cities) ;
citiesRecyclerView.setAdapter(cityAdapter);
}
}
};
t = new Thread(new Runnable() {
#Override
public void run() {
//method that loads data into List.If this method was
//successfully done,then I send message 1 to Handler
loadDataFromFirebase();
}
});
t.start();
//other operations below
}
Hope,that everything understandable. Code works fine. And my problem is that I need to use loadDataFromFirebase method in thread again. I wanted to call t.start() again in order to call loadDataFromFirebase method,but there was error that thread already started. I checked that by writing this code:
if(t.getState()== Thread.State.NEW)
t.start();
else
someMethod();
else statement worked above.
And my questions are:
1) Does loadDataFromFirebase method work really on another thread by this way?
2) How to call loadDataFromFirebase method again in another thread, if something happened? Do I need to create another variable for Thread again?
It's not a good idea to handle all low-level thread work by your own.
Accroding to Android you could:
Use AsyncTask (but notice that they have many drawbacks such as context leak in some cases etc),
I could suggest you to get into RxJava - it's a painless way to use async work in your app.
To 'download' data from Firebase you could probably use FCM (push notifications) to load data on demand.
And what about your question:
"It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution."(c) http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html#start()
If you are using firebase SDK you can use realtime database feature, so do not need to query it each time.
You should just subscribe one time and get updates. For example:
firebaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
YourDataObject value = dataSnapshot.getValue(YourDataObject.class);
Log.d(TAG, "Value is: " + value);
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
});
You can read docs here.

synchronized blocks android

I have one function: fillFromDB which fills an instances of ArrayList called list from the SQLite DB.
I also have another Thread which is suppose to clear that list and re-populate it.
I'm having some issues with the list, since sometimes the other Thread clear the list while the first one is still filling it, causing IndexOutOfBoundsException on an Adapter.
// This occurs onCreate()
fillFromDb(list);
downloadAndRepopulateList(list);
private void downloadAndRepopulateList(List list) {
new Thread(new Runnable() {
#Override public void run() {
list.clear();
// Some other clode
}
}
}
I know that the issue is cause they are not Thread-safe, but I have never used synchronized before.
So my question is:
if I change the download function like this:
private void downloadAndRepopulateList(List list) {
new Thread(new Runnable() {
#Override public void run() {
synchronized(list) {
list.clear();
// Some other clode
}
}
}
}
will it wait for the UIThread to finish filling the list on fillFromDb() and then proceed to clear and repopulate it?
if not, how should I do this?
Though I would rather recommend using LinkedBlockingQueue. i.e.
list = new LinkedBlockingQueue<SomeType>();
fillFromDb(list);
downloadAndRepopulateList(list);
private void downloadAndRepopulateList(List list) {
new Thread(new Runnable() {
#Override public void run() {
list.clear();
// Some other clode
}
}
}
LinkedBlockingQueue will itself manage synchronization for you and you dont need to hold any lock etc.
If you wish to make it using Arraylist, you will have to make it atomic from both the sides. i.e. to access list, they should first hold the lock to object and the proceed. If someone else holds the lock, then wait.
synchonized(list){
fillFromDb(list);
downloadAndRepopulateList(list);
}
private void downloadAndRepopulateList(List list) {
new Thread(new Runnable() {
#Override public void run() {
synhronized(list){
list.clear();
}
// Some other clode
}
}
}
To make it work you also have to make synchronization on your fillFromDb method. So in the end you would have two synchronized parts, one that synchronizes your filling of the list and another synchronizes clear of the list. Also you can use your list as a mutex, but I would recommend you to have a separate object as mutex, it could me just like Object mutex = new Object();.

Android - Proper way to listen for variable change, and do something upon change?

The app I'm making requires that a bit of code be executed whenever the value of a particular variable changes from 0 to 1.
The handler example below is the method I'm currently using to do this (I copied it from someone else).
I have a feeling it's not a proper method though because having just three of these handlers in my app causes the UI to be fairly unresponsive, and causes the device (a phone) to become quite hot.
As you can see, I've put 10ms delays in the handlers to try to deal with this.
Isn't there something more like OnClickListener that can listen at all times for a variable value change without putting such stress on the CPU?
I'm pretty new to Java and Android so a simple example would be very much appreciated.
final Handler myHandler1 = new Handler();
new Thread(new Runnable()
{
#Override
public void run()
{
while (true)
{
try
{
Thread.sleep(10);
myHandler1.post(new Runnable()
{
#Override
public void run()
{
if (myVariable == 1)
{
myVariable = 0;
//do stuff
}
}
});
} catch (Exception e) {}
}
}
}).start();
You must set your variable via a setter method. Then, you can be reactive to that change.
public void setMyVariable(int value) {
this.myVariable = value;
if (myVariable == 1) {
doSomethingWhen1();
} else if (myVariable == 0) {
doSomethingWhen0();
}
}
A more elegant way to do that will be an observer pattern, Here you can find more detailed documentation about it.
You must certainly avoid while(true) loops on mobile device, it will drain your battery and you are also blocking the UI thread. That's the reason why your UI is unresponsive and your cellphone it's quite hot.

Categories

Resources