Why my ViewPager is so slow? - android

Inside the dialogFragment I have viewPager with two pages. Every page contains a custom adapter. One adapter with list of spinners, other adapter with list of EditTexts. ViewPager adds adapters fine.
public class PageFragment extends Fragment {
...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.pagefragment_newprod, null);
LinearLayout ll=(LinearLayout) view.findViewById(R.id.tvLL);
ListView listView=new ListView(getActivity());
ll.addView(listView);
if (pageNumber==0){
dropDownAdapter=new DropDownAdapter(getActivity(), fillListAdapter);
listView.setAdapter(dropDownAdapter);
} else if (pageNumber==1){
boxAdapter = new BoxAdapter(getActivity(), filledFields);
listView.setAdapter(boxAdapter);
}
return view;
}
}
But it works to slow! Current Adapter (I mean at the curren page) create views every milisecond! Look at this:
public class BoxAdapter extends BaseAdapter{
...
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (view == null) {
view = lInflater.inflate(R.layout.addproduct_item, parent, false);
}
Log.d(LOG_TAG, "====As I said every milisecond...======");
EditText editText = (EditText) view.findViewById(R.id.addProductEditText);
editText.setText(p.value);
return view;
}
}
Even when I focused the EditText this Log.d write messages every milisecond!
Besides that, adapter at the next page works too. I have other Log.d at the other adapter getView and it works when I used different page's adapter!
Please help me to understand what is wrong...(

The question has already been solved in the comments. The solution for the OP was apparently to remove complex fragments and their adapter. However, I also had complex fragments in a tab layout with a ViewPager, and the following solution fixed the slow paging problem:
viewPager.setOffscreenPageLimit(2);
The 2 will keep two pages away from the current page in memory. This was enough for me because I had three tabs. Be careful about keeping too many pages in memory, though. See the documentation.

Related

ListView onItemClick not called

I've seen all the related questions, and tried their answers. I have a ListView inside a fragment and it's onItemClick method is called when inside one activity, but not called when in another one. Everything else is the same. I've tried:
Changing android:clickable explicitly.
Changing android:focusable and android:focusableInTouchMode explicitly.
Calling listView.setItemsCanFocus.
Adding android:descendantFocusability="blocksDescendants" attribute both on fragment and activity root.
Still, it's not working. It's the same fragment with same adapter, which doesn't have conditionals about being in which activity. However, in one activity it works perfectly, and in another, onItemClick is not called. I'm on ICS. Why would this happen?
UPDATE:
Here is the relevant code in my fragment:
dataSource = (ArrayList<Map<String, Object>>) task.getResult();
FeedAdapter adapter = new FeedAdapter(getActivity(), dataSource, getUser());
ListView list = (ListView) rootView.findViewById(R.id.listView);
list.setItemsCanFocus(true);
 //just trying these
list.setOnItemClickListener(self);
list.setAdapter(adapter);
adapter.notifyDataSetChanged();
if (dataSource.size() == 0) {
noPostsLabel.setVisibility(View.VISIBLE);
}
And in my adapter:
public View getView(int position, View convertView, ViewGroup parent) {
View view;
final Map<String, Object> post = objects.get(position);
LayoutInflater inflater = LayoutInflater.from(getContext());
if (convertView == null || convertView.getId() == R.id.headerRoot) {
view = inflater.inflate(R.layout.list_item_post_layout, parent, false);
} else {
view = convertView;
}
view.setClickable(false); //just trying these two now, they weren't here originally
view.setFocusable(false);
//populate
view.setTag(post);
[...] //populate the cell. very long code, redacted.
return view;
}
UPDATE 2:
I've also realized some cells are also not selectable in my "working" activity too, when they have a visible HorizontalScrollView within the cell (I have file attaching feature and it's only visible when there are files. Otherwise, it's in GONE visibility state). I have no idea why it's causing such trouble.
UPDATE 3:
I've also found out that views inside the cell are responsive. It's just the cell view itself which is not taking input.
UPDATE 4:
I've ended up moving the tap handler logic to the cell layout itself, instead of relying on list view's handler. I know it's not a good practice but I had to meet a deadline. Besides, it's working pretty smooth now. I'm not closing/answering the question as the technical problem is still present and I haven't found a real solution to it. I've just used a workaround to meet my project deadline.
I am not sure of your problem and I don't see the full code to debug.
I'll submit a sample code which normally should work in a Fragment.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
ListView list = (ListView) view.findViewById(R.id.listView);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int positi on, long id) {
Log.d(TAG, "onItemClick");
}
});
Notes:
I don't use root or any other cached object. I use the view parameter for calling findViewById().
I don't know self also. Instead I instantiated a new view or AdapterView.
Have you tried setting callbacks for the fragments? That's the way Android recommends it. You can check out - https://developer.android.com/training/basics/fragments/communicating.html#Deliver

Show empty view for ArrayAdapter in Android

I've got a ListView in my application that's rendered in a ListFragment's onActivityCreated()using setListAdapter(). Passed in to this setListAdapter()are my implementation of ArrayAdapter. At some times this adapter can be empty, and that's fine, but at those moments I would like to show a message in the list telling that there are no items, instead of just an empty view. However I don't really know how to achieve this, as for I have researched most people to show lists in a ListActivityand by doing that you can setEmptyView() but this doesn't seem doable when using a ListFragment. Another way of doing this was to change view in the ListFragment if the ArrayAdapter has no item's in it, then change view to another showing the message, but this seems to me a bit hacky.
Whats really the proper way of doing what I want to achieve?
Tried to setEmptyView() to my ListView but that didn't work either, see code on how views are inflated in my ListFragment:
public class MyFragment extends ListFragment {
#SuppressLint("InflateParams")
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
ListView listView = (ListView) inflater.inflate(R.layout.my_list, null);
listView.setEmptyView(inflater.inflate(R.layout.list_items_missing, null));
return listView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
MyItemArrayAdapter adapter = new MyItemArrayAdapter(getActivity());
// Populate adapter with items...
setListAdapter(adapter);
}
}
Shouldn't this result in the empty view beeing shown if no items exists in my adapter?
1) Try putting backgroundImage for ListView inside xml. If no item, show backgroundImage, if there is item, put background color.
2) You can also do what as #kgandroid suggested and here, setEmptyView() which you set custom view.
Example:
Another:
You can customize your adapter to show the layout R.layout.list_items_missing when (item == null) instead of inflating the normal custom list item layout that you implement.
Something like this:
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder; //asuming you have this in your custom adapter
if (convertView == null) {
holder = new ViewHolder();
if(MyItemArrayList.get(position)!=null)
{
convertView = this.inflater.inflate(R.layout.layout_list_item,
parent, false);
else
{
convertView = this.inflater.inflate(R.layout.list_items_missing,
parent, false);
}
//the rest of the adapter logic
}

How to change the background of a listview in android based on it's position in the list?

I have a listview that is populated via an adapter. I need one of the items (which are just bits of text) in the listview to have a different background compared to the others (to mark it as the currently selected one).
I have all of the background logic, I just need a way to say listview.setBackgroundById(int position)
or something like that.
How do I do this?
This needs to be as simple as possible, 'cause all of the other things done in the Activity are currently working perfectly. :)
As asked, this is my Adapter that I'm using:
public class SampleAdapter extends ArrayAdapter<SampleItem> {
private String title;
public SampleAdapter(Context context) {
super(context, 0);
}
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.row_station, null);
}
TextView title = (TextView)convertView.findViewById(R.id.station_name);
font.setFont(title, 2, getActivity());
title.setText(getItem(position).title);
RelativeLayout info = (RelativeLayout)convertView.findViewById(R.id.info_relative_button);
info.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
MainActivity.setCurrentTab(41);
MainActivity.setBackDisabled(true);
Log.e("current tab:",String.valueOf(MainActivity.getCurrentTab()));
Fragment fragment = new StationInfo();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();
UserManager.getInstance().setStationId(getItem(position).id);
}
});
return convertView;
}
}
The SampleItem has 2 String fields, title and id, it's very simple.
You need to use a custom list adapter and have it return views with your desired background. Create a class extending ListAdapter or any of the existing SimpleAdapter etc and override getView to inflate a suitable view for your element, and add any logic you need to set the background of that view.
There is no way to tell the listview itself to decorate some of its elements by id or position.
Update: I just noticed you added the list adapter code.
Since you are already implementing getView, to change the background of your element simply call convertView.setBackgroundColor, or have two different views inflated depending on the situation.
(BTW it's really bad practice to call static methods on your activity like in your onClickListener.)
In ListView adapter:
#Override
public View getView(int position, View view, ViewGroup viewGroup) {
if(view==null)
....
//for example every even list item to be grey, every odd to be white
if(((position+1)%2)==0)
view.setBackgroundColor(mContext.getResources().getColor(R.color.grey));
else view.setBackgroundColor(mContext.getResources().getColor(android.R.color.white));
Hope you get an idea...

combining paging and list of android in one view

I am new in programming to android now my work is paused as I am not getting how to accomplish the following I want to create a view which will have paging capability and in the view there would be textview to display the name of person and a list of name of all his relatives .... And the list can be long so it should be scrollable... I know to do paging and list independently but do not know how to combine the both in one view.... I hope I am clear with my question... So guys help me how to accomplish this...
I know to do paging and list independently but do not know how to combine the both in one view
So you can create xml like this :
Linear Layout/ Relative layout
Text View
List View
Put this XML in fragment
EDIT :
public class Fragment1test extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
//This layout contains your list view
View view = inflater.inflate(R.layout.your_view_xml, container, false);
//now you must initialize your list view
Listview listview =(Listview)view.findViewById(R.id.your_listview);
//Here items must be a List<Items> according to your class instead of String[] array
ListAdapter listadapter = new ListAdapter(getActivity(), android.R.layout.simple_list_item_1, items)
ListView.setAdapter( listAdapter());
//getActivty is used instead of Context
return view;
}
}

Add fragment into listview item

I want to have a fragment for each item in a listview, because I want to separate some logic out. I am using a view holder for each item. If the view doesn't exist, I create a new fragment and add it into the container.
holder.mMyFragment = new MyFragment(mActivity, this);
mActivity.getSupportFragmentManager().beginTransaction().add(R.id.my_container, holder.mMyFragment).commit();
Also for each item, I call holder.mMyFragment.setUi(dataSource, position) to set UI of the fragment based on the data source and position.
The problem I'm having is I initialize the UI elements of fragment in onCreateView method of the fragment class, but it's not called when I add the fragment to the item. So later when I call setUi() which uses some UI elements in fragment it complains a NullPointerException. Does anyone have a suggestion? Thanks!
"THERE IS A SOLUTION" for this.
The issue is, you cannot add fragment directly to the container(FrameLayout) with same "id" in listview as you have done in the above code.
The trick is, create listview(Recyclerview) of "LinearLayout". Then dynamically create FrameLayout in adapter and assign different id's for each. Inflate Fragment to FrameLayout and this FrameLayout to LinearLayout.
#Override
protected void onBindBasicItemView(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof VideoHomeViewHolder) {
VideoHomeViewHolder videoHomeViewHolder = (VideoHomeViewHolder) holder;
FrameLayout frameLayout = new FrameLayout(mContext);
frameLayout.setId(position+1); //since id cannot be zero
FragmentHelper.popBackStackAndReplace(mFragmentManager, frameLayout.getId(),
new ShowLatestVideosFragment(mShowLatestVideosItems.get(position)));
videoHomeViewHolder.linearLayout.addView(frameLayout);
}
}
I want to have a fragment for each item in a listview, because I want to separate some logic out.
You can't use fragment as list item views because the API doesn't allow you - View and Fragment aren't even related so there's no way you can use it like that. Make custom views and use adapter getViewTypeCount and getView to use different list item behavior.
Fragment are managed by Activity's FragmentManager or by other Fragments child FragmentManager; while list item views are managed by ListView & ListAdapter. You can use ListViews in Fragments, but not the other way around.
A simple way.
One problem:You should store add restore fragment state.
holder.mMyFragment = new MyFragment(mActivity, this);
int id = View.generateViewId();
findViewByTag("abc").setId(id);
mActivity.getSupportFragmentManager().beginTransaction().add(id, holder.mMyFragment).commit();
Hi I was facing the same problem and I found the way to do it.
My problem was similar to you:
"I want to have a fragment for each item in a listview, because I want to separate some logic out"
In my app I have to give the option to display custom items in vertical (listView) and horizontal (ViewPager) mode. Additionally I had to deal with 18 custom items and each one with different logic, so the best approach was reusing the fragments that I was using for ViewPager in ListView.
I got it but not in the way you were trying, I mean, I used my fragments like "ViewHolders":
Define fragment's widget like variables of class in each fragment.
Create a custom ArrayAdapter and override: getViewTypeCount(), getItemViewType(int position), getCount(), getItem(int position) getView(int position, View convertView, ViewGroup parent)
In getView I checked what kind of layout I needed before "inflate" the respective XML, create a fragment, assign widget from XML to fragment (with rootView.findViewById) and set "tag" with the new fragment.
What you can see at this point is that fragments in ListView never got attached to Activity but you got what you wanted: logic distributed in several parts and all benefits of ListView (reuse of rows, scroll, etc).
If you need I can post part of my code but you have to deal with "spanglish" ;).
UPDATED
All the problem is because when you create a Fragment to be used with ViewPager, usually all "layout and "setup" code is inside onCreateView method, I mean:
Get the view object you are going to use (View rootView = inflater.inflate(R.layout.fragment_question_horizontal_container, container, false);)
Get the widgets from above layout, define behaviors, fonts, etc: (answer = (EditText)rootView.findViewById(R.id.answer_question_text);)
Until this point there is nothing weird.
If you are going to use a fragment with the behavior described above you have to "emulate" the call to onCreateView, fill the data and attach it to the listView.
Here is the trick: split the code in onCreateView in some methods that doesn't care about who's calling them. An example of my onCreateView:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_pregunta_horizontal_container, container, false);
addAnswerLayout(rootView, R.layout.fragment_pregunta_texto, getActivity());
setUpComponents(rootView);
//those 2 methods are about my app logic so I'm not going to talk much about them
setUpQuestionState(savedInstanceState);
readSavedAnswer();
return rootView;
}
public void addAnswerLayout(View rootView, int optionId, Context context) {
mContext = context;
RelativeLayout relativeLayout = (RelativeLayout)rootView.findViewById(R.id.pregunta_container);
LayoutInflater inflater = ((Activity)mContext).getLayoutInflater();
View newView = inflater.inflate(optionId, relativeLayout, false);
relativeLayout.addView(newView);
}
public void setUpComponents(View rootView) {
//next line: some heritage that you can ignore
super.setUpComponents(rootView);
respuesta = (EditText)rootView.findViewById(R.id.pregunta_respuesta_texto);
respuesta.setTypeface(UiHelper.getInstance(getActivity()).typeface);
respuesta.setTextColor(mContext.getResources().getColor(R.color.drs_gris));
...
}
Now let's go to the CustomArrayAdapter for list view:
Define your customArrayAdapter something like this: PreguntasVerticalArrayAdapter extends ArrayAdapter<Pregunta> where "Pregunta" is a generic Fragment with the logic from above.
Override getViewTypeCount(), getItemViewType(int position), getCount(), getItem(int position) getView(int position, View convertView, ViewGroup parent).
The getView follow the same behavior: get the object for the given position in params, reuse a "viewholder" and fill the data. Here my getView:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
Pregunta pregunta = mData.get(position);
if (rowView == null)
rowView = createQuestionUI(pregunta, parent, position);
fillDataInRow((PreguntaUI)rowView.getTag(), pregunta, position);
return rowView;
}
private View createPreguntaUI(Pregunta pregunta, ViewGroup parent, int position) {
View rootView = null;
LayoutInflater inflater = (mPreguntasVerticalFragment.getActivity()).getLayoutInflater();
//you can ignore this part of the code ralted to Bundle.
Bundle args = new Bundle();
args.putLong(PreguntaUI.PREGUNTAUI_ID, pregunta.getIdpregunta());
args.putInt(PreguntaUI.PREGUNTAUI_INDEX, position);
args.putInt(PreguntaUI.PREGUNTAUI_TOTAL_QUESTIONS, getCount());
//internal method of "pregunta" to know what kind of question it is.
String tipo = pregunta.getTipo();
if (tipo.equalsIgnoreCase(PreguntaType.TEXT.toString())) {
rootView = inflater.inflate(R.layout.fragment_pregunta_vertical_container, parent, false);
Pregunta_texto pregunta_texto = new Pregunta_texto();
pregunta_texto.setArguments(args);
//LOOK AT THIS POINT!!!: I'm calling the same methods that I called in onCreateView fragment's method.
pregunta_texto.addAnswerLayout(rootView, R.layout.fragment_pregunta_texto,
mPreguntasVerticalFragment.getActivity());
pregunta_texto.setUpComponents(rootView);
pregunta_texto.setUpQuestionState(null);
pregunta_texto.readSavedAnswer();
//I'm adding the fragment to reuse it when I can
rootView.setTag(pregunta_texto);
}
else if ...
return rootView;
}
That is all... at this point, if you have enough experience dealing with CustomArrayAdapters and Fragments you probably got it! :D
From the Android Documentation : "A Fragment represents a behavior or a portion of user interface in an Activity. You can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities."
For your activity, do you want to add 2 fragments where the first one displays a listView (= ListFragment and the other one is in the right and is shown only when the user clicks on an item (from the first fragment or listView) ?
Instead of using ListFragment, you can use RecyclerView, Android has documentation on that:
https://developer.android.com/training/basics/fragments/creating.html#AddInLayout

Categories

Resources