When I swipe up to refresh my ListView, I perform a click using performClick(), but the wheel freezes until everything that's under the onClickListener is executed.
btini.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Code here
refreshlistmain.setRefreshing(false);
refreshlistmain.setOnRefreshListener(
new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
btini.performClick();
}
}
);
Since the code under onClick() is quite long, the wheel stays frozen for a couple of seconds before disappearing.
How do I fix that?
This code arrangement is wrong. It a recursive call. On each click a new SwipeRefreshLayout.OnRefreshListener will be registered. Just use it like below . Perform long running task and then at last call refreshlistmain.setRefreshing(false);. If long running task is on worker thread then you need to wait for it to complete.
btini.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Do stuff
refreshlistmain.setRefreshing(false);
}
});
refreshlistmain.setOnRefreshListener(
new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
btini.performClick();
}
}
);
This is because you have some long task on UI thread. It will not freeze not only SwipeToRefreshLayout but also any animation or ProgressBar you have (got that).
Solution
Put your task (which you are doing after button click) in AsyncTask or different thread. Which will run Asynchronously.
Related
Is it possible to use only SwipeRefreshLayout loading animation without really refreshing view i.e on initial loading lot's of data?
This animation:
I want to show swipe animation before any view is show, as preloader for view.
Tried different combinations on wiew create, when I use
swipeRefreshLayout.setRefreshing(true);
and
swipeRefreshLayout.setRefreshing(false);
Thing works fine, but my swipe listener then doesn't work, it doesn't even catches event.
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
SomeCustomFragment.refreshFragment();
swipeRefreshLayout.setRefreshing(false);
}
});
Is that I'm trying to do even possible?
You can try this:
refreshLayout.post(new Runnable() {
#Override
public void run() {
refreshLayout.setRefreshing(true);
// load data
.....
}
});
Try with below code to trigger the swipe refresh layout programmatically.
swipeRefreshLayout.post(new Runnable() {
#Override
public void run() {
swipeRefreshLayout.setRefreshing(true);
}
});
By calling directly swipeRefreshLayout.setRefreshing(true) the OnRefreshListener will NOT get executed.
In order to stop the circular loading animation call swipeRefreshLayout.setRefreshing(false)
Views will be rendered on the screen after the onCreate() method. So you need to have a callback function that executes after the onCreate() method.
Something like below will do the trick.
swipeRefreshLayout.post(new Runnable() {
#Override
public void run() {
swipeRefreshLayout.setRefreshing(true);
//Do your stuff here
}
});
Remember to set the animation off by setting
swipeRefreshLayout.setRefreshing(false)
As soon as you're done with the task
I have this code:
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!clicked){
clicked = true;
fab.setImageResource(R.drawable.ic_media_stop);
char[] userInput = et.getText().toString().toLowerCase().toCharArray();
compareToMap(userInput);
}else{
clicked = false;
fab.setImageResource(R.drawable.ic_media_play);
}
}
});
When the floating action button is clicked, I want it to change to a stop symbol and then execute the function afterwards. What is happening is that the code is being executed before the image on the button changes. The image only changes once all of the code has been executed from the compareToMap function even though it is placed before it in the code. Is there a way to make sure that the image changes before the compareToMap function executes?
Note: The compareToMap function contains Thread.sleep methods which is causing the UI to block (I think), but shouldn't the image change before that function is executed?
At this moment the UI didn't load yet. If you want to do some work after the UI is loaded you can use the class Handler.
long postDelay = 100; //The delay (in milliseconds) until the Runnable will be executed
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Code that you want to execute after the UI is loaded
compareToMap(userInput);
}
}, postDelay);
Note: You can't use Thread.sleep on the UI main thread. You can learn more here. https://developer.android.com/guide/components/processes-and-threads.html.
You can use AsyncTask to execute the compareToMap(userInput) method, this will run the compareToMap method in a separated thread and the UI will not be blocked; something like this :
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fab.setImageResource(!clicked ? R.drawable.ic_media_stop : R.drawable.ic_media_play);
if (!clicked) {
// Cancel the executing AsyncTask if there's one already running
if (mAsyncTask != null) {
mAsyncTask.cancel(true);
}
mAsyncTask = new AsyncTask<String, Void, Void>() {
#Override
protected Void doInBackground(String... params) {
compareToMap(userInput);
return null;
}
};
mAsyncTask.execute();
}
clicked != clicked;
}
});
More info about AsyncTasks here or you can check this tutorial.
I have researched how to start the Android SwipeRefreshLayout programmatically.
I have found that website where it is explained how to do that.
Here is the code how I start the animation:
mSwipeRefreshLayout.post(new Runnable() {
#Override
public void run() {
mSwipeRefreshLayout.setRefreshing(true);
}
});
BNow I would like to stop the animation of the SwipeRefreshLayout when the data is loaded.
The code
mSwipeRefreshLayout.setRefreshing(false);
does not work for me.
Has anyone an idea ?
mSwipeRefreshLayout.setRefreshing(true); does not appear to trigger the onRefresh() listener. It only shows the animation. I'm assuming you are calling mSwipeRefreshLayout.setRefreshing(false); as a result of something that happens in your refresh handler.
The solution is to call your refresh method manually from within the Runnable.
mSwipeRefreshLayout.post(new Runnable() {
#Override
public void run() {
mSwipeRefreshLayout.setRefreshing(true);
myRefreshMethod();
}
});
I eventually managed to get my other post sorted; to create a way to update the GUI every second or so. So my runnable runs fine but now I've added a button to the GUI which is meant to stop the runnable. But how do you do it?
I've tried this code:
// Button to stop the runnable
stop = ( Button ) findViewById( R.id.stop );
stop.setOnClickListener( new View.OnClickListener()
{
#Override
public void onClick(View v)
{
handler.removeCallbacksAndMessages( timerTask.class );
}
});
I implement Runnable in order to use it, therefore I don't create a new Thread manually and add a run() method to it. So how do you do it?
Thanks
You can't just murderize the thread. What you'll need to do is add a method to your Runnable object implementation that acknowledges a request to stop. That method then flips a condition that causes your Runnable.run() method to exit.
public class YourClass implements Runnable {
private boolean keepGoing = true;
public void run() {
while(keepGoing) {
// Do important work!
}
}
public void stop() {
this.keepGoing = false;
}
}
So in your onClick(View v) implementation for your stop button, you would call yourClassInstance.stop(). That breaks the loop, the run() method ends, and the thread is cleaned up.
This question is not only limit for Button or this setter.
For example, here a button listener:
runButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
runButton.setEnabled(false);
runScript();//This function will take a long time!!
}
});
When this button is clicked, I want it be disabled immediately. However, practically, I see this button won't get disabled until all the methods finished, that is after the method runScript() finishes, the button actually turns grey.
So, could anyone tell me how to make the button disabled right after that line?
What happens is the runScript method blocks the UI thread. What you want to do inside your onClick method is disable the button then run the script in a different thread, like so
runButton.setEnabled(false);
new Thread(new Runnable() {
#Override
public void run() {
runScript();//This function will take a long time!!
}
}).start();
More information found here:
http://developer.android.com/guide/topics/fundamentals/processes-and-threads.html
As a general rule of thumb, you want to avoid doing anything that may take a long time on the UI thread. What you can do in your click listener is spawn a new thread that does the long-running method in the background. The android AsyncTask class provides a lot of support methods for having background threads that can send updates back to the UI via progress events.
Try calling runButton.invalidate() immediately after setEnabled(false) method
Also
You should not have long running methods in the UI thread transfer runScript() to an asynch task. Button state will get updated faster
runButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
runButton.setEnabled(false);
MyTask asyncTask = new MyTask();
asyncTask.execute();
}
});
private class MyTask extends AsyncTask<void, void, String> {
protected String doInBackground(void) {
runScripts();
//set to something relevant to your app
String result ="";
return result;
}
protected void onPostExecute(String result) {
//do something
}
}
I