ImageView ArrayList gives NullPointerException - android

I'm having some trouble with the logic behind storing an ImageView into an ArrayList.
The application I'm developing keeps track of player statuses in a game. The user first adds Player objects (which keeps track of a status string and a status image to go with it) to an ArrayList (to keep track of them all). Then, after submitting all of the players, a screen pops up inflating a TableRow for each player, containing a button (to view the Player's profile), an ImageView (an icon representing the status), and a TextView (containing the player's status string value).
I don't have a problem with the buttons and loading each player's profile. The problem occurs with loading the "select status" GUI from dialog_select_icon.xml, particularly the ImageView ArrayList. I get a NullPointerException, which doesn't make sense to me because I'm doing it essentially the same way as I did the buttons.
//this code runs when user clicks a player's status icon
public void playerStatusIconClicked(View v)
{
//loop through buttons to determine which player's button was clicked
for (int i = 0; i < playerList.size(); i++)
{
if (v.getId() == playerStatusIVList.get(i).getId())
{
calledPlayer = i; //instance variable
loadStatusIconGUI();
}//if
}//for
}//method playerStatusIconClicked
//showStatusIconGUI inflates the "select status icon" GUI
//and handles the user selecting an icon
private void loadStatusIconGUI()
{
//inflate the GUI for the showStatusIcon dialog (inflater is an instance variable)
View view = inflater.inflate(R.layout.dialog_select_icon, null);
//if the list has something in it, start from fresh
if (!selectStatusIVList.isEmpty())
{
selectStatusIVList.clear();
}
//list of icons in the "select status icon" dialog
selectStatusIVList.add((ImageView) statusIconGUI.findViewById(R.id.statusIV0));
selectStatusIVList.add((ImageView) statusIconGUI.findViewById(R.id.statusIV1));
selectStatusIVList.add((ImageView) statusIconGUI.findViewById(R.id.statusIV2));
selectStatusIVList.add((ImageView) statusIconGUI.findViewById(R.id.statusIV3));
selectStatusIVList.add((ImageView) statusIconGUI.findViewById(R.id.statusIV4));
selectStatusIVList.add((ImageView) statusIconGUI.findViewById(R.id.statusIV5));
selectStatusIVList.add((ImageView) statusIconGUI.findViewById(R.id.statusIV6));
//create a dialog so user can select an icon
AlertDialog.Builder selectIconDialog = new AlertDialog.Builder(this);
selectIconDialog.setView(view); //set the Dialog's custom view
selectIconDialog.setTitle(R.string.title_select_icon);
selectIconDialog.setNegativeButton(R.string.close, null);
selectIconDialog.show();
}//showStatusIconGUI
//Handle clicks in the "select status icon" dialog
//Assigns a new status to the player
public void statusIconClicked(View v)
{
Toast message;
for (int i = 0; i < selectStatusIVList.size(); i++)
{
if (v.getId() == selectStatusIVList.get(i).getId())
{
message = Toast.makeText(
MafiaTracker.this, "new status: " statusID[i], Toast.LENGTH_SHORT);
message.show();
playerList.get(calledPlayer).setImage(imageID[i]);
playerList.get(calledPlayer).setStatus(statusID[i]);
}
}
updateViewPlayerGUI();
}
Note that imageID[i] and statusID[i] are referring to int arrays containing the IDs for each status string and status image.
I can post the xml file but since it's 124 lines long I'd prefer not to. Just know that each ImageView in the xml file DOES have an ID, so I can't figure out why I'm getting these NullPointerExceptions, starting with the "if (!selectStatusIVList.isEmpty())" part, and continuing on with every other call after.
Please help!

statusIconGUI seems to be the main layout xml you used in setContenView().
Consider the line :
selectStatusIVList.add((ImageView) statusIconGUI.findViewById(R.id.statusIV0));
you are using findViewbyID on statusIconGUI. Do that instead on the view instance of R.layout.dialog_select_icon which you inflated.
so, change the above line to :
selectStatusIVList.add((ImageView) view.findViewById(R.id.statusIV0));

Initially selectStatusIVList is null. In loadStatusIconGUI check it for null
if(selectStatusIVList != null){
if (!selectStatusIVList.isEmpty())
{
selectStatusIVList.clear();
}
}else{
selectStatusIVList = new ArrrayList<Integer>();
}

Related

How to show/hide listview elements?

I'm creating a chat application. I want to show the time when user clicks on message
. This feature is working with this code in getView() of BaseAdapter
holder.txt_msg_user.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{
if (holder.txt_date_user.isShown() && holder.txt_AM_user.isShown())
{
holder.usertimelayout.setVisibility(View.GONE);
holder.txt_date_user.setVisibility(View.GONE);
holder.txt_AM_user.setVisibility(View.GONE);
}
else
{
holder.usertimelayout.setVisibility(View.VISIBLE);
holder.txt_date_user.setVisibility(View.VISIBLE);
holder.txt_AM_user.setVisibility(View.VISIBLE);
}
}
});
But i want to add one more feature, like in the below image if i click on every message every message is showing its time, but i want to achieve one thing like skype, if user sees the time of any message then first it will check for the previous messages. If any previous message is showing the time then it should be hide & recently tapped on message by the user should be shown.Please help how it can be possible. This is the problem: (see image)
Since you're achieving the time already and it's being added to each list item, perhaps you could just set the last item in your listview to View.VISIBLE and the rest to View.GONE.
You keep a property like:
View selectedMessage;
Where you set when the user clicks in some message, and verify it:
...
#Override
public void onClick(View v) {
if (selectedMessage != null && v != selectedMessage) {
Holder h = (Holder) selectedMessage.getTag();
h.hideTime();
h = (Holder) v.getTag();
h.showTime();
selectedMessage = v;
}
...
}
...
It worth noting that this Holder interface would be something that you have created, implementing the methods showTime and hideTime. This is not Android built-in.

Android: deleting programmatically added image buttons with ID's

hows it going? I'm creating a little training app for a project, its going fine except for a formatting problem im getting. So, ive a csv file with a name and age for a client. an array is created from this, then I've got a scroll View containing a grid layout and i create Image Buttons from the client array. that's all fine. ive got an add client button at the end of this, the button and its activity work fine, but when you come back to the main screen, the buttons are all screwed up (huge, misplaced etc). So i figured i would loop through and delete all the buttons and repopulate the main screen, except, since i programmatically created them, i cant figure out how to find them to delete them. i tried setting their id's to the index of the array, but then i get a null pointer error.
Function where the buttons are created:
public void fillActivity_main(){
if(listPopulated == false) { // check to see if its aready been created
populateClientList();//fill array with client objects
listPopulated = true;
}
//setup asset manager
AssetManager am = getApplicationContext().getAssets();
//Create the "GridLayout Image Board"
GridLayout buttonBoard = (GridLayout) findViewById(R.id.buttonboard);
int idealWidth = buttonBoard.getWidth(); //get width of the board
int idealHeight = buttonBoard.getHeight() / 2;//same
//create the Listeners, this is a place holder for now but will eventually use SetCurrentClient() (or maybe just switch to Start screen, with the current client?)
View.OnClickListener imageClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.println("CLICK AT: " + v.getId());
Client temp = clientList[v.getId()];
Intent i = new Intent(getApplicationContext(), DisplayClient.class);
System.out.println(temp.getName());
i.putExtra("name", temp.getName());
System.out.println(i.getStringExtra("name"));
i.putExtra("age", Integer.toString(temp.getAge()));
startActivity(i);
}
};
int j = 0; //used the keep track of the id's we set for the buttons
for (int i = 0; i < clientList.length; i++) {
if (clientList[i] != null) {
//creation and ID setting
ImageButton imgbutton = (ImageButton) new ImageButton(this);
imgbutton.setId(i);
//Layout shit
imgbutton.setImageResource(R.mipmap.ic_launcher);
imgbutton.setMinimumWidth(idealWidth);
imgbutton.setMinimumHeight(idealHeight);
imgbutton.setOnClickListener(imageClickListener);
//check and set image
if(clientList[i].getClientImage().equals(" ")) {
try{
imgbutton.set(am.openFd(clientList[i].getClientImage()));}
catch(Exception ex){
ex.toString();
}
Log.d("ClientImageCheck", "No picture found for " + clientList[i].getName());
}
buttonBoard.addView(imgbutton);
j++;
}
}
//create the new Client Button at the end of all the rest.
Button newClientButton = (Button) new Button(this);
newClientButton.setText("+"); // obvious
newClientButton.setLayoutParams(new LinearLayout.LayoutParams(GridLayout.LayoutParams.WRAP_CONTENT, GridLayout.LayoutParams.WRAP_CONTENT));
newClientButton.setWidth(idealWidth);
newClientButton.setHeight(idealHeight);
View.OnClickListener newClientListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(getApplicationContext(), CreateClientForm.class);
startActivityForResult(i, 199);
//System.out.println("Doing good so far, leaving the createclient form bnut still in main");
}
}; // create listener
newClientButton.setOnClickListener(newClientListener); // assign listener
buttonBoard.addView(newClientButton); //add the button the buttonBoard, after all the clients have been added
}
Function where i do the deleting:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//Check which request we're responding to
if (requestCode == 199) {
// Make sure request was successful
if (resultCode == RESULT_OK) {
// The user made a name and crap.
Bundle extras = data.getExtras();
String name = extras.getString("name");
int age = extras.getInt("age");
Client temp = new Client(name, age);
addClientToArray(temp);
System.out.println(name + "attempted add to array");
}
for(int i = 0; i<clientList.length; i++ ){
View v = findViewById(i);
((ViewManager) v.getParent()).removeView(v);
}
fillActivityMain();
}
if i've got the logic right, the 'i' in the loop should be the appropriate id. Granted, the teach has kind of thrown us in the deep end for this project, never taken mobile apps or anything, so all this code is the result of me googling issues as i run into them. I've read the basics for Views, intents, etc, but there must be something i'm missing.
I've tried making the gridLayout that the buttons sit on a class variable so i could call it buttonBoard.removeView(i) or something.
ive also tried `
for(int i = 0; i<clientList.length; i++ ){
ImageButton btn = (ImageButton) findViewByid(i);
((ViewManager) v.getParent()).removeView(btn);
}
Can you add the replacement images at the same time that you delete the existing images? If so, try this:
for(int i = 0; i < buttonBoard.getChildCount(); i++) {
ImageButton tempButton = (ImageButton) buttonBoard.getChildAt(i);
tempButton.setVisibility(View.INVISIBLE);
buttonBoard.addView(yourImageButtonHere, i); //adds a new ImageButton in the same cell you are removing the old button from
buttonBoard.removeView(tempButton);
}
This approach should also prevent the GridLayout from rearranging where the children are. I believe the default behavior if you delete a child view is that the GridLayout will re-order the children so there is not empty cell at the beginning of the grid. I hope that makes sense.
There is so much wrong with this approach.
Mainly you don't have to create the ImageButtons manually and add them to the GridLayout. That is what recycled views such as GridView or RecyclerView are for. In fact you should use those to avoid OutOfMemoryError from having too much images in your layout.
But also you cannot just call setId(i) in the for loop. Android holds many ids already assigned and you can never be sure whether the id is safe. (Unless you use View.generatViewId())
And since you only want to remove all views added to your GridLayout why don't you just call removeAllViews() on the buttonBoard?

swithcing to next textview

Ok im making app and it have 15 button's and 6 textview's.I want when I press first button to change value of first textview(value is "") to something (number one for example).But problem is when i press second button if first textview is already set to some value to set set second textview to second value.
If you need something else ask in comments (sorry for bad English)
here is what I was doing(this is under onclick)when i press second button
if(textview1.equals("1")){
textview2.setText("2");}
else if (textview1.equals("")){
textview1.setText("2");
}
It sounds like you wish to show last 6 buttons pressed.
Store all pressed buttons in a List (i.e. LinkedList) of size 6. Initially, it will be empty.
Then whenever any button is pressed do two things:
1) add it to the List and delete old elements if size exceeds six.
2) set button values from List.
Second step can be achieved like this:
// all TextViews should be in a list
private List<TextView> textViews;
// declare as field
private List<String> memoryQueue = new ArrayList<String>();
public void update() {
//set fields for the pressed buttons
for (int i=0; i<6 && i<memoryQueue.size(); i++) {
String text = memoryQueue.get(i);
textViews.get(i).setText(text);
}
// set empty fields
for (int i = memoryQueue.size(); i<6; i++) {
textViews.get(i).setText("");
}
}
This code snippet assumes that you store your TextViews in a List.
And Easiest way to keep track of last six button:
public void buttonPressed(Button button) {
//get text based on your button
String text = button.getText();
if (memoryQueue.contains(text)) {
return;
}
memoryQueue.add(text);
if (memoryQueue.size() > 6) {
memoryQueue.remove(0);
}
}
Since you're concerned with the text inside of your text view, you should be using the object's getText method:
if( textview1.getText().equals("1") ){ // Edited
textview2.setText("2");
} else if (textview1.getText().equals("")){ //Edited
textview1.setText("2");
}
At first, you have to get the String text from TextView using getText() method then you can compare that String with another String. Now, change your condition as follows...
if(textview1.getText().toString().equals("1")){
textview2.setText("2");}
else if (textview1.getText().toString().equals("")){
textview1.setText("2");
}

ListView Images change back to original settings when scrolled out of view - Android

I have a ListView that contains multiple ListView items. The ListView items Layout contains an ImageView. I use this ImageView as a button. When the button is clicked it changes the ImageView from a gray image to a green image. But when I scroll the ImageView out of visible view and then back to it, it returns to its original color. When the ImageView is created it can be either green or gray, it depends on a JSON array. So if an image is green and clicked it turns to gray. Then when its out of visible view and returned to visible view it is green again! How can I make the images maintain their new state?
Here is my code,
if(p.getJSON().equals("NO")){
imageView.setBackgroundResource(R.drawable.gray);
imageView.setTag(0);
}//end if equals NO
if(p.getJSON().equals("YES")){
imageView.setClickable(false);
imageView.setBackgroundResource(R.drawable.green);
imageView.setTag(1);
}//end if equals yes
imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View imageView) {
final int status = (Integer) imageView.getTag();
if (status == 0){
imageView.setBackgroundResource(R.drawable.green);
imageView.setTag(1);
}
else{
imageView.setBackgroundResource(R.drawable.gray);
imageView.setTag(0);
}
}//end on click
});
You need to persist the state for the items that you have modified with the button press and then restore that state when your adapter's getView() is called for that item.
There are many ways you can do this: in memory, database, etc. You'll have to pick the method that works best for your purposes.
i.e. - item 3 gets clicked and the image changes from grey to green, store something to represent the state of the image (grey vs. green, a boolean would be great for this exact case) and then persist that data somewhere. Then when getView() gets called again for item 3 (it's about to be displayed again) you set the color of the image based on the data you persisted for item 3.
You could just modify the value in the original JSONArray that backs the ListView, btw.
The reason for this behaviour is because you do not persist the state of the items (if they were clicked or not). Each time the list is scrolled, the getView() is called and it executes the following code and the state is reset:
if(p.getJSON().equals("NO") ){
imageView.setBackgroundResource(R.drawable.gray);
imageView.setTag(0);
}//end if equals NO
if(p.getJSON().equals("YES")){
imageView.setClickable(false);
imageView.setBackgroundResource(R.drawable.green);
imageView.setTag(1);
}//end if equals yes
What is needed is a way to keep track of the state of each item based on its position. So you could confidently tell: item at position k is "YES" or "NO"!
You need to keep track of the items which have been clicked so that when getView() is called, you can update the state of the based on its current value (not based on JSON value).
1) Maintain a map of items positions which are checked, and corresponding state value ("YES" or "NO").
2) If item is clicked, add its (position, new state) to the map. If it is clicked again, update its state inside the map.
3) Use this map and set the state of the item in the getView(), something like:
Private field:
HashMap<Integer, String> map = new HashMap<Integer, String>();
In your getView():
String state = p.getJSON();
if(map.containsKey(position)) {
state = map.get(position);
}
if(state.equals("NO") ){
imageView.setBackgroundResource(R.drawable.gray);
imageView.setTag(0);
}//end if equals NO
if(state.equals("YES")){
imageView.setClickable(false);
imageView.setBackgroundResource(R.drawable.green);
imageView.setTag(1);
}//end if equals yes
final int pos = position;
imageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View imageView) {
final int status = (Integer) imageView.getTag();
if (status == 0){
imageView.setBackgroundResource(R.drawable.green);
imageView.setTag(1);
map.put(pos, "YES")
}
else {
imageView.setBackgroundResource(R.drawable.gray);
imageView.setTag(0);
map.put(pos, "NO")
}
}//end on click
});
Note: this is just one of the many ways of getting what you want, however the basic idea should be the same..

onPrepareDialog ListView not populating on first Alert Dialog Creation

I create an alert dialog that has a basic checkbox list in it when I press a button. If the items have been checked before, I want to be able to check the checkboxes for the user. I have accomplished this by manipulating "onPrepareDialog" like so:
#Override
protected void onPrepareDialog(int id, Dialog dialog) {
Log.v("dialog", "On prepare dialog");
ListView lv = ((AlertDialog) dialog).getListView();
if (lv == null){
return;
}
String[] names = Utility.convertStringToArr(currentTravelers, ", ");
for(int i = 0;i < lv.getChildCount();i++){
for(int j = 0;j< names.length;j++){
String tn = lv.getItemAtPosition(i).toString();
if(tn.equalsIgnoreCase(names[j])){
lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
lv.setItemChecked(i, true);
}
}
}
}
This works fine, EXCEPT for the very first time I select the button. It will just show me the checklist with nothing selected. If I cancel out and hit it again, I will then see the correct names checked. I've tried tracing out the ListView child count, and it comes up as 0 the first time.
Is there anyway around this so that the very first time the alert dialog comes up it actually populates the listview so I can check the correct names?
Is there something I am not overriding or adapting? I am at a loss here.
Thanks!
Well I was able to get around this by putting a post delay before it populates the listview:
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() { //code to manipulate goes here
}}, 100);
This basically makes it wait 100 milliseconds, which seems to be enough time for the dialog information to load into the listview. Does anyone know a more efficient way of doing this?

Categories

Resources