runOnUiThread updates wrongly - android

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.

Related

android - Starting an event with the completion of two threads running parallel

I have two or more network calls in separated threads on main activity start, I want to show all data after network threads done.
Thread firstNetworkCallThread=new Thread(new Runnable() {
#Override
public void run() {
// network calls and get data...
}
});
Thread secondNetworkCallThread =new Thread(new Runnable() {
#Override
public void run() {
// network calls and get data...
}
});
firstNetworkCallThread.start();
secondNetworkCallThread.start();
I want these threads work parallel, and when both of them are complete, call new event to show data.
How can I do this?
Guava has a good solution for this. If you convert your Threads to ListenableFutures (also a Guava object) you can create a list of ListenableFutures and add a callback to that list.
Futures.addCallback(
Futures.allAsList(/*future1*/, /*future2*/, /*future3*/),
new AbstractDisposableFutureCallback<List<Object>>() {
#Override
protected void onSuccessfulResult(List<Object> results) {
// whatever should happen on success
}
#Override
protected void onNonCancellationFailure(Throwable throwable) {
// whatever should happen on failure
}
});
Guava also has a bunch methods such as #successfulAsList which only contains successful results or #inCompletionOrder which orders them based on when they completed and a bunch of others.
I generally tend to use Guava as it provides a fairly clean solutions to problems like these.
An example of how to creates a ListenableFuture is as follows:
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
ListenableFuture<Object> explosion =
service.submit(
new Callable<Object>() {
public Object call() {
// get network data
return null; // return the data
}
});

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.

Retrofit "IllegalStateException: Already executed"

I have a Retrofit network call that id like to run every 5 seconds. My current code:
Handler h = new Handler();
int delay = 5000; //milliseconds
h.postDelayed(new Runnable() {
public void run() {
call.enqueue(new Callback<ApiResponse>() {
#Override
public void onResponse(Response<ApiResponse> response) {
Log.d("api", "response: " + response.body().getPosition().getLatitude().toString());
}
#Override
public void onFailure(Throwable t) {
}
});
h.postDelayed(this, delay);
}
}, delay);
This runs once, but then throws the following:
java.lang.IllegalStateException: Already executed.
at retrofit2.OkHttpCall.enqueue(OkHttpCall.java:52)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.enqueue(ExecutorCallAdapterFactory.java:57)
at orbyt.project.MyFragment$1.run(MyFragment.java:93)
Whats the issue here?
As a bonus: whats a better way to handle this? Ill be updating a map every update. I was thinking about trying to use Rx but not sure if this is an appropriate use-case, or how to implement it.
A Call can only be used once. Its documentation tells you how to use one multiple times:
Use clone() to make multiple calls with the same parameters to the same webserver; this may be used to implement polling or to retry a failed call.
So use call.clone().enqueue(..) for Asynchornous and call.clone().execute() for Synchornous respectively to ensure that you have a fresh, unexecuted Call for each request.

Android Parse. Getting Data More Efficiently?

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.

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();.

Categories

Resources