I have an activity in which some of the TextViews are empty at the beginning and are filled dynamically after data has been received from the server. The problem is that I can't see it on the screen, they are not refreshed! What can the problem be?
For example:
<TextView
android:id="@+id/answer_correctness_text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="0.2"
android:visibility="visible" />
and
answerCorrectnessText.setText(R.string.correct_label);
answerCorrectnessText.setTextColor(R.color.correct_answer_color);
The space it occupies remains empty! Thanks.
Ok, here's all the code, hope someone can find the problem: The layout:
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="fill_parent" android:layout_width="fill_parent">
<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"
android:orientation="horizontal"> <!-- android:layout_weight="0.15"> -->
<TextView android:id="@+id/question_text" android:layout_width="0dip"
android:layout_height="fill_parent" android:layout_weight="0.9"
android:text="empty"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="right" android:text="@string/score_label"/>
<TextView android:id="@+id/score_text" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_gravity="right"
android:layout_weight="0.1" android:paddingLeft="5dip"/>
</LinearLayout>
<RadioGroup android:id="@+id/answers_group" android:layout_width="fill_parent"
android:layout_height="0dip" android:orientation="vertical"
android:layout_weight="0.6" android:visibility="invisible">
<!-- May also be generated dynamically if the number of answers differs for each
question -->
<RadioButton android:id="@+id/answerA_button" android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<RadioButton android:id="@+id/answerB_button" android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<RadioButton android:id="@+id/answerC_button" android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<RadioButton android:id="@+id/answerD_button" android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
<RadioButton android:id="@+id/answerE_button" android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</RadioGroup>
<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content"
android:orientation="horizontal">
<Button android:id="@+id/answer_button" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="@string/answer_label"
android:visibility="invisible"/>
<TextView android:id="@+id/answer_correctness_text" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:visibility="invisible"
android:layout_weight="0.2"/>
<TextView android:id="@+id/correct_caption_text" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="@string/correct_answer_label"
android:visibility="invisible"/>
<TextView android:id="@+id/correct_text" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:visibility="invisible"
android:layout_weight="0.2"/>
<Button android:id="@+id/next_button" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="@string/next_label"
android:visibility="invisible"/>
</LinearLayout>
<TextView android:id="@+id/remark_text" android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
The code:
package com.lightcone.webdatastreams;
import java.io.*;
import java.net.*;
import java.text.ParseException;
import java.util.*;
import android.app.*;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.*;
import android.widget.*;
public class POSTexample extends Activity {
private static final String CHAPTERS_DATA_STATE_KEY="chaptersData";
private static final String QUESTION_STATE_KEY="question";
private static final String CHAPTER_STATE_KEY="chapter";
private static final String SCORE_STATE_KEY="score";
private static final int CORRECT_ANSWER_SCORE=10;
private static final int DEFAULT_CHAPTER=-1;
private static final int DEFAULT_SCORE=0;
private static final int NO_SUCH_CHAPTER_INDICATOR=-2;
// Set address for the questioner script on the server
public static final String host_url =
"http://csep10.phys.utk.edu/cgi-bin/quizforms/course1/questioner2.pl"; // Question script
public static final String TAG = "WEBSTREAM";
private ProgressDialog progDialog;
private int maxBarValue = 200;
private Map<String,Object> postData;
private TextView questionText;
private TextView scoreText;
private RadioGroup answersGroup;
private RadioButton[] answerRadioButtons;
private Button answerButton;
private TextView answerCorrectnessText;
private TextView correctAnswerCaptionText,correctAnswerText;
private Button nextButton;
private TextView remarkText;
private HashMap<Integer,Integer> chaptersData;
private QuestionData question;
private int chapter=DEFAULT_CHAPTER;
private int score=DEFAULT_SCORE;
private boolean chapterNotExists;
/*private class ChapterData implements Serializable
{
public int initialQuestionNum;
public int currentQuestionNum;
}*/
private class QuestionData implements Serializable
{
private static final long serialVersionUID=6800939332788597765L;
public int questionNum;
public String questionText;
public String[] answers;
public int correctAnswer;
public String remark;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState!=null)
{
chapter=savedInstanceState.getInt(CHAPTER_STATE_KEY,DEFAULT_CHAPTER);
score=savedInstanceState.getInt(SCORE_STATE_KEY,DEFAULT_SCORE);
question=(QuestionData)savedInstanceState.getSerializable(
QUESTION_STATE_KEY);
chaptersData=(HashMap<Integer,Integer>)savedInstanceState.
getSerializable(CHAPTERS_DATA_STATE_KEY);
}
if (chaptersData==null)
chaptersData=new HashMap<Integer,Integer>();
setContentView(R.layout.postexample);
questionText=(TextView)findViewById(R.id.question_text);
scoreText=(TextView)findViewById(R.id.score_text);
if (TextUtils.isEmpty(scoreText.getText()))
scoreText.setText(String.valueOf(score));
answersGroup=(RadioGroup)findViewById(R.id.answers_group);
answersGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener()
{
@Override public void onCheckedChanged(RadioGroup group,int checkedId)
{ if (!answerButton.isEnabled()) answerButton.setEnabled(true); }
});
/*The assumption is that there's a constant number of possible answers
*for each question, but the radio buttons could also be generated
*dynamically for each question*/
answerRadioButtons=new RadioButton[5];
answerRadioButtons[0]=(RadioButton)findViewById(R.id.answerA_button);
answerRadioButtons[1]=(RadioButton)findViewById(R.id.answerB_button);
answerRadioButtons[2]=(RadioButton)findViewById(R.id.answerC_button);
answerRadioButtons[3]=(RadioButton)findViewById(R.id.answerD_button);
answerRadioButtons[4]=(RadioButton)findViewById(R.id.answerE_button);
answerButton=(Button)findViewById(R.id.answer_button);
answerButton.setOnClickListener(new View.OnClickListener()
{
@Override public void onClick(View v)
{
int checkedRadioButtonID=answersGroup.getCheckedRadioButtonId();
String resourceName=getResources().getResourceName(
checkedRadioButtonID);
char answerLetter=resourceName.charAt(resourceName.indexOf('_')-1);
int userAnswer=answerLetter-'A';
answerButton.setEnabled(false);
if (question.correctAnswer==userAnswer)
{
score+=CORRECT_ANSWER_SCORE;
scoreText.setText(String.valueOf(score));
answerCorrectnessText.setText(R.string.correct_label);
answerCorrectnessText.setTextColor(R.color.correct_answer_color);
remarkText.setText(question.remark);
remarkText.setVisibility(View.VISIBLE);
}
else
{
score+=CORRECT_ANSWER_SCORE;
scoreText.setText(String.valueOf(score));
answerCorrectnessText.setText(R.string.wrong_label);
answerCorrectnessText.setTextColor(R.color.wrong_answer_color);
}
setAnswerComponentsState(false);
}
});
answerCorrectnessText=(TextView)findViewById(R.id.answer_correctness_text);
correctAnswerCaptionText=(TextView)findViewById(R.id.correct_caption_text);
correctAnswerText=(TextView)findViewById(R.id.correct_text);
nextButton=(Button)findViewById(R.id.next_button);
nextButton.setOnClickListener(new View.OnClickListener()
{
@Override public void onClick(View v)
{
if (chaptersData.get(chapter)==question.questionNum+1)
questionText.setText(R.string.no_more_questions_text);
else new BackgroundLoad().execute(host_url);
}
});
remarkText=(TextView)findViewById(R.id.remark_text);
if (chapter==DEFAULT_CHAPTER)
{
Dialog chapterDialog=createChapterDialog();
chapterDialog.show();
}
}
@Override public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater=getMenuInflater();
inflater.inflate(R.menu.options_menu,menu);
return true;
}
@Override public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.change_chapter_item:
Dialog chapterDialog=createChapterDialog();
chapterDialog.show();
return true;
case R.id.reset_score_item:
resetData();
return true;
default: return super.onOptionsItemSelected(item);
}
}
private Dialog createChapterDialog()
{
AlertDialog.Builder dialogBuilder=new AlertDialog.Builder(this);
dialogBuilder.setTitle(null);
LayoutInflater inflater=getLayoutInflater();
/*ViewGroup container=(ViewGroup)chapterDialog.findViewById(android.
R.id.custom);
inflater.inflate(R.layout.change_chapter,container);*/
View dialogView=inflater.inflate(R.layout.change_chapter,null);
dialogBuilder.setView(dialogView);
final EditText chapterEdit=(EditText)dialogView.findViewById(
R.id.chapter_edit);
if (chapter!=DEFAULT_CHAPTER)
chapterEdit.setText(String.valueOf(chapter));
else chapterEdit.setText("1");
final AlertDialog chapterDialog=dialogBuilder.create();
Button okButton=(Button)dialogView.findViewById(R.id.chapter_ok_button);
/*dialogBuilder.setPositiveButton(android.R.string.ok,new DialogInterface.
OnClickListener()*/
okButton.setOnClickListener(new View.OnClickListener()
{
//@Override public void onClick(DialogInterface dialog,int which)
@Override public void onClick(View view)
{
chapterDialog.dismiss();
int newChapter=Integer.parseInt(chapterEdit.getText().toString());
if (chapter!=newChapter)
{
Log.i(TAG,"Here!!!");
chapter=newChapter;
chapterNotExists=false;
if (postData==null) postData=new HashMap<String,Object>();
postData.put("chapter",chapter);
new BackgroundLoad().execute(host_url);
}
}
});
/*//The button does not exist even though we used setPositiveButton!?
ViewGroup.LayoutParams layoutParams=chapterDialog.getButton(AlertDialog.
BUTTON_POSITIVE).getLayoutParams();
layoutParams.width=ViewGroup.LayoutParams.WRAP_CONTENT;*/
return chapterDialog;
}
private void resetData()
{
score=0;
scoreText.setText(String.valueOf(score));
chaptersData.clear();
if (question!=null) chaptersData.put(chapter,question.questionNum);
}
@Override protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
if (chapter!=DEFAULT_CHAPTER) outState.putInt(CHAPTER_STATE_KEY,chapter);
if (score!=DEFAULT_SCORE) outState.putInt(SCORE_STATE_KEY,score);
if (question!=null)
outState.putSerializable(QUESTION_STATE_KEY,question);
if (chaptersData!=null)
outState.putSerializable(CHAPTERS_DATA_STATE_KEY,chaptersData);
}
// Implement query by POST method and return the response as a string.
private QuestionData doPOST(String host_url, Map<String,Object> data){
QuestionData question=null;
//Compose the request body
StringBuilder requestBodyBuilder=new StringBuilder();
for (String parameterName:data.keySet())
{
requestBodyBuilder.append(parameterName);
requestBodyBuilder.append('=');
requestBodyBuilder.append(data.get(parameterName));
requestBodyBuilder.append('&');
}
requestBodyBuilder.deleteCharAt(requestBodyBuilder.length()-1);
String requestBody=requestBodyBuilder.toString();
//Connect and retrieve data
URL url=null;
HttpURLConnection httpConnection=null;
BufferedWriter requestStream=null;
BufferedReader responseStream=null;
try
{
//Send request
url=new URL(host_url);
URLConnection connection=url.openConnection();
if (!(connection instanceof HttpURLConnection))
throw new IOException("Invalid HTTP connection: " + host_url);
httpConnection=(HttpURLConnection)connection;
httpConnection.setDoOutput(true);
httpConnection.setFixedLengthStreamingMode(requestBody.length());
requestStream=new BufferedWriter(new OutputStreamWriter(httpConnection.
getOutputStream()));
requestStream.write(requestBody);
requestStream.close();
// Extract the response status and the headers
int responseStatus = httpConnection.getResponseCode();
Map<String,List<String>> headers=httpConnection.getHeaderFields();
Log.i(TAG, "\nPOST response and headers:" );
Log.i(TAG, "\nResponse="+headers.get(null));
Log.i(TAG, "Response code = "+responseStatus);
Iterator<String> headerNamesIterator=headers.keySet().iterator();
/*Skip the first header, which is actually not a header but the
*status line of the response*/
headerNamesIterator.next();
while (headerNamesIterator.hasNext())
{
String headerName=headerNamesIterator.next();
//for (String headerName:headers.keySet())
for (String headerValue:headers.get(headerName))
Log.i(TAG, "header="+headerName+" value="+headerValue);
}
//Get response body
if (responseStatus==HttpURLConnection.HTTP_OK)
{
responseStream=new BufferedReader(new InputStreamReader(
httpConnection.getInputStream()));
question=buildQuestionData(responseStream);
}
}
catch (IOException ioException)
{
Log.e(TAG,"Error occurred while trying to retrieve data from the " +
"server!",ioException);
}
catch (ParseException parseException)
{
Log.e(TAG,"Error occurred while parsing the response received " +
"from the server!",parseException);
if (parseException.getErrorOffset()==NO_SUCH_CHAPTER_INDICATOR)
chapterNotExists=true;
}
finally
{
if (requestStream!=null)
{
//The closing may occur twice if the stream was closed previously
try { requestStream.close(); }
catch (IOException ioException) { }
}
if (responseStream!=null)
{
try { responseStream.close(); }
catch (IOException ioException) { }
}
if (httpConnection!=null) httpConnection.disconnect();
}
return question;
}
private QuestionData buildQuestionData(BufferedReader responseStream)
throws IOException,ParseException
{
//final String errorMessage="Invalid question data retrieved from server: ";
String line=retrieveLine(responseStream);
if (line.startsWith("<font"))
{
throw new ParseException("Chapter " + chapter + " does not exist! " +
"No question was received.",NO_SUCH_CHAPTER_INDICATOR);
}
QuestionData question=new QuestionData();
question.questionNum=extractIntParameter(line,"qnum",false);
line=retrieveLine(responseStream);
question.questionText=extractStringParameter(line,"question",false);
/*The assumption here is that there's a constant number of possible
*answers for each question, but it could also be dynamic*/
question.answers=new String[5];
int letterInt=(int)'A';
for (int counter=0;counter<question.answers.length;counter++)
{
line=retrieveLine(responseStream);
question.answers[counter]=extractStringParameter(line,"answer" +
(char)letterInt,false);
letterInt++;
}
//Chapter number
line=retrieveLine(responseStream);
int receivedChapter=extractIntParameter(line,"chapter",false);
if (chapter!=receivedChapter)
{
throw new ParseException("The chapter number of the question " +
"received from the server (" + receivedChapter +
" is not equal to the chapter number requested (" +
chapter + ")!",-1);
}
//Correct answer
line=retrieveLine(responseStream);
String correctAnswerStr=extractStringParameter(line,"coran",false);
if (correctAnswerStr.length()>1)
{
throw new ParseException("The correct answer must be one " +
"letter only!",-1);
}
char correctAnswer=correctAnswerStr.charAt(0);
char lastValidLetter=(char)((int)'A'+question.answers.length);
if ((correctAnswer<'A')||(correctAnswer>lastValidLetter))
{
throw new ParseException("The correct answer must be between A and " +
lastValidLetter + "! It's actually equal to " + correctAnswer,-1);
}
question.correctAnswer=correctAnswer-'A';
//Remark
line=retrieveLine(responseStream);
question.remark=extractStringParameter(line,"amp",false);
return question;
}
private String retrieveLine(BufferedReader responseStream) throws
IOException,ParseException
{
String line=responseStream.readLine();
if (line==null) throw new ParseException("Unexpected end of data!",-1);
else return line;
}
private String extractDataParameter(String data,String parameterName)
throws ParseException
{
int separator=data.indexOf('=');
if (separator==-1)
{
throw new ParseException("Invalid data! Parameter value could " +
"not be found: " + data,-1);
}
if (!data.substring(0,separator).equals(parameterName))
throw new ParseException("Missing parameter: " + parameterName,-1);
return data.substring(separator+1);
}
private int extractIntParameter(String data,String parameterName,boolean
isNegativeAllowed) throws ParseException
{
String parameterValueStr=extractDataParameter(data,parameterName);
int parameterValue=-1; boolean isValidNumber=true;
try { parameterValue=Integer.parseInt(parameterValueStr); }
catch (NumberFormatException numberException) { isValidNumber=false; }
if ((isValidNumber)&&(!isNegativeAllowed)&&(parameterValue<0))
isValidNumber=false;
if (!isValidNumber)
throw new ParseException("Parameter " + parameterName + " is invalid!" +
"Either it's non-numeric, or is a negative number and only " +
"positive numbers are allowed: " + parameterValueStr,-1);
return parameterValue;
}
private String extractStringParameter(String data,String parameterName,
boolean isEmptyAllowed) throws ParseException
{
String parameterValue=extractDataParameter(data,parameterName).trim();
if ((!isEmptyAllowed)&&(parameterValue.equals("")))
{
throw new ParseException("Parameter " + parameterName + " is an " +
"empty string!",-1);
}
return parameterValue;
}
private void handleResultQuestionData(QuestionData question)
{
if (question!=null)
{
this.question=question;
if (!chaptersData.containsKey(chapter))
chaptersData.put(chapter,question.questionNum);
questionText.setText(question.questionText);
for (int index=0;index<question.answers.length;index++)
answerRadioButtons[index].setText(question.answers[index]);
answersGroup.clearCheck();
answersGroup.setVisibility(View.VISIBLE);
answerButton.setVisibility(View.VISIBLE);
answerButton.setEnabled(false);
setAnswerComponentsState(true);
remarkText.setVisibility(View.INVISIBLE);
}
else
{
AlertDialog.Builder dialogBuilder=new AlertDialog.Builder(this);
if (chapterNotExists)
{
dialogBuilder.setMessage(R.string.chapter_not_exists_text);
dialogBuilder.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener()
{
@Override public void onClick(DialogInterface dialog,int which)
{ dialog.dismiss(); }
});
}
else
{
dialogBuilder.setMessage(R.string.question_not_retrieved_text);
DialogInterface.OnClickListener listener=new DialogInterface.
OnClickListener()
{
@Override public void onClick(DialogInterface dialog,int which)
{
dialog.dismiss();
switch (which)
{
case Dialog.BUTTON_POSITIVE:
new BackgroundLoad().execute(host_url);
break;
case Dialog.BUTTON_NEGATIVE: finish(); break;
}
}
};
dialogBuilder.setPositiveButton(R.string.try_again_label,listener);
dialogBuilder.setNegativeButton(R.string.exit_label,listener);
} //end else (if chapterNotExists)
dialogBuilder.show();
} //end else (if question!=null)
}
private void setAnswerComponentsState(boolean beforeAnswer)
{
int visibility=(beforeAnswer?View.INVISIBLE:View.VISIBLE);
answerCorrectnessText.setVisibility(visibility);
correctAnswerCaptionText.setVisibility(visibility);
correctAnswerText.setVisibility(visibility);
nextButton.setVisibility(visibility);
}
// Method to create a progress bar dialog of either spinner or horizontal type
@Override
protected Dialog onCreateDialog(int id) {
switch(id) {
case 0: // Spinner
progDialog = new ProgressDialog(this);
progDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progDialog.setMessage("Loading...");
return progDialog;
case 1: // Horizontal
progDialog = new ProgressDialog(this);
progDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progDialog.setMax(maxBarValue);
progDialog.setMessage("Loading...:");
return progDialog;
default:
return null;
}
}
// Use AsyncTask to perform the web download on a background thread. The three
// argument types inside the < > are a type for the input parameters (Strings in this case),
// a type for any published progress during the background task (Void in this case, because
// we aren't going to publish progress since the task should be very short), and a type
// for the object returned from the background task (in this case it is type String).
private class BackgroundLoad extends AsyncTask <String, Void, QuestionData>{
// Executes the task on a background thread
@Override
protected QuestionData doInBackground(String... params) {
// The notation String... params means that the input parameters are an array of
// strings. In new BackgroundLoad().execute(host_url) above we are
// passing just one argument, so params[0] will correspond to host_url.
return doPOST(params[0], postData);
}
// Executes before the thread run by doInBackground
protected void onPreExecute () {
// Call method to create a progress dialog defined by onCreateDialog()
showDialog(0);
}
// Executes after the thread run by doInBackground has returned. The variable s
// passed is the string value returned by doInBackground.
@Override
protected void onPostExecute(QuestionData question){
// Stop the progress dialog
dismissDialog(0);
// Process the response
handleResultQuestionData(question);
}
}
}