we are working on project in order to create an application to help autits to communicate.
In fact, after moving the ImageViews, all of them are getting back in place after my tablet's rotation.
We tried a lot of things and we finally have made this code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.repas);
area1 = (LinearLayout) findViewById(R.id.area1);
area2 = (LinearLayout) findViewById(R.id.area2);
TypedArray arrayResources = getResources().obtainTypedArray(
R.array.resicon);
if( savedInstanceState != null ) {
int count_item = savedInstanceState.getInt("number_of_item");
int tab_item[] = new int[count_item];
for (int i = 0; i < count_item; i++) {
tab_item[i]=savedInstanceState.getInt("Sauvegarde_repas" +i);
}
for (int i = 0; i < arrayResources.length(); i++) {
ImageView imageView = new ImageView(this);
imageView.setImageDrawable(arrayResources.getDrawable(i));
imageView.setOnTouchListener(myOnTouchListener);
imageView.setId(i);
if (check(tab_item,i)){
area1.addView(imageView);
}
else{
area2.addView(imageView);
}
}
}
else {
for (int i = 0; i < arrayResources.length(); i++) {
ImageView imageView = new ImageView(this);
imageView.setImageDrawable(arrayResources.getDrawable(i));
imageView.setOnTouchListener(myOnTouchListener);
imageView.setId(i);
area2.addView(imageView);
}
arrayResources.recycle();
}
area1.setOnDragListener(myOnDragListener);
area2.setOnDragListener(myOnDragListener);
}
#Override
public void onSaveInstanceState(Bundle outState)
{
int count = area1.getChildCount();
View v = null;
outState.putInt("number_of_item", count);
for(int i=0; i<count; i++) {
v = area1.getChildAt(i);
outState.putInt("Sauvegarde_repas" + i, v.getId());
}
super.onSaveInstanceState(outState);
}
Here are my interrogations:
When I set an id, it's just "i", a very simple number. It doesn't seem very unique like a string "R.id.String_here" (even if I know that is converted in Integer), so how can I be sure to do a unique ID?
Do I have to save, one by one, the child of my layout? It's not possible to save the whole layout?
Do you have any advice to improve my code? (Because it looks dirty, isn't it ?)
Thank you very much for your help !
Related
I have a problem with Android Studio. I'm trying to do a pretty simple app but on my phone (Galaxy S8) it always gives me the same error. And I use two computer it does the same at home and at school. When I use the emulator, everything's good.
Try this defensive programming code. This should avoid NPE problem, but the root reason are:
You should refactor your game code with some Design Mode (try MVC at lease). You should not relay on the TextView String Value for game logic decision.
Some UI Tree node maybe has been changed inside the loop.
public boolean checkEndOfGame(LinearLayout cartes, LinearLayout piles){
if(nbCartes == 0){
return true;
}
for (int i=0; i< piles.getChildCount(); i++){
LinearLayout sorte = (LinearLayout)piles.getChildAt(i);
for(int j=0; j< sorte.getChildCount(); j++){
View sorteChild = sorte.getChildAt(j);
if(sorteChild instanceof ConstraintLayout){
ConstraintLayout pile = (ConstraintLayout)sorteChild;
if(0 == pile.getChildCount) {
Log.e("TAG", "pile's child count = 0 ");
continue; //or break ?
}
View pileChild = pile.getChildAt(0);
if(pileChild instanceof TextView) {
TextView textePile = (TextView) pileChild;
int noPile = Integer.valueOf(textePile.getText());
for(int k=0; k< cartes.getChildCount(); k++){
View cartesChild = cartes.getChildAt(i);
if(cartesChild instanceof LinearLayout) {
LinearLayout rangee = (LinearLayout)cartesChild;
for(int l=0; l< rangee.getChildCount(); l++){
View carteChild = rangee.getChildAt(l);
if(carteChild instanceof ConstraintLayout) {
ConstraintLayout carte = (ConstraintLayout)carteChild;
View tv = carte.getChildAt(0);
if(tv instanceof TextView) {
TextView texteCarte = (TextView) tv;
int noCarte = Integer.valueOf(texteCarte.getText());
if(i>0){ //UP
if(noCarte>noPile){
return false;
}
}else{ //DOWN
if(noCarte<noPile){
return false;
}
}
}
}
}
}
}
}
}
}
}
return true;
}
RecyclerView containing multiple layouts such as one row containing Edittext, radioButtons another row containing checkbox etc
Now when I input in first edit text and scroll the list then same inputed value gets copied in the last edit text visible on the screen.
Also if there are two radio buttons visible say radio1 and radio 2 then on scroll this becomes
radio1
radio2
radio1
radio2
i.e. radio1 and radio 2 are duplicated on scroll.
Can any one suggest some solution for the same?
Code for dynamic Edit Text
private void configureViewHolderText(final ViewHolderText holderText, final int position) {
if (questionsArrayList != null && questionsArrayList.size() > 0) {
String hint = questionsArrayList.get(position).getHelperText();
int characterLength = questionsArrayList.get(position).getCharLimit();
boolean isQuestionRequired = questionsArrayList.get(position).isRequired();
if (isQuestionRequired) {
holderText.getTv_dynamic_star().setVisibility(View.VISIBLE);
}
holderText.getTv_dynamic_text_view().setText(questionsArrayList.get(position).getQuestionText());
if (characterLength > 0) {
holderText.getEt_dynamic_edit_text().setFilters(new InputFilter[]{new InputFilter.LengthFilter(characterLength)});
}
if (hint != null && hint.equals("null") == false && hint.equals("") == false) {
holderText.getEt_dynamic_edit_text().setHint(hint);
} else {
holderText.getEt_dynamic_edit_text().setHint("Enter Answer");
}
holderText.getEt_dynamic_edit_text().addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
editTextInput = holderText.getEt_dynamic_edit_text().getText().toString();
// SubmitAnswerRequest submitAnswerRequest = new SubmitAnswerRequest();
// SubmitAnswerRequest.answers answers = submitAnswerRequest.new answers();
// hashAnswerInput.put(questionsArrayList.get(position).get_id(), editTextInput);
/*hashQuestionText.put(questionsArrayList.get(position).get_id(), questionsArrayList.get(position).getQuestionText()) ;
hashQuestionId.put(questionsArrayList.get(position).get_id(), questionsArrayList.get(position).get_id()) ;
hashAnswerType.put(questionsArrayList.get(position).get_id(), questionsArrayList.get(position).getAnswerType());*/
/* for(Map.Entry map : hashAnswerInput.entrySet() )
{
dynamicEditTextAnswer = String.valueOf(map.getValue());
//answers.setAnswerText(inputAnswer);
}*/
/*if(dynamicEditTextAnswer!= null)
{*/
SubmitAnswerRequest submitAnswerRequest = new SubmitAnswerRequest();
SubmitAnswerRequest.answers answers = submitAnswerRequest.new answers();
answers.setQuestionText(questionsArrayList.get(position).getQuestionText());
answers.setQuestionId(questionsArrayList.get(position).get_id());
answers.setAnswerText(editTextInput);
answers.setAnswerType(questionsArrayList.get(position).getAnswerType());
answersArrayList.put(questionsArrayList.get(position).get_id(),answers);
/* }*/
/*for(Map.Entry map : hashQuestionText.entrySet() )
{
String inputAnswer = String.valueOf(map.getValue());
answers.setQuestionText(inputAnswer);
}
for(Map.Entry map : hashQuestionId.entrySet() )
{
String inputAnswer = String.valueOf(map.getValue());
answers.setQuestionId(inputAnswer);
}
for(Map.Entry map : hashAnswerType.entrySet() )
{
String inputAnswer = String.valueOf(map.getValue());
answers.setAnswerType(inputAnswer);
}*/
// SubmitAnswerRequest submitAnswerRequest = new SubmitAnswerRequest();
// SubmitAnswerRequest.answers answers = submitAnswerRequest.new answers();
// answers.setQuestionText(questionsArrayList.get(position).getQuestionText());
// answers.setQuestionId(questionsArrayList.get(position).get_id());
// answers.setAnswerText(editTextInput);
// answers.setAnswerType(questionsArrayList.get(position).getAnswerType());
// answersArrayList.add(answers);
}
#Override
public void afterTextChanged(Editable s) {
}
});
}
}
Code for dynamic radio button
private void configureViewHolderRadioGroup(final ViewHolderRadioGroup holderRadioGroup, final int position) {
if (questionsArrayList != null && questionsArrayList.size() > 0) {
ArrayList<String> radioOptionsList = new ArrayList<String>();
for (int j = 0; j < questionsArrayList.get(position).getOptions().size(); j++) {
String radioItemName = questionsArrayList.get(position).getOptions().get(j).getOptionText();
radioOptionsList.add(radioItemName);
}
holderRadioGroup.getTv_dynamic_text_view().setText(questionsArrayList.get(position).getQuestionText());
boolean isQuestionRequired = questionsArrayList.get(position).isRequired();
if (isQuestionRequired) {
holderRadioGroup.getTv_dynamic_star().setVisibility(View.VISIBLE);
}
int totalCount = questionsArrayList.get(position).getOptions().size();
final RadioButton[] rb = new RadioButton[totalCount];
for (int i = 0; i < totalCount; i++) {
rb[i] = new RadioButton(context);
rb[i].setText(radioOptionsList.get(i));
rb[i].setId(i);
holderRadioGroup.getRg_dynamic_radio_group().addView(rb[i]); //the RadioButtons are added to the radioGroup instead of the layout
holderRadioGroup.getRg_dynamic_radio_group().setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
for (int i = 0; i < group.getChildCount(); i++) {
RadioButton rg = (RadioButton) group.getChildAt(i);
if (rg.getId() == checkedId) {
radioInput = rg.getText().toString();
Toast.makeText(context, radioInput, Toast.LENGTH_SHORT).show();
SubmitAnswerRequest submitAnswerRequest = new SubmitAnswerRequest();
SubmitAnswerRequest.answers answers = submitAnswerRequest.new answers();
answers.setQuestionText(questionsArrayList.get(position).getQuestionText());
answers.setQuestionId(questionsArrayList.get(position).get_id());
answers.setAnswerText(radioInput);
answers.setAnswerType(questionsArrayList.get(position).getAnswerType());
// answersArrayList.add(answers);
answersArrayList.put(questionsArrayList.get(position).get_id(),answers);
ArrayList<String> relatedQuestionsId = new ArrayList<String>();
relatedQuestionsId = questionsArrayList.get(position).getOptions().get(i).getRelatedQuestionIds();
if (relatedQuestionsId != null && relatedQuestionsId.size() > 0) {
for (int k = 0; k < relatedQuestionsId.size(); k++) {
((LinearLayout) holderRadioGroup.getLl_parent_radio_child()).removeAllViews();
getRadioChildQuestions(relatedQuestionsId, holderRadioGroup, k);
}
}
return;
}
else if(rg.getId() != checkedId) {
ArrayList<String> relatedQuestionsId = new ArrayList<String>();
/*for (int j = 0; j < questionsArrayList.get(position).getOptions().size(); j++) {*/
relatedQuestionsId = questionsArrayList.get(position).getOptions().get(i).getRelatedQuestionIds();
if (relatedQuestionsId != null && relatedQuestionsId.size() > 0) {
for (int k = 0; k < relatedQuestionsId.size(); k++) {
((LinearLayout) holderRadioGroup.getLl_parent_radio_child()).removeAllViews();
}
}
}
}
}
});
}
}
}
The recycler view reuses your view holders instances.
So if you are scrolling and a layout is leaving the screen at the top, it gets reused, when the same layout should be used for a new item at the bottom.
You need to reset all dynamic attribues in the onBindViewHolder-method.
For a better understanding set two debug points inside your recycler view adapter:
One inside the onCreateViewHolder-method and one inside the onBindViewHolder-method.
EDIT:
A sample for a working Recycler View Adapter can be found here: https://github.com/olLenz/Movies-with-Kotlin/blob/master/base/src/main/java/com/lenz/oliver/movieswithkotlin/ui/home/HomeAdapter.kt
The onCreateViewHolder-method creates a new instance of the ViewHolder.
The onBindViewHolder-method just calls the bind-method on a created ViewHolder instance. This bind-method sets all dynamic information to the given layout on every call.
Is it possible to get all the TextView in an activity and change their values without knowing any ID? May be something like UI automtor tool that return UI hierarchy but at Java programming level. I tried to Google this but couldn't find any solution.
Edit
What I am trying to achieve here is, I have an external library/SDK which modifies all textView values. So I am planning to initialise it on top of each activity and let the SDK do the work of modifying all the TextViews value.
You can use this code to find all TextViews in your layout, just pass the parent view and it will do the rest:
public static void findViews(View v) {
try {
if (v instanceof ViewGroup) {
ViewGroup vg = (ViewGroup) v;
for (int i = 0; i < vg.getChildCount(); i++) {
View child = vg.getChildAt(i);
// recursively call this method
findViews(child);
}
} else if (v instanceof TextView) {
//do whatever you want ...
}
} catch (Exception e) {
e.printStackTrace();
}
}
try this
First initialize the parent control and use this
ArrayList<TextView> list = new ArrayList<TextView>();
for( int i = 0; i < layout.getChildCount(); i++ ){
if( layout.getChildAt( i ) instanceof TextView )
{
// change the values of text view here
((TextView)layout.getChildAt( i )).setText("your text here");
}
}
If you have activity layout then try as follows
ArrayList<EditText> myEditTextList = new ArrayList<EditText>();
for( int i = 0; i < activityLayout.getChildCount(); i++ ){
if( activityLayout.getChildAt( i ) instanceof EditText )
myEditTextList.add( (EditText) activityLayout.getChildAt( i ) );
}
and getting their values
for(int i=0;i < myEditTextList.size();i++){
System.out.println(myEditTextList.get(i).getText().toString());
}
Hope this will helps you.
I'm here today for my soundboard app ! son to make it simple i have a G_Son object which is the controller of the "Son" model. i get the list of sound from my database (everything is fine until here) but then when I dynamically try to create ImageButtons and add them on my activity (manageLayout() ), I have absolutely nothing appearing on my activity ! not even a single button. So if you have any Idea, or want to give me a hand, I'm aware of any suggestion
private G_Son gson;
private OurNiceSoundPlayer soundPlayer;
private List<Son> sons;
RelativeLayout gameBoard;
private Son selectedSound;
private View.OnClickListener mSoundOnClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
soundPlayer.setSound(sons.get(Integer.parseInt(v.getTag().toString())));
Log.i("Board", "Clicked on ImgButton ->" + v.getTag());
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_board);
gson = G_Son.getInstance();
sons = gson.getSons(getApplicationContext());
soundPlayer = new OurNiceSoundPlayer(getApplicationContext());
gameBoard = (RelativeLayout) findViewById(R.id.soundboard);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
lp.addRule(RelativeLayout.CENTER_IN_PARENT,1);
manageLayout();
gameBoard.invalidate();
}
private void manageLayout() {
if (sons.size()>0)
{
int rawNbr = (int) Math.ceil((double) sons.size() / 3);
int currentSon = 0;
Son displayed = sons.get(currentSon);
for (int i = 0; i < rawNbr; i++)
{
LinearLayout row = new LinearLayout(this);
row.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
for (int j = 0; j < 3; j++)
{
ImageButton btnTag = new ImageButton(this);
if (displayed.getIsPerso()) {
File imgFile = new File(displayed.getPathImage());
if (imgFile.exists()) {
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
btnTag.setImageBitmap(myBitmap);
} else {
btnTag.setImageResource(R.drawable.defaultimage);
}
}
else
{
int id = getResources().getIdentifier("com.example.m.sbst:drawable/" + displayed.getPathImage(), null, null);
btnTag.setImageResource(id);
}
btnTag.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
btnTag.setOnClickListener(mSoundOnClickListener);
btnTag.setBackgroundColor(Color.TRANSPARENT);
btnTag.setTag(currentSon);
btnTag.setId(i);
row.addView(btnTag);
currentSon++;
if (currentSon>=sons.size())
{
break;
}
else
{
displayed = sons.get(currentSon);
}
}
gameBoard.addView(row);
}
}
}
Forgot to mention a size, moreover, after months of learning android, I should advice people to use a grid view to do so, it allows with custom layout to do event better than creating your own layout with dynamic image buttons
I have this so far, and the result is a blank screen. What might I do to achieve the desired effect of listing the first 46 Fibonacci numbers?
TextView fibNum;
static int i = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public static int fib(int n) {
int prev1=0, prev2=1;
for( i=0; i<n; i++) {
int savePrev1 = prev1;
prev1 = prev2;
prev2 = savePrev1 + prev2;
}
return prev1;
}
public void main(String[] args) {
for (int i=0; i<=46; i++)
fibNum = new TextView(this);
fibNum.setText(String.valueOf(fib(i)+", "));
}
}
First, just creating a TextView doesn't make it part of the view hierarchy being displayed. Second, Android will never call your main method. Third, I don't see how your code even compiles; the loop inside main only covers the assignment to fibNum, so at the call to setText, the variable i is not even in scope.
Putting all that aside, let's assume your activity_main.xml layout file already has a TextView in it with id #+id/text where you want to display the numbers. I suggest something like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView text = (TextView) findViewById(R.id.text);
text.setText(getFib(46));
}
public static int fib(int n) {
int prev1 = 0, prev2 = 1;
for(int i = 0; i < n; i++) {
int savePrev1 = prev1;
prev1 = prev2;
prev2 = savePrev1 + prev2;
}
return prev1;
}
public static String getFib(int n) {
StringBuilder sb = new StringBuilder(fib(0));
for (int i = 1; i < n; ++i) {
sb.append(", ");
sb.append(fib(i));
}
return sb.toString();
}
This assumes that calculating 46 Fibonacci numbers doesn't take an inordinate amount of time. If it does, you'll have to move the calculation to a worker thread (probably easiest to do using an AsyncTask).