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.
Related
I've a Worker in which i first want to apply FFMPEG command before uploading it to server. As Worker is already running in background so to keep the result on hold until file uploads I've used RxJava .blockingGet() method. But I'm unable to understand that how to execute FFmpeg command synchronously by anyway i.e. RxJava etc. One tip that I found is to use ListenableWorker but it's documentation says that it stops working after 10 minutes. So, i don't want to go with that solution. Following is the method of FFmpeg just like any other async method. How can i make it synchronous or integrate it with RxJava? Any ideas would be appreciable.
ffmpeg.execute(command, new ExecuteBinaryResponseHandler() {
#Override
public void onFailure(String s) {
}
#Override
public void onSuccess(String s) {
uploadMediaItem(mediaUpload);
}
#Override
public void onProgress(String s) {
}
#Override
public void onStart() {
}
#Override
public void onFinish() {
// countDownLatch.countDown();
}
});
This is the flow of my Worker:
check pending post count in DB.
Pick first post and check if it has pending media list to upload.
Pick media recursively and check if editing is required on it or not.
Apply FFmpeg editing and upload and delete from DB.
Repeat the cycle until last entry in the DB.
Thanks
If you wanna create a syncronous job you need to use the CountDownLatch class (there is a comment in your code).
CountDownLatch is a syncronization object that can be used in cases like this.
As for now there isn't a valid method to have sync workers.
Listenable workers is useful when you want to monitor the worker itself from your app using a Livedata that return useful information (e.g. the status).
If I remember correctly the standard Worker class also descend from Listenable worker so you can use that.
In your case is useful to have two workers: the first apply a FFMPEG command, and the second worker that take the output of this command to do the network upload. Separating this two operations allows you to have more time for complete the two works (10 + 10).
In your case you can do something like this for the first worker:
private final CountDownLatch syncLatch = new CountDownLatch(1);
...ctor
doWork(){
//your asyncronous call
...
#Override
public void onFinish() {
//you need to save error status into a onSuccess and onFailure
syncLatch.countDown();
}
...
//end
syncLatch.await();
...
//evaluate if there are errors
...
//create output to pass to the next worker
Data outputData = ...
//pass the result to second worker, remember that onfailure will stop all subsequent workers
if(error==true)
{
return Result.failure(outputData);
}else{
return Result.success(outputData);
}
}
For the second worker you can do the same according to your upload function behavihour to syncronize the call.
Hope this help.
Cheers.
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 over 10 fragments that execute the same kind of task which is :
Retrieving the Data from the server using Retrofit
Starting an Async Task to update the Database (Using ORMLite)
Once the Database is updated, retrieving the new data from the Database
Notify Dataset has changed in the adapter
I'm wondering if it's useless to put the update database code inside an AsyncTask within my fragment once I retrieve the data from the server?
I have trouble understanding what run on the UI thread and what doesn't and should be started as his own thread through an AsyncTask
Here my code:
private void getLocalIncidentTemplate() {
mIncidentTemplate.clear();
mIncidentTemplate.addAll(GenericDAO.getInstance(EntityGroup.class).queryForAll());
Collections.sort(mIncidentTemplate);
Log.e(TAG, "Incident Template count:" + mIncidentTemplate.size());
mListAdapter.notifyDataSetChanged();
spinner.setVisibility(View.GONE);
}
private void getRemoteIncidentTemplate() {
Call<EntityIncident> call = meepServices.getIncidentTemplate();
call.enqueue(new Callback<EntityIncident>() {
#Override
public void onResponse(Call<EntityIncident> call, Response<EntityIncident> response) {
if (response.isSuccessful()) {
new updateIncidentTemplateTask().execute(response.body());
}
}
#Override
public void onFailure(Call<EntityIncident> call, Throwable t) {
t.getStackTrace();
Log.e(TAG, t.toString());
Utils.showToastMessage(getActivity(), "Error retrieving Incidents", true);
}
});
}
private class updateIncidentTemplateTask extends AsyncTask<EntityCategories, Void, Boolean> {
#Override
protected Boolean doInBackground(EntityCategories... params) {
updateIncidents(params[0]);
return true;
}
protected void onPostExecute(Boolean b) {
getLocalIncidentTemplate();
spinner.setVisibility(View.GONE);
}
}
Here is the Database Update Using ORMlite:
private void updateIncident(EntityCategories categories) {
try {
categories.setId("MobilePlan");
//Update base categories
GenericDAO.getInstance(EntityCategories.class).addOrUpdate(categories);
for (EntityCategories.EntityCategory currentCategory : new ArrayList<>(categories.getCategories())) {
if (currentCategory.getmPlans() != null) {
for (EntityPlan myPlan : new ArrayList<>(currentCategory.getmPlans())) {
EntityPlan oldPlan = GenericDAO.getInstance(EntityPlan.class).queryById(String.valueOf(myPlan.getmId()));
myPlan.setCategories(currentCategory);
if (oldPlan != null) {
if (!myPlan.getmDateModification().equals(oldPlan.getmDateModification())) {
GenericDAO.getInstance(EntityPlan.class).addOrUpdate(myPlan);
}
} else {
GenericDAO.getInstance(EntityPlan.class).addOrUpdate(myPlan);
}
}
} else {
continue;
}
GenericDAO.getInstance(EntityLabel.class).addOrUpdate(currentCategory.getmLabel());
currentCategory.setCategories(categories);
GenericDAO.getInstance(EntityCategories.EntityCategory.class).addOrUpdate(currentCategory);
}
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "DATA updated");
}
For your particular case, you should use the AsyncTask to retrieve data from the backend and place it in the database.
Remember that AsyncTask has three main methods:
onPreExecute() that runs on the UI thread. Useful when you need to prep something that requires UI thread (touching views and whatnot)
doInBackGround() this runs on background thread
onPostExecute() runs also on the UI thread.
In onPostExecute() you could notify your adapter of the new data.
If I were you, I'd use loaders to get notified and retrieve the data off the database. So that the complete chain would be some:
AsyncTask pulls data from the backend and stores it in the database
Your loader will get notified that something changed inside the database and will pull the data from it and call onLoadFinished() method inside your activity/fragment
onLoadFinished() passes the data to the view adapter.
I haven't gone into detail as to how to implement this. I just presented the overall architecture.
I have trouble understanding what run on the UI thread and what doesn't and should be started as his own thread
The short answer:
Everything that might block the UI thread (in other words, might take time) should run on a worker thread (threadpool or dedicated)
DB actions and network requests are classic examples for actions that should always run asynchronously.
In your case I would just use an ORM to wrap all the interaction with the DB, such as ORMlite or any other you find more suitable, in that case you will not have to concern yourself with the inner workings and just provide callbacks for when your calls have finished (successfully or not)
I've been writing android apps for some months now, and I'm at the point where I'm building an actual needed app.
As I want that to work nice and fast, I made a Workerthread to do all kinds of tasks in the background while the UI can...build up and work and stuff.
It's based on the Android Studio Drawer app blueprint.
In Main.onCreate I got my operator=new Operator(), which extends Thread.
Now, when loading a new Fragment, it sometimes calls MainActivity.operator.someMethod() (I made operator static so I can use it from anywhere), and after some time I realized, the only tasks actually running in background are those in the operators run() method and an Asynctask my login Fragment runs. Everything else the UI waits for to complete and therefore gets executed by the UI thread.
So I thought: no problem! My operator gets a handler which is built in run(), and I change those tasks:
public void run() {
Looper.prepare(); //Android crashed and said I had to call this
OpHandler = new Handler();
LoadLoginData();
[...Load up some Arrays with hardcoded stuff and compute for later use...]
}
public void LoadLoginData() {
OpHandler.post(LoadLoginDataRunnable);
}
private Runnable LoadLoginDataRunnable = new Runnable() {
#Override
public void run() {
if(sharedPreferences==null)
sharedPreferences= PreferenceManager.getDefaultSharedPreferences(context);
sessionID=sharedPreferences.getString("sessionID", null);
if(sessionID!=null) {
postenID = sharedPreferences.getString("postenID", PID_STANDARD);
postenName = sharedPreferences.getString("postenName", PID_STANDARD);
context.QuickToast(sessionID, postenName, postenID);
}
}
};
context is my MainActivity, I gave the operator a reference so I could send Toasts for Debugging.
But now, the Runnables seem to not run or complete, any Log.e or Log.d stuff doesn't arrive in the console.
After some googeling and stackoverflowing, everyone is just always explaining what the difference is between Handlers, Asynctask, and Threads. And the multitask examples always only show something like new Thread(new Runnable{run(task1)}).start times 3 with different tasks.
And so became my big question:
How to correctly, over a longer time (~lifecycle of the MainActivity), with different tasks, use a background thread?
Edit: to clarify, I would also like a direct solution to my special problem.
Edit 2: after reading nikis comment (thank you), the simple answer seems to be "use HandlerThread instead of thread". Will try that as soon as I get home.
Trying a HandlerThread now. It seems my OpHandler, initialized in run(), gets destroyed or something after run() has finished, not sure whats up here (this is btw another mystery of the kind I hoped would get answered here). I get a NullpointerException as soon as I try to use it after run() has finished.
Make your worker thread own a queue of tasks. In the run() method, just pop a task from the queue and execute it. If the queue is empty, wait for it to fill.
class Operator extends Thread
{
private Deque<Runnable> tasks;
private boolean hasToStop=false;
void run()
{
boolean stop=false;
while(!stop)
{
sychronized(this)
{
stop=hasToStop;
}
Runnable task=null;
synchronized(tasks)
{
if(!tasks.isEmpty())
task=tasks.poll();
}
if(task!=null)
task.run();
}
}
void addTask(Runnable task)
{
synchronized(tasks)
{
tasks.add(task);
}
}
public synchronized void stop()
{
hasToStop=true;
}
}
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.