This is my code, it should print a random value (between 0 and 1) but it doesn't do that!
I don't know how to fix it! I tried multiple things, none of them are working out!
Here's the code:
package com.example.lode.coder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.TextView;
import java.util.Random;
public class Coder extends AppCompatActivity {
TextView display;
String one;
boolean bl= true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_coder);
display = (TextView) findViewById(R.id.text);
}
void all() {
while (bl) {
Random rand = new Random();
int n = rand.nextInt(2);
one = n + (String) display.getText();
display.setText(one);
}
}
}
You don't show where the all() method is called. If it's not called anywhere, that would explain why display never gets any text set.
But assuming that it is called somewhere, there's still a big problem: the all() method is an infinite loop. Until you return control to the framework, any changes you make to display won't show up on the screen. (In fact, your app will likely then be killed off by the framework when it notices that the app has become unresponsive.)
If you want to change the text continuously, look into using a Handler. You can create a Runnable that does the actual change and then reschedules itself to run again after a short time. Don't use a loop like you currently have in all().
Something like this would work:
public class Coder extends AppCompatActivity {
private static long UPDATE_INTERVAL = 500; // every half second -- adjust as needed
TextView display;
String one;
Handler handler;
Runnable updater;
Random rand = new Random();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_coder);
display = (TextView) findViewById(R.id.text);
Handler handler = new Handler();
updater = new Runnable() {
#Override public void run() {
int n = rand.nextInt(2);
one = n + display.getText().toString();
display.setText(one);
handler.postDelayed(updater, UPDATE_INTERVAL);
}
}
}
#Override protected void onStart() { // or override onResume() instead
super.onStart();
startUpdates();
}
#Override protected void onStop() { // or override onPause() instead
super.onStop();
stopUpdates();
}
void startUpdates() {
handler.post(updater);
}
void stopUpdates() {
handler.removeCallbacks(updater);
}
}
you haven't called all() function anywhere and even if you do, the logic would still be wrong because bl always stays true and so the while loop is an infinite loop which never stops. Try this code:
public class Coder extends AppCompatActivity {
TextView display;
String one;
boolean bl= true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_coder);
display = (TextView) findViewById(R.id.text);
all();
}
void all() {
Random rand = new Random();
int n = rand.nextInt(2);
one = n + display.getText().toString();
display.setText(one);
}
}
if you want the loop you need to set your bl variable to false at some point to stop the loop from going on infinitely.
Related
I want to make an Splash Screen and I want to show some views (which already made them Invisible in XML) and after the last one made Visible via Java code, I want to open another activity, I know I should make handler and runnables to do so, but I don't know exactly how to do it!
can someone please show me how in code? this is what I've done so far.
public class SplashActivity extends AppCompatActivity {
private static final int SPLASH_TIME_OUT = 3600;
private static final int VIEW_COUNT = 4;
private TextView welcome_tv1, welcome_tv2, welcome_tv3;
private ImageView logo;
private Typeface typeface;
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_splash);
init();
setAnimations();
handler.postDelayed(new Runnable() {
#Override
public void run() {
startActivity(new Intent(SplashActivity.this, MainActivity.class));
finish();
}
}, SPLASH_TIME_OUT);
}
private void setAnimations() {
YoYo.with(Techniques.FadeInDown)
.duration(2500)
.repeat(0)
.playOn(logo);
logo.setVisibility(View.VISIBLE);
YoYo.with(Techniques.FadeInDown)
.repeat(0)
.delay(400)
.duration(1000)
.playOn(welcome_tv1);
welcome_tv1.setVisibility(View.VISIBLE);
YoYo.with(Techniques.FadeInDown)
.repeat(0)
.delay(1400)
.duration(1000)
.playOn(welcome_tv2);
welcome_tv2.setVisibility(View.VISIBLE);
YoYo.with(Techniques.FadeInDown)
.repeat(0)
.delay(2800)
.duration(800)
.playOn(welcome_tv3);
welcome_tv3.setVisibility(View.VISIBLE);
}
private void init() {
welcome_tv1 = findViewById(R.id.welcome_tv_one);
welcome_tv2 = findViewById(R.id.welcome_tv_two);
welcome_tv3 = findViewById(R.id.welcome_tv_three);
typeface = Typeface.createFromAsset(getApplicationContext().getAssets(),
"Fonts/myFont.ttf");
logo = findViewById(R.id.logo);
setTextViews();
}
private void setTextViews() {
welcome_tv1.setText(getResources().getString(R.string.welcome_tv_txt));
welcome_tv2.setText(getResources().getString(R.string.welcome_tv2_txt));
welcome_tv3.setText(getResources().getString(R.string.welcome_tv3_txt));
welcome_tv1.setTypeface(typeface);
welcome_tv2.setTypeface(typeface);
welcome_tv3.setTypeface(typeface);
}
If you want to create welcome screens that will only run for the first time the user starts the application you can use the SharedPreferences to check if it is the first time, display your welcome views slider and after the last one open your activity.
You can see the whole implementation here
Hope it helps
I wanted to create countdown as soon as the user sees an activity. However, there does not seem to be an appropriate callback for that. Neither onResume nor onWindowFocusChanged seem to be the correct callbacks, because the whole code is executed before the user even see anything. As a result I end up with "Go!" on the screen right from the start.
In a nutshell:
Do you have any idea how to implement a countdown without any user interaction as soon as the activity is visible to the user?
EDIT:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import java.util.concurrent.TimeUnit;
import android.widget.TextView;
public class ChallengeModeTutorial extends AppCompatActivity {
private void delayOneSec()
{
try
{
TimeUnit.SECONDS.sleep(2);
}
catch (InterruptedException e)
{
assert true;
}
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_challenge_mode_tutorial);
}
#Override
public void onWindowFocusChanged(boolean hasFocus)
{
super.onWindowFocusChanged(hasFocus);
TextView readySteadyGo = (TextView) findViewById(R.id.challengeModeTutorialReadySteadyGoTextView);
// TextView tutorialText = (TextView) findViewById(R.id.challengeModeTutorialTextTextView);
TextView timeUntilStart = (TextView) findViewById(R.id.challengeModeTutorialReadyTimeTextView);
readySteadyGo.setText("");
timeUntilStart.setText("5");
delayOneSec();
timeUntilStart.setText("4");
delayOneSec();
timeUntilStart.setText("3");
delayOneSec();
readySteadyGo.setText("Ready!");
timeUntilStart.setText("2");
delayOneSec();
readySteadyGo.setText("Steady!");
timeUntilStart.setText("1");
delayOneSec();
readySteadyGo.setText("");
readySteadyGo.setText("Go!");
}
}
The problem is that you're blocking the UI thread. When you call setText(String) it doesn't immediately gets drawn. The TextView gets invalidated and it will be draw on the next draw phase. But if you block the thread, this will never happen. You have to use a postDelayed() to execute the next setText(String) a second later.
I'm not sure if this works, but you could try using a ViewTreeObserver in onCreate. It gets called once the layout is drawn. (Replace LinearLayout with whatever Layout your "activity_challenge_mode_tutorial" actually is.)
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_challenge_mode_tutorial);
final LinearLayout layout = (LinearLayout) findViewById(R.id.YOUR_VIEW_ID);
ViewTreeObserver vto = layout.getViewTreeObserver();
vto.addOnGlobalLayoutListener (new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// Remove listener to prevent repeat calls.
layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// Start countdown here.
}
});
}
Code is taken from this answer: https://stackoverflow.com/a/7735122/8118328
You can start your countdown, inside of your onStart method, which you need to overwrite.
The visible lifetime of an activity happens between a call to onStart() until a corresponding call to onStop(). During this time the user can see the activity on-screen, though it may not be in the foreground and interacting with the user.
From:
https://developer.android.com/reference/android/app/Activity
#Override
protected void onStart() {
super.onStart();
}
I finally got it to work like this:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class ChallengeModeTutorial extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_challenge_mode_tutorial);
}
#Override
protected void onStart()
{
super.onStart();
final TextView readySteadyGo = (TextView) findViewById(R.id.challengeModeTutorialReadySteadyGoTextView);
final TextView timeUntilStart = (TextView) findViewById(R.id.challengeModeTutorialReadyTimeTextView);
readySteadyGo.setText("");
Thread t=new Thread(){
#Override
public void run(){
while(continueThread){
try {
Thread.sleep(1000);
runOnUiThread(new Runnable() {
#Override
public void run() {
if(currentCount > 0)
{
timeUntilStart.setText(String.valueOf(currentCount));
}
else
{
timeUntilStart.setText("Go!");
}
switch (currentCount)
{
case 2: readySteadyGo.setText("Ready!"); break;
case 1: readySteadyGo.setText("Steady!"); break;
default: readySteadyGo.setText(""); break;
}
currentCount--;
if (currentCount == 0)
{
continueThread = false;
}
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t.start();
}
private boolean continueThread = true;
private int currentCount = 5;
}
I am designing a small application which changes a TextView every second with a random letter.
For now, my code looks like this and works very well :
#BindView(R.id.textview_letter) TextView letterTV;
private static final int DELAY_MILLIS = 1000;
private static final int LOOP_MAX = 10;
private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private Handler h = new Handler();
private Random random = new Random();
private int position = 0;
private Runnable run = new Runnable() {
#Override
public void run() {
if (position >= LOOP_MAX) {
letterTV.setText("THE END !");
h.removeCallbacks(run);
} else {
String randomLetter = String.valueOf(ALPHABET.charAt(random.nextInt(ALPHABET.length())));
letterTV.setText(randomLetter);
h.postDelayed(run, DELAY_MILLIS);
position++;
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mylayout);
ButterKnife.bind(this);
h.post(run);
}
I now want to improve it by setting the background of my TextView to black (or make it invisible) for few ms between each letter, so the user is notified in case there is twice the same letter in a row.
My only noob thought was to put another Runnable in my Runnable and handle them with split delay (like 700 and 300 ms for instance), but this seems hugely overcomplicated.
What is the right way to do this ?
(and BTW, is the Runnable/Handler really the most adapted pattern for me to use ?)
EDIT : In a non-UI thread I could do domething like this :
while (randomLetter.next()) {
letterTV.setText(randomLetter);
Thread.sleep(700);
letterTV.setBackgroundColor(Color.BLACK);
Thread.sleep(300);
}
Use RxAndroid, it will reduce the complexity:
public class Test extends AppCompatActivity {
private Disposable randomLetterObservable;
private TextView textView;
private Random random = new Random();
private final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
randomLetterObservable = Observable.interval(500L, TimeUnit.MILLISECONDS)
.timeInterval()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Timed<Long>>() {
#Override
public void accept(Timed<Long> longTimed) throws Exception {
String randomLetter = String.valueOf(ALPHABET.charAt(random.nextInt(ALPHABET.length())));
textView.setText(randomLetter);
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
if (randomLetterObservable != null) {
randomLetterObservable.dispose();
}
}
}
with dependencies:
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'io.reactivex.rxjava2:rxjava:2.1.8'
Edit: Here is a modified solution that also changes the background if the same letter occurs twice in a row.
public class Test extends AppCompatActivity {
private Disposable randomLetterObservable;
private TextView textView;
private Random random = new Random();
private final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private String lastLetter;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
randomLetterObservable = Observable.interval(700L, TimeUnit.MILLISECONDS)
.timeInterval()
.observeOn(AndroidSchedulers.mainThread())
.switchMap(new Function<Timed<Long>, ObservableSource<String>>() {
#Override
public ObservableSource<String> apply(Timed<Long> longTimed) throws Exception {
String randomLetter = String.valueOf(ALPHABET.charAt(random.nextInt(ALPHABET.length())));
if (randomLetter.equals(lastLetter)) {
textView.setBackgroundColor(Color.BLACK);
return Observable.just(randomLetter)
.observeOn(Schedulers.computation())
.debounce(300L, TimeUnit.MILLISECONDS);
} else {
lastLetter = randomLetter;
return Observable.just(randomLetter);
}
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
#Override
public void accept(String s) throws Exception {
textView.setText(s);
textView.setBackgroundColor(Color.TRANSPARENT);
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
if (randomLetterObservable != null) {
randomLetterObservable.dispose();
}
}
}
Events are emitted in a background thread, background color and letters are set on the main thread. I think this is pretty much what you asked for. (You might need to play with the values to get the desired effect).
Good luck.
My textview should change the value according to the variable predict, but it remains at zero and does not change the value. Is there any solution to it?
Part of my code is: (textView1 is my id of TextView in xml)
public class face extends Activity implements CvCameraViewListener2 {
public int predict;
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
predict = model.predict(resizer);
}
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "called onCreate");
super.onCreate(savedInstanceState);
TextView txt=(TextView)findViewById(R.id.textView1);
txt.setText(Integer.toString(predict));
}
}
My textview should change the value according to the variable predict.but it remains at zero and does not change the value
I am guessing from this that you change the int variable(predict) alot, so whenever you change the variable then you call your TextView.setText(yourString);.. Oncreate runs only when your activity is initiating or being created.
While the variable changes dynamically, the text view should be set dynamically. So, move that from onCreate(), which will be calling only once when Activity creates.
public class face extends Activity implements CvCameraViewListener2 {
public int predict = 0;
TextView txt;
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
// confirm that model and resizer are as expected and not null.
predict = model.predict(resizer);
if (txt != null)
txt.setText(""+predict);
//returns an object of Mat
}
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "called onCreate");
super.onCreate(savedInstanceState);
// hope you called setContentView(yourLayout);
txt=(TextView)findViewById(R.id.textView1);
if (txt != null)
txt.setText(""+predict);
}
}
onCameraFrame is not running on the UI thread so it cannot change views created on the UI thread (such as your textview). Simply put something like this inside onCameraFrame:
if (condition) {
runOnUiThread(new Runnable() {
#Override
public void run() {
txt.setText("whatever");
}
});
}
Note that TextView txt = findTextView txt=(TextView)findViewById(R.id.textView1); must be done outside onCameraFrame
You should update the text of the TextView every time predict is changing.
private void updateTextView() {
txt.setText(Integer.toString(predict));
}
Call this method after assigning a new value to predict:
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame)
{
predict = model.predict(resizer);
updateTextView();
}
So I made an AsyncTask class that runs doInBackground() successfully. I have debugged it, and the entire doInBackground() method runs correctly:
public class MyClass extends AsyncTask<String , String , Boolean> {
protected Boolean doInBackground(String... strings)
{
ArrayList<String[]> stories = new ArrayList<String[]>();
...*irrelevant code that works*...
String[][] storiesA = new String[stories.size()][2];
...*irrelevant code that works*...
ArrayList<Integer> displayed = new ArrayList<Integer>();
//calls publishProgress() every 10 seconds with a random String[2] from storiesA
for (int x = 0 ; x < storiesA.length ; x++)
{
if (displayed.size() >= storiesA.length) displayed.clear();
Random gen = new Random();
int rand;
rand = gen.nextInt(storiesA.length);
while (displayed.contains(rand))
{
rand = gen.nextInt(storiesA.length);
}
displayed.add(rand);
publishProgress(storiesA[rand][0] , storiesA[rand][1]);
long t0 , t1;
t0=System.currentTimeMillis();
do
{
t1=System.currentTimeMillis();
} while (t1-t0<10000);
}
return true;
}
}
As you can see, I made it so the onProgressUpdate() parameter should be String..., as in the method in my UI:
protected void onProgressUpdate(String... stories) {
TextView title = (TextView)findViewById(R.id.bulletinBoardTitle);
TextView body = (TextView)findViewById(R.id.bulletinBoardText);
String titleText = stories[0];
String bodyText = stories[1];
title.setText(titleText);
body.setText(bodyText);
}
In case it's relevant, I also defined:
protected void onPostExecute(Boolean result) {
//will never call this method; it is deprecated in this context
TextView title = (TextView)findViewById(R.id.bulletinBoardTitle);
TextView body = (TextView)findViewById(R.id.bulletinBoardText);
title.setText("Refreshing...");
body.setText("Murica!");
}
So the problem is apparent with all the debuggers I've run. While the entire doInBackground() code (executed here:)
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.media);
new MyClass().execute();
}
works well and runs fully, when it calls publishProcess() the onProgressUpdate() method never gets run.
I'm a very novice Android programmer, so please keep that in mind if you have any idea what might be the problem here.
Thanks for the help!