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);
Related
I want to make a text view that will update the text after 12 seconds randomly from an array list, automatically.
My code is not working well, it just changes the text one time but I want it to change it every 12 sec.
Here is is the onCreate method of my fragment:
#SuppressLint("SetTextI18n")
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_dashboard, container, false);
TextView topStatus_tv = root.findViewById(R.id.TopStatus);
String[] topStatus = {
"Hello ", //0
"Welcome to your PERSONAL DICTIONARY",//1
"Hi Whats up beauty?",//2
"Good Evening, sir",//3
"how is the Weather",//4
"Get Motivated, go on",//5
"By upgrading your second language, open your mind and be more clever",//6
"Practice everyday!",//7
"Make good habits",//8
"Your HABITS will make a good person from you,\nnot just your Believes",//9
"Knock knock! who is it?\nits the programmer needs your donation",//10
"First make a good Believe, then make good habits\n(Good does not mean perfect)",//11
"Decrease blaming, increase accepting",//12
"You know? sometimes im tired from everything. ",//13
"Music is strange, isn't it?",//14
"you wanna see someone weird? goto setting, press donate button and choose 1000$.\nthen go look at the mirror",//15
"Spotify, IM COMING FOR YOU!!!",//16
"Don't work too much.\ngo hangout with your friends, their idiots",//17
"you know? In parallel worlds you are coding and I am using your app",//18
"When you are in a good mood, the world has to give you what you want",//19
"make a wall from others goodness.\nwhen they make a mistake, take one brick from wall, don't break it."//20
};
Handler handler = new Handler();
for (int i = 0; i < 100; i++) {
handler.postDelayed(new Runnable() {
#Override
public void run() {
int random = new Random().nextInt(20);
topStatus_tv.setText(topStatus[random]);
}
}, 12000);
}
return root;
}
Assign your Runnable to a variable. Then use the variable in postDelayed. At the end of your run() function call postDelayed with the Runnable-variable again with 12 seconds.
Remove your for loop and use a counter variable to limit the number of repetitions.
Something like this (without the counter):
class YourActivity {
// ...
private Handler handler = new Handler();
private Runnable runnable;
public View onCreateView() {
// ...
runnable = new Runnable() {
#Override
public void run() {
int random = new Random().nextInt(20);
topStatus_tv.setText(topStatus[random]);
handler.postDelayed(runnable, 12000);
}
};
handler.postDelayed(runnable, 12000);
// ...
}
}
You can give id to the textView and use onClickListener in your java code and setTime
Working on an Android application, and I need a TableLayout to update on a regular basis without clogging the UI thread. Here is the TableLayout:
<TableLayout
android:id="#+id/pidata"
android:layout_width="wrap_content"
android:layout_height="match_parent">
</TableLayout>
Here is the gist of the code that needs to run, and update the TableLayout with new data every couple of seconds.
public static TableLayout piTableLayout;
public static HashSet<PIModel> PiData;
piTableLayout = (TableLayout)findViewById(R.id.pidata);
while (isRunning) {
PiData = getPiData();
piTableLayout.removeAllViews();
for (PIModel model : PiData) {
TableRow row = new TableRow(this);
TableRow.LayoutParams rowParams = new TableRow.LayoutParams();
rowParams.setMargins(0, -4, 0, -4);
rowParams.height = 40;
TextView pointNameText = new TextView(this);
pointNameText.setText(model.getAttributeName());
pointNameText.setGravity(Gravity.LEFT);
pointNameText.setLayoutParams(rowParams);
pointNameText.setTextColor(Color.parseColor("white"));
pointNameText.setTypeface(null, Typeface.BOLD);
pointNameText.setPadding(0, 0, 10, 0);
TextView valueText = new TextView(this);
valueText.setText(model.getValue());
valueText.setLayoutParams(rowParams);
valueText.setTextColor(Color.parseColor("white"));
valueText.setPadding(0, 0, 10, 0);
piTableLayout.addView(row);
row.addView(pointNameText);
row.addView(valueText);
}
try {
Thread.sleep(3000);
}
catch (InterruptedException ex) {
}
}
Previous Code
Handler piHandler = new Handler();
Runnable piRunnable = new Runnable() {
#Override
public void run() {
while (isRunning) {
piHandler.post(new Runnable() {
#Override
public void run() {
//logic to add to TableLayout
}
});
try {
Thread.sleep(3000);
}
catch (InterruptedException ex) {
}
}
}
};
new Thread(piRunnable).start();
You can't call Thread.sleep on the UI Thread, cause it will block all updates of the screen while the method doesn't finish, you must either use one of the following solutions:
Use android.os.Handler with repeting messages (handleMessage) that will run on UI Thread but will wait on background for new messages to arrive; (Simply solution)
Use a Thread by yourself and post messages to a Handler to go back to UI Thread; (Best solution)
Use a CountdownTimer (that does need an fixed ammount of time to start and reachs 0, stoping the proccess);
Use AsyncTask with an while(true) loop and use publishProgress from doInBackground and handle the state change at onProgressUpdated to touch the UI (Not recomended, cause AsyncTasks must have short lifes);
Use a Service to do the same as the AsyncTask and send Broadcasts to the Activity; (Complex solution)
I searched a lot and tried it with handler but nothing worked..
I want an activity with a text view (remove text in on create) and if its visible I want to set text to this view and after some times again and again and again..
Do I really need an interaction from user like button to start this??
You can easily achieve this using a Handler that runs a Runnable that calls itself again after some time.
So, you can declare a Handler and a Runnable like so
private Handler mHandler = new Handler();
private Runnable mRunnable = new Runnable() {
#Override
public void run() {
mTextView.setText("wtv");
mHandler.postDelayed(this, 1000);
}
};
So, onCreate you clear the textview and start the runnable
mTextView.setText("");
mHandler.postDelayed(mRunnable, 1000);
Something like that:
static int i = 0;
final int MAX_COUNT = 10;
final int TIME_DELAY = 5000;
final TextView textView = %yours text view%;
final Runnable changeTextViewState = new Runnable() {
#Override
public void run() {
textView.setText("it" + i++);
if (i < MAX_COUNT) {
textView.postDelayed(this, TIME_DELAY);
}
}
};
textView.postDelayed(changeTextViewState, TIME_DELAY);
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);
}
}
}
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.