I am new to Android and I am having trouble understanding the concept so basically this is what i want to do to understand it better..
I created a DrawShape class that extends view. In this class in the OnDraw() I am creating a circle and filling it with a color.
From the Activity I am calling the application. //Until this point I am doing fine.
Now, I need to re-paint the Circle multiple times (Blue, Red, Yellow etc..)
So I was reading and the best way is to use Threads.. I also read you need to use postInvalidate() to redraw (I still dont understand from where I should be calling this) is this called from the Activity?, or within the OnDraw()?.
Hopefully you understand what i want to accomplish, is just that i havent found a good tutorial that shows this, how to repaint something x amount of times .. when I do Thread.sleep() it all stops then it shows my app.. but now i understand why, because i am playing with the main Thread.
Please help me understand this..
Thank you
i did something like this
animcolor()
{
Timer timer = new Timer();
int delay = ...;
int period = ...;
timer.schedule(new TimerTask(){
run() {
setColor( randomint() ); )
customview.postInvalidate();
}
}, delay, period);
threads? not necessary to create them; Timers make a good job on concurrency.
... and the code would somewhat look like....
res/layout/file.xml
<org.customviewlayout a:id="#+id/customlayout"/>
src/org.MyActivity.java
class MyActivity
{
onCreate()
{
customlayout = findViewById(R.id.customlayout);
customlayout.animcolor();
}
}
src/org.customlayout.java
import org.customview;
class customlayout
{
customview;
customlayout(context, attrs)
{
customview = new customview();
addview(customview); // so it's onDraw() method will be called
}
onlayout(...)
{
customview.layout(...);
}
animcolor()
{
Timer timer = new Timer();
int delay = ...;
int period = ...;
timer.schedule(new TimerTask(){
run() {
setColor( randomint() ); )
customview.postInvalidate();
}
}, delay, period);
}
setcolor(int)
{
....
}
}
i think, you can do this using a Timer and a TimerTask inside your activity. The TimerTask runs with the delay you specify and when run all you what to do is yourDrawShapeInstance.postInvalidate();
the mechanism is this, because you arent on the ui thread you call postInvalidate() to add an invalidate on the ui queue, when the ui engine pick the delayed invalidate that you invoke before, then calls automatically the onDraw method of your DrawShape view and the view will be redrawed.
(i donĀ“t test this, i write here)
TimerTask task = new TimerTask(){
public void run(){
myDrawShapeInstance.postInvalidate();
}
}
When drawing, always use a thread away from the main thread and always invalidate after thread has finished (for the most part -- to display current results from drawing). You will probably call your drawing functions from some user-related event, so make sure you're making another thread for that drawing process. Follow those rules and you will be fine.
void drawCircleToCanvas(int color)
{
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
myDrawShapeInstance.postInvalidate();
}
};
Thread updateUI = new Thread() {
public void run() {
//************draw something here***************
handler.sendEmptyMessage(0);
}
};
updateUI.start();
}
Related
I'm using code that looks like this :
_thread = new Thread(){
#Override
public void run() {
try {
while (true) {
operate();
Thread.sleep(DELAY);
}
} catch (InterruptedException e) {
// Doesn't matters...
}
}
};
operate function looks like this :
// does things....
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
// adds an ImageView to the screen
}
});
// does other things...
At the bottom line, what i wanted to achieve is an operation that happens once in a while, without interrupting the main thread and the UI, something like a game-loop.
In the first 2 times that operate() runs, it adds the ImageView and everything is alright, but after 2 or 3 times it stops adding the ImageViews, but the UI is still running as usual. When i debugged the problem, i found out that after 3 times the run() method of the Runnable isn't called anymore, even thought the operate function was called.
The wired thing (for me) was that when i removed the Thread.sleep, everything worked fine (much faster of course...). I tried to replace it with a very long for loop (just for checking) and it worked, but of course it is not an appropriate solution to the problem.
I read about the problem, most of the people that asked this question did a thread.sleep or an infinite loop on the main thread, but, as i see it, i didn't do such thing. Many people wrote that you should replace the Thread.sleep with Handler.postDelayed. I tried to do it but it didn't work, maybe I did it wrong. I even tried replacing the runOnUiThread with other options I found on the internet, but all of them gave me the same exact results. I tried to replace the method that I'm adding the view to the activity, but all of them, again, gave the same result.
The waiting is crucial for this application. I got to find a way to wait sometime and then execute a function on the UI thread, cause this pattern returns at least a couple of times in my application.
It sounds like you want a post delay so that you can do the code on the UI thread after some delay. Handler Post Delay.
private static final int DELAY = 500;
private Handler mHandler;
private Runnable mRunnable;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
start();
}
private void start()
{
mHandler = new Handler();
mRunnable = new MyRunnable(this);
mHandler.postDelayed(mRunnable, DELAY);
}
private void stop()
{
mHandler.removeCallbacks(mRunnable);
}
private void doSomething()
{
// Do your stuff here.
// Reschedule.
mHandler.postDelayed(mRunnable, DELAY);
}
Recommended way of creating a Runnable.
private static class MyRunnable implements Runnable
{
private WeakReference<MainActivity> mRef;
// In here you can pass any object that you need.
MyRunnable(MainActivity activity)
{
mRef = new WeakReference<MainActivity>(activity);
}
#Override
public void run()
{
// Safety check to avoid leaking.
MainActivity activity = mRef.get();
if(activity == null)
{
return;
}
// Do something here.
activity.doSomething();
}
}
There could be several reasons why the UI Runnable isn't being executed. Probably the activity variable has something messed up with it or it's referencing the context incorrectly, or as you said the Thread.sleep() could be causing an issue. At this point more parts of the code needs to viewed to better solve the problem.
A better way of implementing your logic is to use a scheduled Timer instead of using an infinite loop with a Thread.sleep() in it. It will execute the code within a background thread. And then use a Handler to update the UI instead of activity.runOnUiThread(). Here's an example:
// Global variable within the activity
private Handler handler;
// Activity's onCreate()
#Override
protected void onCreate(Bundle savedInstanceState) {
handler = new Handler(getMainLooper());
Timer timer = new Timer("ScheduledTask");
// Timer must be started on the Main UI thread as such.
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
operate();
}
}, 0L, DELAY);
}
private void operate() {
// does things in background....
handler.post(new Runnable() {
#Override
public void run() {
// adds an ImageView to the screen from within the Main UI thread
}
});
// does other things in the background...
}
Is there any function in Android that can use to make the activity wait for an interval and continue working?
I mean , for example, I use setContentView() to set a layout , and after 3 seconds it will load another layout, and continue to do another job, I don't need to repeat doing same thing after an interval, just continue do another thing.
Thanks in advanced.
You can Use Following Method to Set Interval
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// This method will be executed once the timer is over
// Do your code here
}
}, 3000);
Here, 1000 = 1 Second
But Before running this code make sure that you are not in BACKGROUND PROCESS THREAD...otherwise this may cause an error..
Do it at Android Style:
Handler mHandler = new Handler();
mHandler.postDelayed(runnableHandler, 3000);
private Runnable runnableHandler = new Runnable() {
#Override
public void run() {
doSomething()
}
};
private void doSomething() {
// Before do something remove all callbacks from Handler
mHandler.removeCallbacks(runnableHandler);
andFinallyDoWhatYouNeed();
}
I have been developing iOS apps for quite a time and now i have switched to android. I have a requirement in which I have to start timer(In think in Android, I need to use handler) when view appears(onResume) and invalidate timer(stop handler) when view disappears(onPause). I am able to create runnable Handler but not able to stop it.
My code is:
protected void AutoRefresh() {
try{
handler.postDelayed(new Runnable() {
public void run() {
new LongOperation().execute("");
}
AutoRefresh();
}, 60000);
}
catch(Exception ex){
}
}
Now, how can I stop this this handler thread when view disappears. Please also comment, if its not the right way to do timer implementation in android.
when view appears(onResume) and invalidate timer(stop handler) when
view disappears(onPause). I am able to create runnable Handler but not
able to stop it.
Keep a reference to the Runnable you use:
private Runnable mRefresh = new Runnable() {
public void run() {
new LongOperation().execute("");
}
AutoRefresh();
}
//...
protected void AutoRefresh() {
handler.postDelayed(mRefresh, 60000);
}
and in onPause remove it like this:
handler.removeCallbacks(mRefresh);
Keep in mind that this will not remove the currently Runnable that is being executed(if any) so in the LongOperation's onPostExecute method you might want to check if the Activity is still available before refreshing the UI or doing any other interaction with the Activity.
Please also comment, if its not the right way to do timer
implementation in android.
You seem to need to do an action at a certain interval of time and using a Handler is the way to do it, I don't think a timer is what you need.
I has use OnTouchListener to visible layout1 while screen was touch.
Now I want invisible layout1 while the screen didn't be touch three seconds.
But I don't know which event listener can I use?
Now the problem has be resolved.
But another one was appear.
I use:
class unTouchTask extends TimerTask {
public void run() {
if(untouch == true) {
RelativeLayout rl = (
RelativeLayout)findViewById(R.id.relativeLayout2);
rl.setVisibility(View.INVISIBLE);
timer.cancel();
untouch = false;}
}
}
Below error on linerl.setVisibility(View.INVISIBLE);:
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Option1 : You need to run a timer to track the user intraction inactive time, and on every user touch you will need to reset the timer.
Code your timer as below:
class UpdateTimeTask extends TimerTask {
public void run() {
//hide your layout
}
}
And in the event listener to start this update, the following Timer() instance is used:
if(startTime == 0L) {
startTime = evt.getWhen();
timer = new Timer();
timer.schedule(new UpdateTimeTask(), 300, 200);
}
NOTE :In particular, note the 300, 200 parameters. The first parameter means wait 300 ms before running the clock update task the first time. The second means repeat every 200ms after that, until stopped.
Option 2: Fortunately, the role of Timer can be replaced by the android.os.Handler class, with a few tweaks
You can get more detailed example at http://www.vogella.de/articles/AndroidPerformance/article.html
Regards.
You can use the Timer and TimerTask to schedule something to happen in a time interval.
If the user ever touches the screen, cancel the timer and reset it. You will need to UI related stuff in the UI thread. This article will give you an idea.
You are getting this Error because You can use threads but all the views, and all the views related APIs, must be invoked from the main thread (also called UI thread.) So the solution to this is to use the Handler. A Handler is an object that will post messages back to the UI thread for you. http://developer.android.com/reference/android/os/Handler.html will guide you to code handlers.
The second option is to use runOnUiThread. Following is what I do in my thread :
runOnUiThread(new Runnable() {
public void run() {
titleProgress.setVisibility(View.VISIBLE);
}
});
//long operation here
runOnUiThread(new Runnable() {
public void run() {
titleProgress.setVisibility(View.INVISIBLE);
}
});
Every 5 seconds, I want to call my webservice and get text (not images), then display it in my ImageAdapter. What would be the best way to accomplish this?
final Handler handler = new Handler();
final Runnable r = new Runnable()
{
public void run()
{
callWebservice();
}
};
handler.postDelayed(r, 5000);
It depends if you want to use a different thread or not. Do you want the user to be able to interact with the application on the UI Thread while the images are downloading? If so, then I would definitely use an AsyncTask with a small ProgressBar (style="#android:style/Widget.ProgressBar.Small")
If you don't care about threading then what #inazaruk said.
Edit: the truth is most modern apps that retrieve data from a web service will use an AsyncTask with a discreet little loader in the corner just to let the user know it's updating.
Edit 2: here's an example of using a TimerTask to run something every 5 seconds. The key is the runOnUiThread(). There may be better ways to tie all the elements together but this accurately portrays all the pieces.
myTimer = new Timer();
myTimer.schedule(new TimerTask() {
#Override
public void run() {
CallWebService();
}
}, 0, 1000);
}
private void CallWebService()
{
this.runOnUiThread(fetchData);
}
private Runnable fetchData = new Runnable() {
public void run() {
asyncTask.execute();
}
};
You should call asynctask inside the application main thread. Asynctask can't be called in a background thread.