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();.
Related
In my libgdx app I have a renderer:
#Override
public void render() {
if (mUpdate) {
update();
}
.
.
.
}
The update call changes arrays which holds object that are used in subsequent calls in render.
My app disables continous rendering in create:
Gdx.graphics.setContinuousRendering(false);
Each time I want the update call to fire I set mUpdate = true from a UI thread (fired of by user action) and request rendering:
public void invalidate(boolean update) {
mUpdate = update;
Gdx.graphics.requestRendering();
}
Now the problem is invalidate(false) might be called in between implicitly by a non user action which in turn might set mUpdate = false. This leads to update never being called (but we will have 2 x requestRendering).
What would be my best solution here? Should I have an AtomicInteger counter to be sure update is always being called in my render call?
public void invalidate(boolean update) {
if (update) {
mUpdateCounter.getAndIncrement();
}
Gdx.graphics.requestRendering();
}
and then
#Override
public void render() {
if (mUpdateCounter.get() > 0) {
update();
mUpdateCounter.getAndDecrement();
}
.
.
.
}
Or if it would be possible to pass instance information (mUpdate) per renderer call.
You can call update directly in your invalidate(boolean) method:
if (update)
update();
If you need the render thread you can use Gdx.app.postRunnable():
if (update) {
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
update();
}
});
}
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
}
});
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.
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.
I have an Activity with 3 spinners. These spinners get their data from a web-service by a method that takes about 1 minute to be completed.
I want to load the Activity first and after it is made visible, call that web-service method and load data. I have tested the following codes separately but none of them solved my problem. In these samples application goes into a black screen and when the web-service operation completed, it is made visible.
#Override
protected void onCreate() {
//.........
final Runnable r = new Runnable()
{
public void run()
{
loadMyData();
}
};
Utilities.performOnBackgroundThread(r);
}
#Override
protected void onResume() {
new Thread() {
#Override
public void run() {
loadMyData();
}
}.start();
super.onResume();
}
#Override
protected void onStart() {
if (comesFromOnCreateMethod)
{
final Runnable r = new Runnable()
{
public void run()
{
loadMyData();
}
};
Utilities.performOnBackgroundThread(r);
}
comesFromOnCreateMethod = false;
super.onStart();
}
#Override
protected void onResume() {
if (comesFromOnCreateMethod)
{
final Runnable r = new Runnable()
{
public void run()
{
loadMyData();
}
};
Utilities.performOnBackgroundThread(r);
}
comesFromOnCreateMethod = false;
}
If you are getting a black screen, then I would assume your code is being run on the UI thread and not on the background, causing the UI to hang until the work is completed.
One of the best solutions to doing background work is an AsyncTask. Using this, you can call it in your onCreate() method, and when its done, it will post a callback to the UI thread for you in which you can display you data.
If you want this method to run everytime this Activity displays, then call it in onResume(). Otherwise, call it in onCreate().
In your onCreate, make the async tasks as the others have advised. Make sure you generate the content for the app first and then call the asyncTasks. You can control your spinners from the callback.
First of all, you might want to increase your accept rate, 39% is pretty low.
Anyway, you might want to check AsyncTask, it should do the thing. http://developer.android.com/reference/android/os/AsyncTask.html
Typically, you will want to initialize in onPreExecute, do the networking in the doInBackGround, and set the result to the UI thread on the OnPostExecute. Hope this will help.
Use AssynchTask() and you should call super.onResume() or any lifecycle method in respective life cycle method first then other specific method you want to do....