I'm currently following Udacity android development free courses, but I got an idea about an app and wanted to try out some of the stuff I just learned.
My problem is the following; I was trying to make a ListView out of some FrameLayouts. I'm using this FrameLayouts as i dont want to create a list of strings, but a list of "Boxes" I just made up. I tried to use an ArrayAdapter template using frameLayouts but compiler says i need to use TextView. What can i do here?
The final idea is to get some engine like the one that shows up in this page. promedioponderado.herokuapp.com
Assuming you got a type you want to display, say something like this:
class Foo{
final int bar;
Foo(int bar){this.bar = bar;}
}
You can override the View getView(int position, View convertView, ViewGroup parent) method of your adapter and do something like this
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view= inflater.inflate(R.layout.your_frame_layout_thingy, parent, false);
EditText box= (EditText) view.findViewById(R.id.my_box);
box.setText("Value is" + getItem(position).bar);
and remember to return view
For more details, I recommend you take a look at how Adapters work, something like this seems to be a good starting point.
If you don't understanding what's the whole class Foo thing, I would recommend you look into Java fundamentals as starting Android programming without some basic understanding of Java is rather hard.
Related
I've started to learn mobile app development with Java and Kotlin (using Android Studio) and I'm stuck with something:
Ihave a kotlin class in a file, this is the code:
data class Clients (
val Id: Long,
val name: String,
val phoneNumber: List<String>,
val avatar: Uri?
);
and I have this code in the MainActivity(Java):
List<Clients> infos = InfosKt.retrieveAll(getApplicationContext());
My ListView code in my MainActivity:
ListView list_clients;
list_clients = findViewById(R.id.list_allclients);
I just want to know, How Can I put the data from List in a ListView ? The idea is that users see the Name and Phone numbers of all Clients.
Is there a way to convert the List in an Array ?
You need to put the actual items in the list - you do with with an Adapter, where you actually create a View and put the data in it.
There's an example on the Android developer site (not in Kotlin for some reason but you'll get the idea):
private class MyAdapter extends BaseAdapter {
// override other abstract methods here
#Override
public View getView(int position, View convertView, ViewGroup container) {
if (convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.list_item, container, false);
}
((TextView) convertView.findViewById(android.R.id.text1))
.setText(getItem(position));
return convertView;
}
}
What's basically happening is whenever the ListView needs to create an entry, it calls getView in the adapter. That inflates a list item layout, which you need to create - TextViews for your name and phone number, an ImageView for your avatar, that kind of thing.
Then you just find those views and fill them with your data - getItem is passing in a position value for the item's position in the list, so you use that to grab the right data object out of your array, and then you can set up your views to display it.
So you write that class, then call setAdapter(MyAdapter()) and the ListView will use it.
Someone recommended RecyclerViews instead, they are more efficient and the way you're supposed to do things, but they're also way more complicated. So I think this is the best way to learn the basic idea of making a layout, inflating it and filling it with data. Once you understand that, all the RecyclerView boilerplate will be a little easier to handle!
Hello i have a fully working code for my list adapter:
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.overview_item, null);
//getting id's
TextView name =(TextView)vi.findViewById(R.id.userUsername);
TextView date =(TextView)vi.findViewById(R.id.imageDate);
ImageView image=(ImageView)vi.findViewById(R.id.userImage);
ImageView avatar=(ImageView)vi.findViewById(R.id.userAvatar);
//setting text
name.setText(dataNames.get(position));
date.setText(dataDates.get(position));
//set image
Log.d("test: ", "Adapter wants to get picture");
imageLoader.DisplayImage(dataImage.get(position), image);
imageLoader.DisplayImage(dataAvatars.get(position), avatar);
return vi;
}
This code works perfect but the problem is this function runs everytime when you scroll throught the listview so whenever the lis item is getting in sight. And that's not what i want. i want it to do this function just once for every list item. This is because when your scrolling fast trought the list it has to load all images again so the loading image is showing and it keeps jumping because the loading image is another size then the image wich is getting loaded. I hope thay tou understand my question and can help me. Already thanks and if i'm not clear please ask my anything in the comments.
So short:
How do i run this code just once for every list-item and not everytime when it's getting in sight?
Your code might call findViewById() frequently during the scrolling of ListView, which can slow down performance. Even when the Adapter returns an inflated view for recycling, you still need to look up the elements and update them. A way around repeated use of findViewById() is to use the "view holder" design pattern.
Check this links:
1 - http://www.javacodegeeks.com/2013/09/android-viewholder-pattern-example.html
No, you should not. This is the way ListView works. Beside, you should use ViewHolder pattern for better performance.
If you still want to do this, you could remove check NULL with convertView. It will solve your problem, but lead to performance, I think.
I have to show some HTML with images from the internet in a ListView. The images are handled in a custom Html.ImageGetter. The problem is, I need the TextView available to download the images to inside. This leads to having to incorporate the HTML parsing inside the ArrayAdapter's getView method. But that method gets called very often by the Android system as it recycles and redraws elements.
How can I stop this recycling from happening? I assume I have to use a different flow. This is my current getView() method:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView view = new TextView(context);
CharSequence element = getItem(position);
CharSequence html = Html.fromHtml(element.toString(), new MessageImageGetter(context, view), null);
view.setText(html);
view.setPadding(12, 4, 12, 4);
return view;
}
Maybe a list-like behavior is possible without the use of ListView and ArrayAdapter, that doesn't recycle and redraw often.
How can I stop this recycling from happening?
You don't. You create a richer model object. Rather than having what appears to be a ListAdapter<String>, have a ListAdapter<Thing>, where:
Thing holds your existing string value (element)
Thing caches the Html.fromHtml() result
Your getView() gets the html CharSequence from the Thing and therefore can take advantage of caching
Feel free to substitute a more applicable noun than Thing, of course... :-)
I'm not sure if this is just something that is up to developer opinion but I am creating an android app and have a Listview that displays a custom view. My layout basically consists of a View (as an xml resource file and a class that derives from the view that is the root), a Domain Model object (has the data to be bound to the view) and an adapter which derives from BaseAdapter that binds the data from the Domain Model to the View in the getViewMethod as follows:
Model: SampleItem
Custom View: SampleView
Adapter: (code below)
public View getView(int position, View convertView, ViewGroup parent) {
SampleView sampleView;
SampleItem item = (SampleItem)getItem(position);
if(convertView == null) {
sampleView = new SampleView(_context);
}
else {
sampleView = (SampleView)convertView;
}
sampleView.setTitle(item.getTitle());
sampleView.setContentText(item.getContent());
sampleView.setItemRowNumer(item.getRowNumber());
... //etc
return sampleView;
}
This is how I've always seen it done, but I wonder is this the right way to do it.
My thought, coming from a different approach to data binding, is that the actual view class doesn't have a concept of what it's model is, and diverting the control to how data is bound to it to an adapter class that may not exist if moved elsewhere.
I was thinking that the custom view class has a reference to the object that is bound to it and in it's constructor it populates the view based on the data. So the adapter is essentially a shell class that only does this:
public View getView(int position, View convertView, ViewGroup parent) {
SampleView sampleView;
SampleItem item = (SampleItem)getItem(position);
if(convertView == null) {
sampleView = new SampleView(_context, item);
}
else {
sampleView = (SampleView)convertView;
}
return sampleView;
}
And the actual constructor for the view would know its model and populate itself as opposed to the Adapter doing work that seems outside of it's responsibility.
The adapter should do it. Two reasons.
1) CursorAdapter#bindView: it's defined in the framework. It's idiomatic and it will be what other android programmers would expect to see while reading your code. IMHO keeping things idiomatic improves code maintenance and legibility.
2) The way AdapterView classes work in android is that they reuse the Views returned from the adapter. This is so that a lot of new objects aren't created during scroll/flick/etc. animations and UI events. In order for that to work the AdapterView passes that View back to the adapter and expects that view to be reused. IMHO the intention and expectation is for the Adapter to handle updating and rebinding that View. If you attempt your method and keep the binding in the Views constructor then the only time data binding would happen would be in the constructor. You would then need to move that binding into a separate function possibly cluttering the class interface and with inheritance getting into other problems.
For me, I prefer that a View only care about how to display something. That's all the responsibilities I really want it to worry about. I think that's enough since some views can become quite complex. I like to leave it to other classes to worry about telling the View what it should be displaying and where that data should be coming from. Sometimes this means very simple bindings, i.e., calling toString() multiple times in a row. However, it decouples the data that is being displayed from the underling data which allows for one to change with the possibility of reusing the other.
I want to be able to access my ArrayAdapter's view:
public View getView(int position, View convertView, ViewGroup parent)
I'm not sure how I can access this:
View myView = myArrayAdapter.getView(myPosition, myView, ?);
I am not sure how I can get a ViewGroup parent?
Well as far as I understand you don't suppose to Adapter in general serves as a source to instance of AdapterView so getView contract is follows :
in params : inPosition,convertView,viewParent
result : View witch will be shown at position inPosition , you can use convertView to bind data to if it's not null, returned view will be attached to viewParent.
So if you want to acquire view that will be shown by adapter view at specific position, why don't just call
AdapterView<?> adapterView = getAdapterView();
View myView = adapterView.getChildAt(position);
If you want to change way of showing view at specific position you should use
Adapter myAdapter = getAdapter();
//change data inside adapter
myAdapter.notifyDataSetChanged();
Update:
Try adding a field to the data in the data set that holds the background resource/color to be used when returning the view, and in the getView do
holder.background = dataSet.get(position).getBackground()
If you don't know what I'm talking about with this holder thing, check How to load the Listview "smoothly" in android
Old:
I'd say the ListView containing the adapter is the parent ViewGroup.
Anyway, why don't you use the ListView containing the ArrayAdapter? The ListView is the container of the Views, rather than the adapter, that only holds the data collection and creates and returns Views on demand when the ListView asks for them (f.e, when scrolling). Even if you were able to fetch a view for the position X, I'd say that won't work, as the convertView you pass as a parameter is not the one the ListView is holding and showing.
Take into account that in a ListView there are at most 7-8 Views inflated at any given moment (I don't know the exact number), and what the ListView does is fill them in by calling the adapter's getview.
This said, to update a single row (a single view) you'll need to update the adapter's data collection. Then, speculating, try to get that View from the ListView and invalidate it, but I doubt this'll work.
I think these concepts are right, if they are wrong I'd be grateful if anyone corrects me.
Why do you want to update only one view at a time?