Updating each second in Android - java

I am making an app that counts up every second based on rate of pay, and as it is written now, it crashes on startup.
Am I doing the thread section wrong?
I am kind of new to android, so I am a bit unclear on the onCreate method in general. Any clarification about that and how it relates to my code would be helpful as well.
The button is supposed to start the count. I think it's crashing due to the t.start() line, but I don't know how to trigger the event.
package com.example.terik.myapplication;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView text2;
text2 = (TextView) findViewById(R.id.textView2);
Thread t = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
updateTextView();
}
});
}
} catch (InterruptedException e) {
}
}
};
t.start();
}
private void updateTextView() {
TextView text2;
double update;
double rateofPay = 9.00;
text2 = (TextView)findViewById(R.id.textView2);
CharSequence newtime = text2.getText();
int number = Integer.parseInt(newtime.toString());
update = number+ rateofPay;
text2.setText((int) update);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}

One problem was a NumberFormatException when trying to parse a Double as an Integer.
The other problem was trying to call setText() with an int on this line:
text2.setText((int) update);
This fixed it:
private void updateTextView() {
TextView text2;
double update;
double rateofPay = 9.00;
text2 = (TextView)findViewById(R.id.textView2);
CharSequence newtime = text2.getText();
double number = Double.parseDouble(newtime.toString());
update = number+ rateofPay;
text2.setText(String.valueOf(update));
}
Edit:
Here's how you would only start the Thread when you click the Button. First make the Thread t an instance variable, so that it can be accessed in the button click run() method (you might want to re-name that method too!).
I just tested this, it worked for me:
public class MainActivity extends ActionBarActivity {
Thread t;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView text2;
text2 = (TextView) findViewById(R.id.textView2);
t = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
updateTextView();
}
});
}
} catch (InterruptedException e) {
}
}
};
}
public void run(View v) {
t.start();
}
private void updateTextView() {
TextView text2;
double update;
double rateofPay = 9.00;
text2 = (TextView)findViewById(R.id.textView2);
CharSequence newtime = text2.getText();
double number = Double.parseDouble(newtime.toString());
update = number+ rateofPay;
text2.setText(String.valueOf(update));
}
//.........
Edit 2:
As #BladeCoder mentioned in the comments, a Thread is really over-kill for this. Using a Handler and postDelayed() is really the best route for something like this.
Also, it would be better to make the TextView an instance variable so that you don't create a new reference every time you update it.
I tested this version as well:
public class MainActivity extends ActionBarActivity {
TextView text2;
Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text2 = (TextView) findViewById(R.id.textView2);
handler = new Handler();
}
Runnable updateText = new Runnable(){
#Override
public void run(){
updateTextView();
handler.postDelayed(this, 1000);
}
};
public void run(View v) {
handler.postDelayed(updateText, 1000);
}
private void updateTextView() {
double update;
double rateofPay = 9.00;
CharSequence newtime = text2.getText();
double number = Double.parseDouble(newtime.toString());
update = number+ rateofPay;
text2.setText(String.valueOf(update));
}
//.............

Instead of using thread to achieve this, you can achieve the same effect with a "neat way" using the Timer class.
Check this stackoverflow answer Android timer? How-to?
Regarding the onCreate method I suggest you to check the activity life cycle
Called when the activity is first created. This is where you should do all of your normal static set up: create views, bind data to lists, etc. This method also provides you with a Bundle containing the activity's previously frozen state, if there was one.
Always followed by onStart().
Check the documentation for further info http://developer.android.com/reference/android/app/Activity.html#onCreate(android.os.Bundle)

Related

Android: Show always a ProgressBar inside AsynckTask with runOnUIThread

There are an application that process many operations in an AsyncTask that has a runOnUIThread call.
The application has the code to show an indeterminate ProgressBar when the process it's doing in background, but the progress bar isn't shown always, in one cases yes, in other cases no.
With this model of (bad structure) code, how can I sure that the progress bar always is shown
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.TextView;
public class AsyncTestActivity extends ActionBarActivity {
private ProgressDialog pd = null;
private void loadingBar(String titulo){
pd = ProgressDialog.show(this, titulo, "Please wait ...", true, false);
}
private void closeLoading(){
pd.dismiss();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_test);
TextView textView = (TextView) findViewById(R.id.textView);
Task async = new Task(textView);
async.execute("");
}
private class Task extends AsyncTask<String, Void, String> {
private TextView tv;
public Task(TextView tv) {
this.tv = tv;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
loadingBar("Warning");//I want to show this always
}
#Override
protected String doInBackground(String... params) {
runOnUiThread(new Runnable() {
#Override
public void run() {
try {
for(int i = 0; i <= 10; i++) {
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
return "End";
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
tv.setText(result);
closeLoading();
}
}
}
I, can't change the structure (AsyncTask/runOnUIThread)the code because is big and I have few time to do this. The goal is that the progress bar always is ahowed. I had been reading that this is a bad practice, but the code was made by another person.
Did you ever try to call bringToFront() inside your onPreExecute():
#Override
protected void onPreExecute() {
super.onPreExecute();
loadingBar.bringToFront();
loadingBar("Warning");//I want to show this always
}
(Untested code)
or if you want to make sure, you can include your progressBar as your Task parameter then directly execute bringToFront();
public Task(TextView tv, ProgressBar pB) {
this.tv = tv;
this.pb = pB.bringToFront();
}
hope it helps
Call loadingBar("Warning"); before async.execute("");.
If it's not showing, there is a problem with your ProgressDialog. Can you try edit loadingBar() method like this? :
ProgressDialog pd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_async_test);
//init progress
pd = new ProgressDialog(this);
//
TextView textView = (TextView) findViewById(R.id.textView);
Task async = new Task(textView);
async.execute("");
}
private void loadingBar(String titulo){
pd.show();
pd.setTitle(titulo);
}

How to get ProgressBar to show while OnClickListener is running?

I have a simple Android program that calculates how long it takes the phone to compute a certain mathematical problem. I want the mathematical problem to start when I hit the button, and while it is running I want a spinning progress bar to be displayed, and I want it to disappear after the math problem is done. This is the code I currently have:
public class main extends AppCompatActivity {
private TextView mScore;
private Button mRunButton;
private TextView mScoreText;
private ProgressBar mSpinner;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mScore = (TextView) findViewById(R.id.score);
mRunButton = (Button) findViewById(R.id.runbutton);
mScoreText = (TextView) findViewById(R.id.scoreText);
mSpinner = (ProgressBar) findViewById(R.id.progress);
mSpinner.setVisibility(View.GONE);
View.OnClickListener listener = new View.OnClickListener(){
#Override
public void onClick(View v) {
mSpinner.setVisibility(View.VISIBLE);
long startTime = System.nanoTime();
long start = System.currentTimeMillis();
long count = 0l;
for(long x=0;x<Integer.MAX_VALUE ;x++){
count+=1;
}
long end = System.currentTimeMillis();
long endTime = System.nanoTime();
long duration = ((endTime - startTime) / 1000000);
mScore.setText(duration + "");
mSpinner.setVisibility(View.GONE);
}
};
mRunButton.setOnClickListener(listener);
}
}
From what I can tell, nothing in the view of the app updates until after the phone is done with the entire onClick method, which is not what I want it to do. I want the progress bar to be displayed ONLY while the program is 'working'. How would I go about doing this?
Thank you
As Blackbelt and vilpe89 mentioned, you have to separate the threads. You can do this by having another class that extends ASyncTask which will handle the calculations. The problem with that is that the progress dialog needs to run on the UI thread. You can have an interface that changes the progress dialog in the main class.
Calculator class:
public final class Calculator extends AsyncTask<Void, Void, Void> {
Context context;
calcCallback mCallback;
public Calculator(Context c) {
this.context = c;
this.mCallback = (calcCallback) c;
}
//The main class needs to implement this interface
public interface calcCallback {
Void calcDone();
Void calcStarted();
//Other methods if necessary
}
#Override
protected Boolean doInBackground(Void... params) {
mCallback.calcStarted();
//Your calculations here
mCallback.calcDone();
return null;
}
}
MainActivity
public class MainActivity extends Activity implements Calculator.calcCallback, {
private TextView mScore;
private Button mRunButton;
private TextView mScoreText;
private ProgressBar mSpinner;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mScore = (TextView) findViewById(R.id.score);
mRunButton = (Button) findViewById(R.id.runbutton);
mScoreText = (TextView) findViewById(R.id.scoreText);
mSpinner = (ProgressBar) findViewById(R.id.progress);
mSpinner.setVisibility(View.GONE);
View.OnClickListener listener = new View.OnClickListener(){
#Override
public void onClick(View v) {
Calculator calculator = new Calculator(MainActivity.this);
calculator.execute();
}
};
mRunButton.setOnClickListener(listener);
}
#Override
public Void calcStarted() {
runOnUiThread(new Runnable() {
#Override
public void run() {
mSpinner.setVisibility(View.VISIBLE);
}
});
}
return null;
}
#Override
public Void calcDone() {
runOnUiThread(new Runnable() {
#Override
public void run() {
mSpinner.setVisibility(View.GONE);
}
});
}
return null;
}
}
You can also set up your calcDone() as calcDone(int duration) so that you can pass the calculated duration back to the main thread.

setcontent view in thread

I want to make a thread which will change the layout of my activity ... I have 2 layouts : welcomepage and activity_main ...
The goal of thread: when I launch my application , the welcomepage layout will be visible in only 5 sec and after that the layout again will be activity_main ...
I wrote the code as below:
package com.example.tripolimazad;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
public class MainActivity extends Activity {
public TextView counter = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.welcomepage);
counter = (TextView) findViewById(R.id.Counter);
Thread th=new Thread(){
#Override
public void run(){
try
{
Thread.sleep(10000);
setContentView(R.layout.activity_main);
}catch (InterruptedException e) {
}
}
};
th.start();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
but it doesnt work !!! have anyone any solution plz !
You cannot change the UI on a non-UI thread, however in an Activity, you can use the runOnUiThread method:
runOnUiThread(new Runnable() {
#Override
public void run() {
setContentView(R.layout.activity_main);
}
});
This seems very strange though, to have this in your onCreate.
You may also try to use CountDownTimer something like:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.welcomepage);
//display the logo during 5 secondes,
new CountDownTimer(5000,1000){
#Override
public void onTick(long millisUntilFinished){}
#Override
public void onFinish(){
//set the new Content of your activity
MainActivity.this.setContentView(R.layout.main);
}
}.start();
//...
}
See Displaying logo for few seconds at application start for more.
Alternatively you can use a handler to avoid creating a new thread as following:
getWindow().getDecorView().getHandler().postDelayed(new Runnable() {
#Override public void run() {
setContentView(R.layout.activity_main);
}
}, 10000);
UI related operations must be done on UI thread only and must not be done in non-UI thread as you are doing. But you can update UI from non-UI thread as follows:
activityContext.runOnUiThread(new Runnable() {
#Override
public void run() {
setContentView(R.layout.activity_main);
}
});
However a better approach for the situation you mentioned is to use an Async task, provided by the Android.You can try following :
/*
* Activity/Thread to display the **welcomepage**
* when the app is started.
*/
public class SplashActivity extends Activity {
// how long until we go to the next activity
protected int _splashTime = 5000; // 5 seconds
// thread to display welcome page
private Thread splashTread;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_welcome_page_layout);
// thread for displaying the WelcomeScreen
splashTread = new Thread() {
#Override
public void run() {
try {
synchronized (this) {
// wait 5 sec
wait(_splashTime);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// finish the current splashactivity
finish();
// start MainActivity as next activity
startActivity(new Intent(SplashActivity.this, MainActivity.class));
}
}
};
// start the thread.
splashTread.start();
}
}

Issue with displaying TextView in real-time using asyncTask

I am learning how to use asyncTask and I have issue with trying to display the TextView in real-time. The mainActivity have few buttons that will start new activity plus a TextView that show the value that changes for every 200 milliseconds. But the issue is that the TextView doesn't show up until I click on button to start another activity, and the value doesn't changes when I pressed "back button" to return to mainActivity. However, it does changes the value when I press button to start another activity.
private TextView t;
private int counter;
private boolean isUiVisible = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
t = (TextView) findViewById(R.id.counter);
counter = 0;
}
#Override
public void onStart(){
super.onStart();
isUiVisible = true;
new UpdateUi().execute();
}
#Override
public void onPause(){
super.onPause();
isUiVisible = false;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private class UpdateUi extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
while (true) {
if (isUiVisible) {
counter++;
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
// Ensure the asynkTask ends when the activity ends
break;
}
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
t.setText(counter + "");
}
}
public void callRed(View view){
Intent intent = new Intent(this, RedActivity.class);
startActivity(intent);
}
public void callYellow(View view){
Intent intent = new Intent(this, YellowActivity.class);
startActivity(intent);
}
I have tried setText in onProgressUpdate, but it showed nothing. I also searched to see if other have issues, but it seems that they do have same issue as mine (one was onClickListener, which was not what I was looking for).
The TextView doesn't show up probably because it has no text inside it...cannot tell for sure without looking at the layout.xml file.
You got that behaviour because the variable isUiVisible becomes false only when onPause() is called, that is when you switch activity. At that point the AsyncTask exits his doInBackground method and executes onPostExecute which puts some text in the TextView making it appears.
To try to fix your code you should call publihProgress() inside doInBackground and then use onProgressUpdate to update your TextView in the UIThread.

Android/Java Repeat Button Click

I am writing my first android application, and am trying to write an app where you simply click a button to display a message, and can do so as many times as you want. So far I have:
public class MyProject extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final TextView tv = new TextView(this);
Button startButton = (Button) findViewById(R.id.startbutton);
startButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
tv.setText("Hello World!");
setContentView(tv);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {setContentView(R.layout.main);}}, 2000);
}
});
}
}
However doing it this way, when I get back to my main screen and click on the button again...nothing happens. How can I get repeated button clicks to repeat the behaviour?
Your example is very simple and, from what I understand, no multithreading is needed.
You just have to initialize your layout one time, after that you can update the content of the single views.
So... this will set "hello world" string on every button click, you will not notice any difference because the string is always the same :D
public class MyProject extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// this is needed one time only
setContentView(R.layout.main);
// add your textview in xml
final TextView tv = (TextView) findViewById(R.id.textView);
final Button startButton = (Button) findViewById(R.id.startbutton);
startButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
tv.setText("Hello World!");
}
}
}
}
To do something more fun you can set a counter to update on every click, this way the textview change will be noticeable are more fun!!
int i = 0;
startButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
tv.setText("you have reached " + i);
i++;
}
}
Here, you are calling setContentView to replace the entire current view with a TextView containing "Hello World!" Then after two seconds you setContentView again to set it back to the main layout. Since OnCreate is only called once when the activity is created, the OnClickListener is never set again.
This code will do what you are looking for.
public class MyActivity extends Activity
implements View.OnClickListener{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
}
private void init() {
setContentView(R.layout.main);
Button startButton = (Button) findViewById(R.id.startbutton);
startButton.setOnClickListener(this);
}
#Override
public void onClick(View v) {
TextView tv = new TextView(this);
tv.setText("Hello World!");
setContentView(tv);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
init();
}
}, 2000);
}
}
You may notice that OnClick is a separate method in my example. This is because I implemented the interface View.OnClickListener. I was able to write the implemented method as part of my class and then pass this as an argument to setOnClickListener. I'm explaining this because you mentioned you are new to Java.
TextView txt;
// our handler
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
//display each item in a single line
txt.setText(txt.getText()+"Item "+System.getProperty("line.separator"));
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txt=(TextView)findViewById(R.id.txt);
}
#Override
protected void onStart() {
super.onStart();
// create a new thread
Thread background=new Thread(new Runnable() {
#Override
public void run() {
for(int i=0;i<10;i++)
{
try {
Thread.sleep(1000);
b.putString("My Key", "My Value: "+String.valueOf(i));
// send message to the handler with the current message handler
handler.sendMessage(handler.obtainMessage());
} catch (Exception e) {
Log.v("Error", e.toString());
}
}
}
});
background.start();
}
}
Note:Handler one type of thread not udpate any UI here
Take an example from here

Categories

Resources