I'd like to show a series of 10 questions and have the user answer, and have the app show whether the answer is correct, and then show the next question.
Right now I can show the first question, check whether it's correct, and then display the second question. I don't know how to get this looping, however, to show all questions. Here is the relevant code:
public class MathTestActivity extends AppCompatActivity {
int i = 0;
int n = 20; /*How many rows this test*/
String[] mathTest = new String[40];
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mathtest);
final TextView mathProblem = (TextView) findViewById(R.id.mathProblem);
final EditText mathAnswer = (EditText) findViewById(R.id.mathAnswer);
//Styling for the question text
mathProblem.setTextSize(40);
mathProblem.setTextColor(Color.rgb(0, 0, 0));
//Try to read the problem and answers text file
try {
InputStream is = this.getResources().openRawResource(R.raw.mediummath);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
int n = 20; /*How many rows this test has*/
/*read in file to array*/
for (i = 0; i < n; i=i+2) {
if ((line = reader.readLine()) != null)
mathTest[i] = line;
if ((line = reader.readLine()) != null)
mathTest[i+1] = line;
}
} catch (IOException e) {
e.printStackTrace();
}
mathProblem.setText(mathTest[0]);
Button enterButton = (Button) findViewById(R.id.enterButton);
enterButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int correctcount = 0;
i = 0;
String answer = mathAnswer.toString() ;
String correctAnswer = mathTest[i+1];
if (answer.equals(correctAnswer)){
Toast.makeText(MathTestActivity.this,
R.string.correct_toast,
Toast.LENGTH_SHORT).show();
correctcount++;
i = i + 2;
mathProblem.setText(mathTest[i]);
correctAnswer = mathTest[i+1];
}
else{
Toast.makeText(MathTestActivity.this,
correctAnswer,
Toast.LENGTH_SHORT).show();
i = i + 2;
mathProblem.setText(mathTest[i]);
correctAnswer = mathTest[i+1];
}
}
});
}
}
You can't count the correct answers with a local variable that gets set to 0 each time you click the button. :)
You should move int correctcount = 0; outside of the listener and next to your i and n variables.
You will also want to remove the i = 0; line from inside the button click because that will reset you back to the first question every time you click the button.
Also, since these three lines are duplicated between the if and the else, you can just place them directly after the else.
i = i + 2;
mathProblem.setText(mathTest[i]);
correctAnswer = mathTest[i+1]; // this isn't needed, though
You can try putting your questions in ViewPager if you want to make the questions shown in sliding presentation (http://developer.android.com/training/animation/screen-slide.html).
Or you can put your question inside a ListView if you want to view the question from top to bottom. (http://developer.android.com/guide/topics/ui/layout/listview.html)
EDIT:
Actually you are close to achieve what you want to do.
You should delete i = 0; inside your button onClick() function as it prevents you from going to next questions (3rd, 4th, etc). You might want to consider clearing the mathAnswer EditText when the user submits a question.
Also, it is not necessary to set correctAnswer = mathTest[i+1]; inside your if-else function.
Use arraylist for questions array and answer array.use view pager with two layouts questions and answer layout.if the answer array of position equal to the user answer its correct answer like u can dynamically
Related
I can successfully display the first problem from the text file, however I am having trouble accepting that answer and then displaying the second problem. I used a for loop in order to read lines from the text file. I also have an onClick listener.
My major problem is, how do I have the for loop wait until the onClick listener is hit before looping into the second problem.
Here's the relevant code:
public class MathTestActivity extends AppCompatActivity {
String correctAnswer;
int i = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mathtest);
TextView mathProblem = (TextView) findViewById(R.id.mathProblem);
final EditText mathAnswer = (EditText) findViewById(R.id.mathAnswer);
//Stying for the question text
mathProblem.setTextSize(40);
mathProblem.setTextColor(Color.rgb(0, 0, 0));
//Try to read the problem and answers text file
try {
InputStream is = this.getResources().openRawResource(R.raw.mediummath);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
int n = 20; /*How many rows this test has*/
for (i = 0; i < n; i++) {
if ((line = reader.readLine()) != null)
mathProblem.setText(line);
if ((line = reader.readLine()) != null)
correctAnswer = line;
}
} catch (IOException e) {
e.printStackTrace();
}
Button enterButton = (Button) findViewById(R.id.enterButton);
enterButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int correctcount = 0;
String answer = mathAnswer.toString() ;//need to turn answer into string Integer.parseInt(mathAnswer.getText().toString());
if (answer == correctAnswer){
Toast.makeText(MathTestActivity.this,
R.string.correct_toast,
Toast.LENGTH_SHORT).show();
correctcount++;
i++;
}
else{
Toast.makeText(MathTestActivity.this,
R.string.incorrect_toast,
Toast.LENGTH_SHORT).show();
i++;
}
}
});
//Add layout for this activity
RelativeLayout layout = (RelativeLayout) findViewById(R.id.mtestcontent);
layout.addView(mathProblem);
layout.addView(mathAnswer);
}
}
As you can see, it's the logic inside the "try" portion that I'm having difficulty with. Can someone help me with the logic here?
You need to "react" to an event. Your current code will read the entire file, then only display the last question & answer.
A recommended approach would be the following logic.
Read your entire file into a list of (question, answer) pairs that you can index later.
Load the first question
Declare a button listener
Compare the answer given to the correct answer
If correct, load the next question
I am developing a simple questionnaire-like app which includes lots of radio buttons joined into groups and spinners. I have multiple activities (6); some of them having RBs and some Spinners to let the user answer the questions.
The following step, which I have trouble with, is how to fetch lots of selections (of all the radio buttons/choices) and possibly do that in a for loop (so I don't have to initialize each new variable 30+ times in a row for just one activity). I've already assigned IDs to all of the views, but am having a hard time how to actually fetch the selection, initialize a new var corresponding to the selection (let's say radio button 1 in radio group 1 gives me a new variable with a value of 1) and then make the variables available to all of the activities (should I use global when initializing?).
My failed attempt on generating 10 variables for the first "page"
public void goTo2(View v) {
checkRB();
Intent intent1 = new Intent(Vprasalnik1.this, Vprasalnik2.class);
startActivity(intent1);
finish();
}
public void checkRB()
{
for (int i=0;i<9;i++)
{
RadioButton "vRB" + i; //I'd like to loop and initialize vars by adding a number to them (vRB1, vRB2, ...)
}
}
Put variables into array like a
int size = 9;
RadioButton[] views = new RadioButton[size];
public static checkRB()
{
for(int i=0;i<size;i++)
{
views[i] = (RadioButton)findViewByID(...);//For example
}
}
Or make a structure :
public class Choise
{
int mRadioButtonChoise;
int mSpinnerChoise;
}
And use something like this:
...
Choise c = new Choise();
c.mRadioButtonChoise = yourRadioButtonID;
c.mSpinnerChoise = youtSpinnerChoiseID;
...
Using a variable to identify a resource:
RadioButton[] rb = new RadioButton[size];
public static checkRB()
{
for(int i=0;i<size;i++)
{
int id = context.getResources().getIdentifier("vRB" + i, "id", context.getPackageName())
rb[i] = (RadioButton)findViewByID(id);
}
}
If you have an array of RadioButtons then you can get all the values at the same time, however initializing them will have to be manual.
RadioButton rb[];
boolean rbc[];
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
rbc=new boolean[200];
rb=new RadioButton[200]();
rb[0]=(RadioButton)findViewById(R.id.rb1);
rb[1]=(RadioButton)findViewById(R.id.rb2);
rb[2]=(RadioButton)findViewById(R.id.rb3);
rb[3]=(RadioButton)findViewById(R.id.rb4);
// many more.
}
public void checkRB()
{
for (int i=0;i<9;i++)
{
rbc[i]=rb.isChecked(); //I'd like to loop and initialize vars by adding a number to them (vRB1, vRB2, ...)
}
}
Then before starting your intent add all relevant data to it.
So I've managed to cramp up the radio buttons activity, so that it finally works. If anyone is interested - I've used tags in xml code to properly assign values (1, 2 and 3 for each group of buttons) and managed to get an output in my testToast. At least I didn't have to initialize all of the variables manually - I've been saving the values into an ArrayList and then appended to them via StringBuilder.
Thanks to everyone who tried to help - it turned out I've needed a bit more research, testing and teasing my half-awake brain.
btn = (Button) findViewById(R.id.v3_btn1);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
for(int i = 1; i <= 36; i++)
{
tmpRGid = "radioGroup_v3q" + i;
tmp2RGid = getResources().getIdentifier(tmpRGid, "id", getPackageName());
RGid = (RadioGroup) findViewById(tmp2RGid);
selectedOption = RGid.getCheckedRadioButtonId();
RBid = (RadioButton) findViewById(selectedOption);
addToIDList.add((String)RBid.getTag());
}
String testToast = "";
StringBuilder builder = new StringBuilder();
builder.append("Vaša izbira (");
for (int z=0; z < addToIDList.size(); z++) {
testToast = addToIDList.get(z);
builder.append(testToast + ", ");
}
builder.setLength(builder.length() - 2);
builder.append(") je bila shranjena.");
Toast.makeText(Vprasalnik3.this, builder, Toast.LENGTH_LONG).show();
I have two identical views with a number of editTexts. In one, pre-defined answers are populated in the editTexts (but not shown to the user). In the second, the user starts with all blank editTexts, and then fills them out in an attempt to make them the same as the pre-defined answers.
So I want to loop through the user's view, checking it against the pre-defined one, until an inequality is found, in which case the method will return false.
My code is below. Inside the onCreate I have a buttonListener (when the user is ready to check answers)
btnSolution.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(checkAnswer() == true){
Toast.makeText(getBaseContext(), "all good!", Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(getBaseContext(), "no good", Toast.LENGTH_LONG).show();
}
}
});
the checkAnswer() method is then defined as follows
public boolean checkAnswer() {
final int ROW_COUNT = 15;
final int COL_COUNT = 10;
final String ROWS[] = {"R1","R2","R3","R4","R5","R6","R7","R8","R9","R10","R11","R12","R13","R14","R15"};
final String COLS[] = {"C1","C2","C3","C4","C5","C6","C7","C8","C9","C10"};
for(int i=0; i<ROW_COUNT; i++) {
for(int j=0; j<COL_COUNT; j++) {
String a = ROWS[i];
String b = COLS[j];
int editTextBaseId = getResources().getIdentifier("box" + a + b, "id", getPackageName());
int editTextAnswerId = getResources().getIdentifier("boxA" + a + b, "id", getPackageName());
EditText editTextBase = (EditText)findViewById(editTextBaseId);
EditText editTextAnswer = (EditText)findViewById(editTextAnswerId);
String textBase = editTextBase.getText().toString();
String textAnswer = editTextAnswer.getText().toString();
if(textBase.equals(textAnswer)) {
}
else {
return false;
}
}
}
return true;
}
Unfortunately when I try and run this I am getting a crash and the following error in my LogCat
12-17 00:05:02.075: E/SKIA(16370): FimgApiStretch:stretch failed
Any obvious errors?
That's not an error itself. I guess you're using a Samsung as your target device, if so, don't worry about it.
In the other hand, maybe it's better to compare only the strings. All those findViewById are inneficient.
Looking at your code:
EditText editTextAnswer = (EditText)findViewById(editTextAnswerId);
Do you have both views in the same layout, and the one with the answers is hidden? I mean, if you have the view with blank editTexts as the content of your activity, you can't find the editText with the answer as it's in other xml (assuming you did it as a different xml).
I am developing an app that is a question's game. I managed to show the answers to each question to a different button each time but i am having trouble to check the right answer. My approach is: I created an extra column to the database where i indicate the column where the right answer is(1,2,3 or 4). I use this code for showing the answers in different buttons.
cur = dbHelper.getRandomQuestion();
String corrans = cur.getString(cur.getColumnIndex("CorrectAnswer"));
a = Integer.parseInt(corrans);
String question = cur.getString(cur.getColumnIndex("QUESTIONS"));
String answer0 = cur.getString(cur.getColumnIndex("ANSWER1"));
String answer1 = cur.getString(cur.getColumnIndex("ANSWER2"));
String answer2 = cur.getString(cur.getColumnIndex("ANSWER3"));
String answer3 = cur.getString(cur.getColumnIndex("ANSWER4"));
txtQuest.setText(question);
ArrayList<String> lstAnswers = new ArrayList<String>();
lstAnswers.add(answer0);
lstAnswers.add(answer1);
lstAnswers.add(answer2);
lstAnswers.add(answer3);
score.setText("Your score is " + b +","+ a);
Random random = new Random();
int[] textViews = new int[] { R.id.button1, R.id.button2, R.id.button3, R.id.button4 };
int textViewIndex = 0;
while (lstAnswers.size() > 0) {
int index = random.nextInt(lstAnswers.size());
if(a == index){ b = index;}
else{}
String randomAnswer = lstAnswers.remove(index);
((TextView)findViewById(textViews[textViewIndex])).setText(randomAnswer);
++textViewIndex;
}
To each button call to compare the values of a and b and then act accordingly. But it doesnt seem to work. I understand why but i cannot figure it out. Any help appeciated.
use Collections.shuffle(list) to shuffle your answer array and then display the answer
Set a tag as "right" to your button where anwer is correct and later compare the the tagvalue and disply right or wrong
EDIT: below thing is just an outline
Here im displaying answers in buttons....
List<Integer> intList = new ArrayList<Integer>(Arrays.asList(0,1,2,3));
Collections.shuffle(intList);
Log.d("ERR","List after shuffling: " + intList);
// below answers will be assiagned randomly to buttons...
btn_cmpTagline[intList.get(0)].setText(answr1);
btn_cmpTagline[intList.get(0)].setTag("right");
btn_cmpTagline[intList.get(1)].setText(answr2);
btn_cmpTagline[intList.get(1)].setTag("wrong");
btn_cmpTagline[intList.get(2)].setText(answr3);
btn_cmpTagline[intList.get(2)].setTag("wrong");
btn_cmpTagline[intList.get(3)].setText(answr4);
btn_cmpTagline[intList.get(3)].setTag("wrong");
//On Click
#Override
public void onClick(View v) {
switch(v.getId()){
case R.id.btn_tag1:
Log.d("ERR", v.getTag().toString());
if(v.getTag().toString().equalsIgnoreCase("right")){
//this button has right answer .. do anything
}
break;
case R.id.btn_tag2:
Log.d("ERR", v.getTag().toString());
if(v.getTag().toString().equalsIgnoreCase("right")){
//this button has right answer .. do anything
}
break;
case R.id.btn_tag3:
Log.d("ERR", v.getTag().toString());
if(v.getTag().toString().equalsIgnoreCase("right")){
//this button has right answer .. do anything
}
--
--
}
When you remove items from the list the the index of the correct answer will change, so you have to update where the correct answer is located.
you can get the value of the right answer instead of the index. then, as you add the answers to buttons you can check if it is the same with the correct answer and keep the new index.
I'm developping an app which constantly needs to show the results to the user in a TextView like some sort of log.
The app works nicely and it shows the results in the TextView but as long as it keeps running and adding lines the app gets slower and crashes because of the character length of the TextView.
I would like to know if the android API provides any way to force a TexView to automatically delete the oldest lines that were introduced in order to make room for the new ones.
I had the same problem. I just resolved it.
The trick is to use the getEditableText() method of TextView. It has a replace() method, even a delete() one. As you append lines in it, the TextView is already marked as "editable", which is needed to use getEditableText(). I have something like that:
private final static int MAX_LINE = 50;
private TextView _debugTextView; // Of course, must be filled with your TextView
public void writeTerminal(String data) {
_debugTextView.append(data);
// Erase excessive lines
int excessLineNumber = _debugTextView.getLineCount() - MAX_LINE;
if (excessLineNumber > 0) {
int eolIndex = -1;
CharSequence charSequence = _debugTextView.getText();
for(int i=0; i<excessLineNumber; i++) {
do {
eolIndex++;
} while(eolIndex < charSequence.length() && charSequence.charAt(eolIndex) != '\n');
}
if (eolIndex < charSequence.length()) {
_debugTextView.getEditableText().delete(0, eolIndex+1);
}
else {
_debugTextView.setText("");
}
}
}
The thing is, TextView.getLineCount() returns the number of wrapped lines, and not the number of "\n" in the text... It is why I clear the whole text if I reach the end of the text while seeking the lines to delete.
You can do that differently by erasing a number of characters instead of erasing a number of lines.
This solution keeps track of the log lines in a list and overwrites the textview with the contents of the list on each change.
private List<String> errorLog = new ArrayList<String>();
private static final int MAX_ERROR_LINES = 70;
private TextView logTextView;
public void addToLog(String str) {
if (str.length() > 0) {
errorLog.add( str) ;
}
// remove the first line if log is too large
if (errorLog.size() >= MAX_ERROR_LINES) {
errorLog.remove(0);
}
updateLog();
}
private void updateLog() {
String log = "";
for (String str : errorLog) {
log += str + "\n";
}
logTextView.setText(log);
}
Here is an example that adds lines to an output log limited by the set max lines. The scrollview will auto scroll to the bottom after every line is added. This example work purely with the contents of the TextView so it doesn't have the need for a separate data collection.
Add the following to your activity xml:
<ScrollView
android:id="#+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical" >
<TextView
android:id="#+id/textViewOutput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1000" />
</ScrollView>
In your activity add the following code:
private static final int MAX_OUTPUT_LINES = 50;
private static final boolean AUTO_SCROLL_BOTTOM = true;
private TextView _textViewOutput;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
_textViewOutput = (TextView) findViewById(R.id.textViewOutput);
}
//call to add line(s) to TextView
//This should work if either lineText contains multiple
//linefeeds or none at all
private void addLinesToTextView(String lineText) {
_textViewOutput.append(lineText);
removeLinesFromTextView();
if(AUTO_SCROLL_BOTTOM)
_scrollView.post(new Runnable() {
#Override
public void run() {
_scrollView.fullScroll(ScrollView.FOCUS_DOWN);
}
});
}
// remove leading lines from beginning of the output view
private void removeLinesFromTextView() {
int linesToRemove = _textViewOutput.getLineCount() - MAX_OUTPUT_LINES;
if (linesToRemove > 0) {
for (int i = 0; i < linesToRemove; i++) {
Editable text = _textViewOutput.getEditableText();
int lineStart = _textViewOutput.getLayout().getLineStart(0);
int lineEnd = _textViewOutput.getLayout().getLineEnd(0);
text.delete(lineStart, lineEnd);
}
}
}
The TextView shows what you set via setText() method. So this sounds to me like you should cut down the input you provide.
To empty the TextView, you can do setText("");
Kotlin answer of Vincent Hiribarren
fun write_terminal_with_limit(data: String?, limit:Int)
{
log_textView.append(data)
val nb_line_to_del: Int = log_textView.lineCount - limit
// Erase excessive lines
if (nb_line_to_del > 0)
{
var end_of_line_idx = -1
val char_seq: CharSequence = log_textView.text
for (i in 0 until nb_line_to_del)
{
do
{
end_of_line_idx++
}
while (end_of_line_idx < char_seq.length && char_seq[end_of_line_idx] != '\n')
}
if (end_of_line_idx < char_seq.length)
{
log_textView.editableText.delete(0, end_of_line_idx + 1)
}
else
{
log_textView.text = ""
}
}
}
I made personnal adjustment...
I think you are using TextView.append(string) then it will add to old text.
If you are setting using setText it will replace the old text
This is an old one, but I just found looking for a solution to my own problem.
I was able to remove all TextViews from a LinearLayout using nameoflayout.removeAllViews();
There is another method that will allow you to remove views from specified places in the layout using ints, it's: nameoflayout.removeViews(start, count); so I'm sure you could create a time out for how long textviews remain visible.
No, android API doesn't provide any functionally that delete oldest lines from textview automatically till API level 25. you need to do it logically.
Try to write a function that takes an old string on TextView and add new string to it, then get substring last strings that TextView capable. And set it to TextView. Something like this:
String str = textview.getText();
str += newstring;
int ln = str.length();
ln = ln-250;
if (ln<0) ln=0;
str = str.substring(ln);
textview.setText(str);
reference Vincent Hiribarren answer.
make it simple-->
TextView _debugTextView;
//if excess 20 lines keep new 200 chars
if(_debugTextView.getLineCount() >20) _debugTextView.getEditableText().delete(0,_debugTextView.getText().length()-200);