How to pause/delay on Android? - java

I am currently learning how to develop applications for Android mobile devices.
I wrote a test application to display numbers 0-9 on the device screen. I created a simple function to delay the number change.
However, upon running the application, only the final number is displayed. There is also a delay before this final number shows. I'm assuming that the length of the pause is my defined delay multiplied by the number of digits to be shown.
How do I create an app that changes the numbers with a delay?
public class AndroidProjectActivity extends Activity {
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
Main();
}
void Delay(int Seconds){
long Time = 0;
Time = System.currentTimeMillis();
while(System.currentTimeMillis() < Time+(Seconds*1000));
}
void Main() {
String ConvertedInt;
TextView tv = new TextView(this);
setContentView(tv);
for(int NewInt = 0; NewInt!= 9; NewInt++){
ConvertedInt = Character.toString((char)(NewInt+48));
tv.setText(ConvertedInt);
Delay(5);
}
}

One way of doing this is to create a runnable that updates your view. This will still update on the UI thread, but wait in the background. There might be mistakes in the below code, but it should run with minor tweaks..
Blocking in any of the system calls into your activity is not good, since you're blocking the UI thread. Your app will be force closed, with an Application Not Responding message. Here is another good example.
public class AndroidProjectActivity extends Activity {
private Handler mHandler;
private TextView mTextView;
private Runnable mCountUpdater = new Runnable() {
private int mCount = 0;
run() {
if(mCount > 9)
return;
mTextView.setText(String.valueOF(mCount+48));
mCount++;
// Reschedule ourselves.
mHandler.postDelayed(this, 5000);
}
}
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
// Cleaner to load a view from a layout..
TextView tv = new TextView(this);
setContentView(tv);
mTextView = tv;
// Create handler on UI thread.
mHandler = new Handler();
mHandler.post(mCountUpdater);
}
}

Try creating a thread, which sleeps for certain interval of time, and then increment the value by 1 till 9. And use Handler to update the UI.
You can also use AsyncTask

The call to main() i blocking the UI so it can not display nay numbers until the call is finished.

Related

Trying to make a basic counter using scheduled executor service

I'm new to java and was trying to make a simple android app that does the following:
display a window in the main activity
every second the value of integer i is increased by 1
update the window content to display the value of i every second
for example the window should display the following text:
1st second: "update 1"
2nd second: "update 2"
3rd second: "update 3"
...
etc
I learned that using java's ScheduledExecutorService with ScheduleAtFixedRate is better than implementing an infinite loop, so I attempted the following code:
public class MainActivity extends AppCompatActivity {
public FrameLayout mLayout;
public WindowManager wm;
public WindowManager.LayoutParams lp;
public int i;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// display a window saying "hello"
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
mLayout = new FrameLayout(this);
lp = new WindowManager.LayoutParams();
lp.format = PixelFormat.TRANSLUCENT;
lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
LayoutInflater inflater = LayoutInflater.from(this);
inflater.inflate(R.layout.text_bubble, mLayout);
((TextView) mLayout.findViewById(R.id.text)).setText("hello");
wm.addView(mLayout, lp);
//creating a scheduled executor service, it runs the method "myTask" at fixed rate of 1 second
final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
myTask();
}
}, 0, 1, TimeUnit.SECONDS);
}
private void myTask() {
Log.v(TAG,"Running");
//Increment i by 1 and update the window layout
i = i + 1;
((TextView) mLayout.findViewById(R.id.text)).setText("update " + i);
wm.updateViewLayout(mLayout, lp);
}
}
When I start the app it does display the window as intended, but it doesn't update the number every second, instead it only shows "update 1". I can't tell why as I didn't get any errors. After some trial and error I found that when I remove the last two lines from the myTask method (the lines responsible for updating the text of the window layout):
((TextView) mLayout.findViewById(R.id.text)).setText("update " + i);
wm.updateViewLayout(mLayout, lp);
when I remove these two lines the executor service will function just fine, and I can see that by watching the logged text message "running" popping every second. but when I add those two lines again, it doesn't pop these messages anymore(except for the first second).
so what am I doing wrong here? I thought the problem could be about the the way I update the layout maybe. what am I missing here?
Try this:
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
//Your stuff
}
}, 0, 1000);
Or this using the scheuldedServiceExecutor:
final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
//Your stuff
}, 1, 5, TimeUnit.SECONDS);

Prevent crashing while heavy process

I am making a Map based app where users would often load over 10k polygons on the map. The only problem is that the only way to add a polygon to the map is in the UI thread, which means when I add them it will either freeze for 5 - 10 seconds or it will crash.
I'm ready to accept that it will just have to take time to load, but is there a way I can slow down the for loop when the system is struggling to prevent the crashing and even the freezing? One method I have thought of is putting a short delay on the for loop, but that will be less than ideal as it will have to take much longer then it has to to be on the safe side.
protected void onPostExecute(HashMap<String, ArrayList> result){
for(String key : result.keySet()){
List<PolygonOptions> thisList = result.get(key);
for(PolygonOptions poly: thisList){
Polygon thisPoly = mMap.addPolygon(poly);
}
}
}
Here there is a pseudo code about how I solve this:
private final Handler handler_render_data = new Handler ();
private int actualItemRendering;
private static final int HANDLER_RUN_DELAY = 1000;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Display the message telling the user to wait
// This Linear Layout includes a text and cover all teh screen
lyt_report_progress = (LinearLayout) findViewById (R.id.lyt_report_progress);
lyt_report_progress.setVisibility (View.VISIBLE);
lyt_report_progress.requestFocus ();
lyt_report_progress.setClickable (true);
// Your code calling your async task
}
// Your callback from your async task
private void callbackHere (Data myData) {
this.localMyData = myData;
// You store your data locally and start the rendering process
actualItemRendering = 0;
handler_render_data.post (createDataFromTaskResult);
}
private Runnable createDataFromTaskResult = new Runnable () {
#Override
public void run () {
if (actualItemRendering < myData.length ()) {
// Render your data here
// Continue with the next item to render
actualItemRendering++;
handler_render_data.post (createDataFromTaskResult);
} else {
// All fields were rendered
handler.postDelayed (hideProgressBarTask, HANDLER_RUN_DELAY);
}
}
};
private Runnable hideProgressBarTask = new Runnable () {
#Override
public void run () {
lyt_report_progress.setVisibility (View.GONE);
}
};
Hope it helps you.
Split it into several tasks and execute each task on main thread separately. I.e.
for (int i = 0; i < 20; ++i) {
runOnUiThread(new Runnable() { .. process 1/20 of your work });
}
You don't need to add a delay. Also you can experiment with granularity, probably better to increase it from 1/20.

How to stop while loop after back button is hit

I have tried so many ways of solving my problem, but still no success.I have a method, which returns me a string value and I am using it to update TextView on my screen like this:
outCPU.setText(getCpuInfo());
Which would be fine, but I need to update this TextView until back button was pressed.
I guess i have need a while loop which starts after activity has been created and stops after back button was pressed. This loop should be in a new thread, because:- I have to load the activity first and execute the loop in another thread so the executing won't affect main thread and loading of the activity.
As I've already said, I don't know how to do this properly even though i have spent few hours on it.
Could someone show me an example how to get this done? Thanks...!!
EDITED - WORKING:
private Handler mHandler;
private int i;
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_systeminfo);
outCPU = (TextView) findViewById(R.id.outCPU);
outMEM = (TextView) findViewById(R.id.outMEM);
outTASKS = (TextView) findViewById(R.id.outTASKS);
i = 0;
mHandler = new Handler();
mHandler.post(mUpdate);
}
private Runnable mUpdate = new Runnable() {
#Override
public void run() {
outCPU.setText(getCpuInfo());
outMEM.setText(getMemInfo());
outTASKS.setText(getTasksInfo());
i++;
mHandler.postDelayed(this, 1000);
}
};
#Override
public void onBackPressed() {
mHandler.removeCallbacks(mUpdate);
super.onBackPressed();
Log.i("MSG", "Going back");
finish();
}
You can use AsyncTask to perform operations on UI Thread while being in a Thread. Or you can use 'my favorite' , the combination of Thread and Handler. To make sure the thread is stopped when back is pressed, you can use handler.removeCallBacks(Runnable) The following example could solve your problem:
//Global
Handler h = new Handler();
private static boolean flag = true;
public void updateTextView(){
// call thread here
h.post(thread);
}
// take this thread out side so that it can be stopped with handler
Thread thread = new Thread(){
public void run(){
while(flag)
outCPU.setText(getCpuInfo());
}
}
public void onBackPressed(){
flag = false;
h.removeCallBacks(thread);
super.onBackPressed();
}
Use a shared flag somewhere in your app:
private volatile boolean wasPressed = false;
In while loop, check this flag:
while (!wasPressed) {
runOnUiThread(new Runnable() {
#Override
public void run() {
outCPU.setText(getCpuInfo());
}
});
// sleep for a while
}
On button click listener, switch wasPressed to true.

Android "Skipped XX frames!"

So I am learning on how to develop android applications.
I am trying to get this program to flash some letters, one at a time fairly quickly
on a textView, but when I try this on my android device and it does not work I get the message "I/Choreographer﹕ Skipped 57 frames! The application may be doing too much work on its main thread."
(AttetionalBlinkTrial is a class that has a field called "blinkList" that is an ArrayList of strings)
public void startTask(View view) throws InterruptedException {
TextView textView = (TextView) findViewById(R.id.display);
AttentionalBlinkTrial theTrial = new AttentionalBlinkTrial();
theTrial.generateTargets();
theTrial.generateBlinkList(5);
for (int i = 0; i <= 5; i++) {
textView.setText(theTrial.getBlinkList().get(i));
Thread.sleep(40);
textView.setText(");
Thread.sleep(40);
}
}
Thread.sleep makes UI thread inaccessible. You should use Handler class instead. Sorry I can't provide any codes since I am on mobile but it's quite easy. If i remember right "postDelayed" method is what you need.
public void blink(TextView textView) {
if (textView.getText() == "Blink!") {
textView.setText("");
} else {
textView.setText("Blink!");
}
}
public void blinkingTask() throws InterruptedException {
final Handler handler = new Handler();
final TextView textView = (TextView) findViewById(R.id.my_text);
Runnable runnable = new Runnable() {
#Override
public void run() {
blink(textView);
}
};
for (int i = 0; i <= 5; i++) {
handler.postDelayed(runnable, 1000 + (i * 1000)); // 5 delayed actions with 1000 ms interval.
}
}
take a look at
Update UI from Thread.
you should do all the operations on seperate thread
AttentionalBlinkTrial theTrial = new AttentionalBlinkTrial();
theTrial.generateTargets();
theTrial.generateBlinkList(5);
and only set text on UI thread.

android - Showing variable changes

Ok - I know there has got to be a simple solution to this but for the life of me I can't figure it out.
Programming a very basic android activity to simply iterate through 0-99. I have a textview that I want to display the count. What happens is that it simply stays blank until the end and then shows the ending count (99).
Not sure if a textview is the right way to display or what the answer is. Any help is greatly appreciated. Thanks in advance
Try using code like this in onCreate (where number is defined as a field):
textView.post(new Runnable() {
#Override
public void run() {
number++;
textView.setText("counting: " + number);
if (number < 100) {
textView.postDelayed(this, 50);
}
}
});
Edit: code was edited as View classes have post and postDelayed, which propagates call to Handler instance they have internally.
You need to read a bit about Handler class.
Warning: this code leaks Activity for the time of approximatelly 5 seconds and should not be used directly in production code. You need to remove Runnable from the message queue at the appropriate time (maybe in onDestroy, but it depends on your needs).
View.removeCallbacks for anti-memory-leak.
My guess is that your onCreate() has code like this:
for (int i=0;i<100;i++) {
tv.setText(String.valueOf(i));
Thread.sleep(100); // or something to delay for a bit
}
That will give you the output that you are describing.
As with many GUI frameworks, Android's UI is event-driven. Calling setText() does not update the screen. Rather, it puts a message on a queue, asking for the screen to be updated. That queue is processed by the main application thread... the same thread that is calling onCreate() in the first place. Hence, what you are doing is queuing up 100 setText() calls, none of which will be processed until your loop is complete. Applying the 100 of them takes very little time, giving the visual result of only seeing the last change.
User a timer scheduled at a fixed rate. Increment a counter every second. Set the text on the UI thread. cancel the timer when required.
public class MainActivity extends Activity {
TextView _tv;
Timer _t;
int _count=0;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
_tv = (TextView) findViewById( R.id.textView1 );
_t = new Timer();
_tv.setText(""+_count);
_t.scheduleAtFixedRate( new TimerTask() {
#Override
public void run() {
_count++;
runOnUiThread(new Runnable() //run on ui thread
{
public void run()
{
_tv.setText(""+_count);
if(_count==99)
{
_t.cancel();
}
}
});
}
}, 1000, 1000 );
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
_t.cancel();
}
}
Use a countdown timer, in below code, onTick() will get called every second, here you can display/update your number each second.
set interval according to your need. Its in mili seconds.
public class TimerActivity extends Activity {
private final long startTime = 100 * 1000;
private final long interval = 1 * 1000;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer);
countDownTimer = new MyCountDownTimer(startTime, interval);
countDownTimer.start();
public class MyCountDownTimer extends CountDownTimer {
public MyCountDownTimer(long startTime, long interval) {
super(startTime, interval);
}
#Override
public void onFinish() {
text.setText("Time's up!");
}
#Override
public void onTick(long millisUntilFinished) {
text.setText(100 - millisUntilFinished/1000);
}
}
}

Categories