I am trying to use swipe refresh layout to update some data.
All works fine but a small bug that I can't seem to solve
When I pull to refresh, the animation gets frozen.
I have implemented it this way:
myRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
// Do some stuff
// Sleep as a demonstrator of the issue
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
myRefreshLayout.setRefreshing(false);
}
});
and also tried this:
myRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
myRefreshLayout.post(new Runnable() {
#Override
public void run() {
// Do some stuff
// Sleep as a demonstrator of the issue
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
myRefreshLayout.setRefreshing(false);
}
});
}
});
}
});
but the animation remains frozen until the everything is done, and then it just vanishes (because it hits the setRefreshing(false))
After searching a little, I thought it could be the UI that is waiting for the stuff to finish, so I tried to implement it this way:
myRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
new Thread(new Runnable() {
#Override
public void run() {
// Do some stuff
// Sleep as a demonstrator of the issue
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
myRefreshLayout.setRefreshing(false);
}
});
}
});
}
});
}
What happens in this case is that the refresh indicator never vanishes, so I guess it is not calling the runOnUiThread
I tried the same thing with the main looper (handler) instead of the runOnUiThread with the same effect.
Is there any neat way of implementing this?
Am I missing some detail?
I tried the steps described above and I also looked on Stack Overflow for similar issues to no avail.
Thanks!
It's right to do refreshing on background thread,and setRefreshing(false) on main thread. The problem is you forgot to call start() after new thread.
myRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
new Thread(new Runnable() {
#Override
public void run() {
// Do some stuff
// Sleep as a demonstrator of the issue
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
myRefreshLayout.setRefreshing(false);
}
});
}
}).start();// start the thread here
}
});
}
Related
After click button I would like to change its color, then wait one second and change its color back.
This is my code:
public void click(final View view) throws InterruptedException {
final Button btn = findViewById(view.getId());
btn.setBackgroundColor(Color.parseColor("#0000ff"));
btn.setClickable(false);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
t.join();
btn.setBackgroundColor(Color.parseColor("#e2e2e2"));
btn.setClickable(true);
}
It doesn't work. I've checked it with more complex code and debugger and it looks like all UI changes are made collectively after finish this function.
I've found this thread: apply ui changes immediately and tried to put setBackgroundColor() and setClickable() into runOnUiThread function:
runOnUiThread(new Runnable() {
#Override
public void run() {
btn.setBackgroundColor(Color.parseColor("#0000ff"));
btn.setClickable(false);
}
});
But it also doesn't work. What should I do?
Something like this :
private final Handler handler = new Handler();
public void click(final View view) {
view.setBackgroundColor(Color.parseColor("#0000ff"));
view.setClickable(false);
handler.postDelayed(() -> {
view.setBackgroundColor(Color.parseColor("#e2e2e2"));
view.setClickable(true);
}, 1000);
}
#Override protected void onPause() {
super.onPause();
handler.removeCallbacks(null);
}
The question is not very clear. However, I am trying to summarize the question that I have understood from your question.
You are trying to set a button's background color on clicking on it and change it back after some time. If this is the situation, then I think your idea of how threads work is wanting.
In your code, the button will change the color immediately as the sleep that you are using is running in another thread (other than UI thread). The code is executed correctly, however, you cannot see the effect of the Thread.sleep as its running in a separate thread.
So all you need to do here is to change the background color again inside the thread. Modify your code like the following.
public void click(final View view) throws InterruptedException {
final Button btn = findViewById(view.getId());
btn.setBackgroundColor(Color.parseColor("#0000ff"));
btn.setClickable(false);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
btn.setBackgroundColor(Color.parseColor("#e2e2e2"));
btn.setClickable(true);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
}
This should work.
I have created a demo trying to show what the code will do.
However, using Handler in case of updating UI elements in this specific case is recommended. Please see the comments below.
public void click(final View view) throws InterruptedException {
final Button btn = findViewById(view.getId());
btn.setBackgroundColor(Color.parseColor("#0000ff"));
btn.setClickable(false);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
btn.setBackgroundColor(Color.parseColor("#e2e2e2"));
btn.setClickable(true);
}
}, 1000);
}
Not sure why that wouldn't work, but I've done something similar with
delayHandler = new Handler();
delayHandler.postDelayed(new Runnable() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
//change stuff on ui
}
});
}
}, 1000);
if that doesn't work the only other functional difference in my code is that instead of btn being a final Button it's a private global variable in my activity.
Hope the following code will help :
btn.setBackgroundColor(Color.RED); // color you want for a second
new CountDownTimer(1000, 1000) {
#Override
public void onTick(long arg0) {
// TODO Auto-generated method stub
}
#Override
public void onFinish() {
btn.setBackgroundColor(Color.BLUE); //to change back color to prior state
}
}.start();
Try this,i think it's work for you..
final Button bPdf = findViewById(R.id.pdf);
bPdf.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
bPdf.setBackgroundColor(Color.parseColor("#0000ff"));
new CountDownTimer(1000, 50) {
#Override
public void onTick(long arg0) {
// TODO Auto-generated method stub
}
#Override
public void onFinish() {
bPdf.setBackgroundColor(Color.parseColor("#e2e2e2"));
}
}.start();
}
});
I have an Android App which constantly auto updating a list of data from the App's SQLite which an ArrayAdapter is used for handling the data, So for this I've made another thread or handler from the onCreate method of the Acitivity, and inside it's code there's a continuous loop for updating then waiting (or sleeping the thread for a moment, ex/ 10 sec), There are two problems involved:
1- Only the UI thread can touch it's views (though I only touched ArrayAdapter if it counts as a View).
2- Once the other thread starts to run, The UI thread seems to stuck in it, and won't update even the first UI update (complete white).
codes for the autoUpdate() method: (which is called on the last line of the UI onCreate method):
public void startAutoUpdateLogData(final int milliseconds){
continueAutoUpdate = true;
new Thread(){
#Override
public void run() {
while(continueAutoUpdate){
try{
Log.v("updating..", "");
updateLogFromDatabase();
Thread.sleep(milliseconds);
}catch(Exception e){
e.printStackTrace();
}
}
}
}.start();
}
OR:
public void startAutoUpdateLogData2(final int milliseconds){
continueAutoUpdate = true;
runOnUiThread(new Runnable() {
#Override
public void run() {
while(continueAutoUpdate){
try{
Log.e("updating...", "");
updateLogFromDatabase();
Thread.sleep(milliseconds);
}catch(Exception e){
e.printStackTrace();
}
}
}
});
}
OR
public void startAutoUpdateLogData3(final int milliseconds){
continueAutoUpdate = true;
final Handler handler = new Handler();
runOnUiThread(new Runnable() {
#Override
public void run() {
while(continueAutoUpdate){
try{
handler.postDelayed(new Runnable(){
public void run(){
Log.e("updating...", "");
updateLogFromDatabase();
}
}, milliseconds);
}catch(Exception e){
e.printStackTrace();
}
}
}
});
}
Neither of these work.
You can do many ways. But this one will be more closer solution to what you have done.
private void runThread() {
new Thread() {
public void run() {
while (continueAutoUpdate) {
try {
handler.postDelayed(new Runnable(){
public void run(){
Log.e("updating...", "");
updateLogFromDatabase();
}
}, milliseconds);
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
After trying various stuff, I finally found the solution: Anytime you have some long-run tasks to perform, you can assign a new Java thread to execute it, but when there's a need to update the UI from that thread, which can't be directly accessing any components of the UI, So in that case you only need to wrap the code with runOnUiThread() inside the other thread. ex/
private void startAutoUpdateLogData(final int milliseconds) {
final Handler handler = new Handler();
continueAutoUpdate = true;
new Thread() {
public void run() {
while (continueAutoUpdate) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.e("updating...", "");
updateLogFromDatabase();
}
});
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
I want to call adapter.notifyDataSetChanged() from another thread. I read that I should use an AsyncTask and do the adapter.notifyDataSetChanged() in post execute.
I must execute the AsyncTask every 5 seconds only on the current activity (might be parent or child activity) because only one activity can do the asynctask at the same time.
Should I create a TimerTask which executes the AsyncTask every 5 seconds, stop it when I start another activity and start it back in onResume ?
Here is my code for the thread which updates the ListView of the current Activity.
private void runEventHandler() {
new Thread() {
public void run() {
while (true) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
users.add(new User(10, "a", false));
adapter.notifyDataSetChanged();
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
Now I must be able to update the child activities' ListViews when a new User is added.
one possible way is that you create a flag in both activity to control your threads to be run ( the following codes are not runable just example to understand what you can do):
Activity A
{
public static boolean stopThread = false;
#Override
public void onResume()
{
super.onResume();
// put your code here...
stopThread =false;
runEventHandler();
}
private void runEventHandler() {
new Thread() {
public void run() {
while (A.stopThread != false) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
users.add(new User(10, "a", false));
adapter.notifyDataSetChanged();
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
#Override
protected void onStop(){
super.onStop();
stopThread =true;
}
}
Activity B
{
public static boolean stopThread = false;
#Override
public void onResume()
{
super.onResume();
// put your code here...
stopThread =false;
runEventHandler();
}
private void runEventHandler() {
new Thread() {
public void run() {
while (B.stopThread != false) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
users.add(new User(10, "a", false));
adapter.notifyDataSetChanged();
}
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
#Override
protected void onStop(){
super.onStop();
stopThread =true;
}
}
also you can use onPause() instead of onStop(). depends on your program concept.
You should a timertask like in link below : https://examples.javacodegeeks.com/android/core/activity/android-timertask-example/
the code to post any change on UIThread if you are in a different thread like doInBackground of AsyncTask:
runOnUiThread(new Runnable() {
#Override
public void run() {
// Here you can set your Ui Components
}
});
I'm programming a small android app in Java/eclipse.
In one part of my app i need a thread, as i build in the following way:
protected void onResume() {
super.onResume();
// we're going to simulate real time with thread that append data to the graph
new Thread(new Runnable() {
#Override
public void run() {
// we add 100 new entries
for (int i = 0; i < 100; i++) {
runOnUiThread(new Runnable() {
#Override
public void run() {
addEntry();
}
});
// sleep to slow down the add of entries
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// manage error ...
}
}
}
}).start();
}
Evertything works fine so far. But now i want to start that thread not automatically. I want to handle ".start()" with a button.
How can i realize it?
I'm very new to Java and Android.
Thanks in Advance!
You can use Handler with Runnable instead of your Thread idea, Check out the following code, it server your purpose,
private Handler broadcastHandler;
private Runnable broadcastRunnable;
protected void onResume() {
super.onResume();
broadcastRunnable = new Runnable() {
#Override
public void run() {
// Your UI related operations
runOnUiThread(new Runnable() {
#Override
public void run() {
addEntry();
}
});
// Add some delay
broadcastHandler.postDelayed(broadcastRunnable, 1000);
}
}
public void onButtonClick(View view) {
broadcastHandler.postDelayed(broadcastRunnable, 1000);
}
I've got a problem in Android with runOnUiThread. I start an AsyncTask (inside an Activity) that waits for a while, and after calls the method showDialog(id). After this call, it sleeps for another while, and finishes calling the method dismissDialog(id).
This is the code:
public class MyActivity extends Activity {
...
protected class StartWaiting extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... arg0) {
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Show dialog
runOnUiThread(new Runnable() {
#Override
public void run() {
showDialog(PROGRESS_DIALOG_LOADING);
}
});
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Dismiss dialog
runOnUiThread(new Runnable() {
#Override
public void run() {
dismissDialog(PROGRESS_DIALOG_LOADING);
}
});
return null;
}
#Override
protected void onPostExecute(Void arg) {
new StartServices().execute();
}
}
}
Unfortunately, the behaviour is different from what I want to do: showDialog() and dismissDialog() are called one immediately after the other.
I think that the reason why this happens is that the UI Thread execute both actions "when it can", that is at the end of sleeping actions.
Well, does it exist some "flushUI()" method that force a thread (in this case, the UI Thread) to execute every action before continue?
You could just add a synchronization point in your thread, using a CountDownLatch for instance:
final CountDownLatch latch = new CountDownLatch(1);
view.post(new Runnable() {
public void run() {
try {
// Do stuff on the UI thread
} finally {
latch.countDown();
}
}
});
try {
if (!latch.await(CAPTURE_TIMEOUT, TimeUnit.MILLISECONDS)) {
return;
}
} catch (InterruptedException e) {
// Handle exception
}