I have created a compound control that I am reusing in multiple activities. This control contains a bunch of TextViews and Buttons, and most importantly a ListView. I define the XML in a layout file and in the constructor to this compound control, I inflate the XML as such:
String service = Context.LAYOUT_INFLATER_SERVICE;
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(service);
inflater.inflate(R.layout.map_menu, this, true);
The layout XML contains a ListView, and also in the constructor this compound control will handle setting up the adapter (my adapter extends ArrayAdapter) and array for it, like so:
ListView tableOfContentsList = (ListView) findViewById(R.id.tocListView);
_layerAdapter = new LayerAdapter(context, R.layout.toc_layer_item, _layers);
tableOfContentsList.setAdapter(_layerAdapter);
This compound control is used in two activites - one of these activities calls another. No relation between the two activities is intended.
Here is my problem. When the compound control is created in the initial activity, the above code is called to set the adapter of this control. Then, when the second activity is created and navigated to, the constructor is called again on this second instance of the control. This seems to have a side effect on the first control located in the initial activity. The second control seems to overwrite parts of the adapter from the first control - because basically the first adapter will not be functional once the constructor to the second control is called.
It is my guess that since I am referencing the resource ID of the ListView in both controls, Android is removing the adapter from the first ListView when the second ListView is created - because it sees both ListViews as having the same resource ID? Is this possible?
I have had trouble before in this exact same case - where multiple compound controls are used in different activities (and multiple times in a single activity) - and the problem was due to inflating from XML layout. My solution to that prior problem was to get rid of the inflating from layout, and instead creating the objects through code. This was acceptable because those compound controls were much simpler and contained only two views - however I feel in the above ListView case, where my compound control has at least ten views in it, it is not an acceptable solution to define each view in code. I need the layout XML.
Has anyone ever experienced this sort of clashing behavior when using custom compound controls that are inflated from XML, and re-used in multiple instances?
From my understanding Android should create a new instance of the widgets each time you inflate the xml. Do you have any static members in you compound widget class?
Related
I'm looking for an effective and reusable way of reusing lists of data in slightly different contexts.
What I have is a list like the following:
[Bitmap] PlayerName
[Bitmap] PlayerName
...
These are stored as ArrayLists that I get from Cursors and are parcelable so I can move them around as required.
The issue I have is that I want to re-use the Image and name but change info within the line.
What I mean is this:
When I show the players in the first list, I have a remove button that removes that player from the whole game.
In another list I also use a remove button but that's to remove them from a specific instance of a game.
In both these instances I've got a Removebutton with the list, I use lazy hackery when I construct the ListaAapter to choose what the button does. The listitems themselves have no listener, just the button.
I now want to reuse the player list again, but have the whole items clickable (i.e. use the OnItemClickListener or some such) and then place a number next to them (in the order they were clicked).
I imagine I could add a TextView under the Remove box and wire it into the same thing and make the TextView and the Button visible as required but that seems like a pretty bad way to manage it.
How should I separate the presentation from the data in this instance?
Potential solutions
1.
As per a suggestion on using layouts, I have a constructor like this:
public PlayerListAdapter(Context context, ArrayList<Player> players, GameInstance gameInstance) {
super(context, R.layout.row_player_empty, players);
this.context = context;
this.players = players;
this.gameInstance = gameInstance;
}
Would I add an int for layout to that constructor and then change my getView and onClick methods to use the layout to drive the different data sources?
2.
Another solution I've looked at is 'merging' layouts. Here I create a base 'player' and then for each set of additional UI elements I wrap the base into the additional elements as a new layout. This at least means I'm re-using the font/size/margins etc.
I'd probably rather overlay the elements a bit more dynamically but at least If I change the base style i'm doing it once rather than 3 times.
You can manage both list with different xml for it.
From fragment/activity, you can passs which kind of list view you are looking and on depneds on that, your xml out of 2 layout will inflate and you can set values.
In first case, you need just delete button clickable, so you can set listener on that only, in second case you need entire button clickable, so you can set onClickListner when you set that kind of list view xml.
As you have 2 cases:
in case 1, you should pass any boolean or enum kind value in constructor, so you can identify which kind of xml, I need to populate
And in getView() before inflating view, you should compare that value and depends on that, you should populate xml, like:
getView(){
if(case1){
View view = mInflater.inflate(R.layout.case_one_layout, null);
//set all values and listener on delete button as your require.
}else if(case2){
View view = mInflater.inflate(R.layout.case_two_layout, null);
//here you can set listener on entire row as onItemclick from fragment.
}
}
You can also manage with switch or other way as you like.
I searched allover but couldn't find any clear answer. I have a ListView declared in A customView and I would like to open another ListView when clicking on an Item.
I managed to do that by changing the adapter each time I click on an item on the Main ListView and show a pseudo new ListView. However this is not a stable solution.
I would like to know how can I instantiate a new listView without using intents or without having to change the adapter each time I want a new list output. I would want to create an entirely new ListView without direct connection to the initial one.
Can you try using ListFragment with FrameLayout in layout file? and just switch fragment when click on list item
I found the solution. I created in the CustomView several LinearLayouts for each listview one root layout. I have also created an individual class for each listView and used the same CustomAdapter and ViewHolder throughout. What I additionally used were interfaces that I declared in each List View class, with a method that tracks the row number. Based on this I implemented all the interfaces in the CustomView and listened to the clicked rows. At last, I then created animation methods and played with the visibilities.
By the way, instead of setting the List views to INVISIBLE i set them to GONE, hence there are quite manny the GPU doesn't need to recalculate the layout bounds.
Hope that helps cheers.
The method that i Place in the customView init() looks like this:
The interface listener must be implemented on "this" context of the CustomView, otherwise NUllPointerException hence the ListView doesn't know where to listen too.
i have to make a listview in which there are two elements to be displayed vertically.
i know that to use the default adapter given with android there can only be one array and one text resource...ie if i am using android.R.layout.simple_list_view then there is only one text resource.
To make a custom Listview i am doing the following:
making a xml layout file for each element of the listview
extending a custom adapter class which extends the baseadapter
in the getview method of the custom adapter class i am inflating the view for each element and then returning with the info i want the listview element to have from an array which i have passed as a constructor to the custom adapter class.
this seems very tedious because there are several instances where i have to make listview where sometimes there are three text elements in each listview element and sometimes 2 text elements in each listview element.
is there an easier way to do the above.
thank you in advance.
With such simple layout, I'd suggest you to just use a LinearLayout and 2-3 TextViews (or any view you need, even an horizontal LinearLayout). Nothing will beat that simplicity. There's no need for a ListView in that case.
You could consider creating a generic, reusable ListView layout file that is loaded up with all the various elements you need (which, hopefully is a concise few). You could default as many of those elements in the layout XML file with android:visible="false" and then programmatically toggle the visibility.
Why can't you just reuse the adapter? It's got plenty of loading/unloading methods associated with it.
Yes, what Aleadam is saying; if you only have a couple of things why use a ListView? TextView would seem a much quicker way to prototype data display!
I'm reading the book 'Hello, Android'. In the Sudoku example, it uses a options menu. It needs a MenuInflater that we use to read the menu definition from XML and turns it into a real view.
To use button, textview, or many other views, I don't need to inflate them.
My question is, in what situations, I need inflaters? Why doesn't Android treat menus like other views?
You need an inflater at every place that you want to dynamically create a view out of an XML file.
Activity layouts are automatically inflated when you call setContentView() as they're always required.
But when the menu is required — which is only when the user first presses the Menu button — the XML-defined layout needs to be manually inflated.
Similarly, if you have a ListView, you don't know in advance what rows will exist, so we have to inflate a View from XML for each row in the list, as they're required.
Inflaters are mainly used for parsing Xml layout into view objects. As mentioned above the inflation is needed for making a link between the UI defined in the Xml for manipulating and making developer.
Whenever UI Updation is needed we need inflation and UI Updation is done through view object and developer can dynamically create view and add to existing view.
Hence inflation helps developer to change behaviour of UI in xml layout according to specified condition in a program.
With inflation, we are able define controllers in MVC for each xml layout where xml is view.
Menu is also a view it has to inflated In certain code such setContentView(specifiedLayout) includes inflation
But in earlier version it was not like this it was like setContextView(getInflater().inflate(specifiedLayout))
for ease of programming,android developers have incorporated inflation in setContentview() and there are lot scenarios like add view to layout addView(),etc..In most cases inflation has incorporated in code that why most of beginner does know inflation concept and has difficulties in understanding inflation in android.
I have to dynamically add a list of views (the views use RelativeLayout). Can I do this by specifying the view definition in xml and instantiate multiple objects off it? This gives the usual benefits of separating the view part from the code (for e.g., making it easy for the UI guys to alter things) or Is going the ArrayAdapter the suggested/only route?
are you saying that you want to do this?
View v1 = (View) findViewById(R.id.someView);
View v2 = (View) findViewById(R.id.someView);
If you do this, you will merely have 2 references to the same view; it does not create two separate View objects. However, if you want to make a vertical list of views, look into ListActivity. in this case you will make a layout xml that will be used for every item in the list. you will need to implement a ListAdapter, or use a SimpleArrayAdapter.
does that help?