ListVIew in Fragment Very Laggy - java

I have a ViewPager with 3 fragments. The rightmost fragment has a ListView inside it. The problem is that on two weaker phones I tested this on, it works seemingly smooth and not laggy. However, when I test it on my Note 3, the transition from the middle fragment to this one is very laggy and over 300 frames are skipped according to the logcat. Also, if I lock the phone and then unlock it back onto the ListView it is very laggy to scroll or do anything, unless I swipe left twice to the leftmost fragment. This is my onCreateView, onAttach and onStart methods as well as the adapter below.
#Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
View view= inflater.inflate(R.layout.fragment_c,container,false);
mainalyout = (LinearLayout) view.findViewById(R.id.linear_layout_listview);
listView = (ListView) view.findViewById(R.id.followed_cities);
horizontal_scroll = (HorizontalScrollView) view.findViewById(R.id.horizontal_scroll_view);
swipe = (LinearLayout) view.findViewById(R.id.scroll_up);
layout = (LinearLayout) view.findViewById(R.id.scroll_view_layout);
swipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_refresh_layout);
return view;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
context = MyApp.getContext();
session = new SessionManager(context);
userString = session.getUserDetails();
username = userString.get("username");
viewPager = (ViewPager) activity.findViewById(R.id.pic_pager);
parent = (FragmentActivityTesting) activity;
username = userString.get("username");
queue = Volley.newRequestQueue(context);
followed_cities = session.getFollowedCities();
try {
citysearcher = (citysearcher) activity;
} catch(Exception e) {}
try {
slideshowready = (slideshowready) activity;
}catch (Exception e) {}
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onStart() {
super.onStart();
swipeRefreshLayout.setOnRefreshListener(this);
if (followed_cities.contains("")) {
followed_cities.clear();
}
if (getActivity().getIntent().getStringExtra("launcher").equals("add")) {
get_followed(username);
}
if (followed_cities.isEmpty()) {
followed_cities.add(new CityShort("","NONE"));
ArrayAdapter<CityShort> adapter = new EmptyAdapter();
adapterr = adapter;
listView.setAdapter(adapterr);
}
else {
ArrayAdapter<CityShort> adapter = new MyListAdapter();
adapterr = adapter;
listView.setAdapter(adapterr);
}
My adapter :
private class MyListAdapter extends ArrayAdapter<CityShort> {
public MyListAdapter() {
super(getActivity(), R.layout.followed_item, followed_cities);
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
itemView = convertView;
if (itemView == null) {
itemView = getActivity().getLayoutInflater().inflate(R.layout.followed_item, parent, false);
}
TextView city_name = (TextView) itemView.findViewById(R.id.followed_city_txt);
final String curr_city = followed_cities.get(position).getCityName();
city_name.setText(curr_city);
city_name.setTag(followed_cities.get(position).getCityId());
if (curr_city.length() > 15) {
city_name.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
}
listView.setOnTouchListener(swipeDetector);
return itemView;
}
#Override
public int getViewTypeCount() {
return getCount();
}
#Override
public int getItemViewType(int position) {
return position;
}
}

I saw you had 2 listviews (findViewById(R.id.followed_cities) and findViewById(R.id.horizontal_scroll_view)). The horizontal listview is not well-implemented for recycling items.
Consider a better official support solution with RecyclerView. It supports both vertical and horizontal and provides better performance (as least the number of frames skipped will be less than current listview).

Two things that I see:
1) You have several LinearLayouts. I'm not certain what your xml layout looks like, but if LinearLayouts are nested they can certainly reduce visual rendering time. RelativeLayouts are more efficient(though I do use LinearLayouts when I'm first writing the xml file, because it's a little less time consuming for me as a general setup, then to later go back and update to using RelativeLayout).
2) You're doing all of these calculations on your MainThread, which is also Android's GPU essentially. You might be interested in processing all of this on a separate thread, this will certainly reduce rendering time. Check out "extends AsyncTask" and "Intent Service".

Change these things and try if works..
ViewHolder holder = null;
if (convertView == null) {
holder = new ViewHolder();
convertView = getActivity().getLayoutInflater().inflate(R.layout.followed_item, parent, false);
city_name = (TextView) itemView.findViewById(R.id.followed_city_txt); //Make this class level variable
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}

Replace your adapter with this
package com.munk.gaanasync;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.view.LayoutInflater;
import java.util.zip.Inflater;
private class MyListAdapter extends ArrayAdapter<CityShort>
{
public MyListAdapter()
{
super(getActivity(), R.layout.followed_item, followed_cities);
mInflater = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
ViewHolder holder = null;
itemView = convertView;
if (itemView == null)
{
holder = new ViewHolder();
itemView = mInflater.inflate(R.layout.followed_item, parent, false);
holder.city_name = (TextView) itemView.findViewById(R.id.followed_city_txt);
itemView.setTag(holder);
}
else
{
holder = (Viewholder) itemView.getTag();
}
final String curr_city = followed_cities.get(position).getCityName();
holder.city_name.setText(curr_city);
holder.city_name.setTag(followed_cities.get(position).getCityId());
if (curr_city.length() > 15)
{
holder.city_name.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
}
listView.setOnTouchListener(swipeDetector);
return itemView;
}
public static class ViewHolder
{
public TextView city_name;
}
#Override
public int getViewTypeCount()
{
return getCount();
}
#Override
public int getItemViewType(int position)
{
return position;
}
private Inflater mInflater;
}

Related

Can't put an ArrayList in a ListView inside a CustomAdapter in Android Studio

I'm having a problem understanding how to finish this part of my code.
It's an app that searches a list of games with the help of an API.
Everything is working so far so good right now, but one final thing.
In the code, first of all I have a simple activity with an edit_text, a button and an empty list view that it is called "lv_listofgames".
Then, when I press the "search" button, I fill the "lv_listofgames" with a series of rows formed by an imageview, a listView called "list_item_text" and a button.
To this point everything is okay it seems.
Then I should just fill the "list_item_text" inside the "lv_listofgames" with the contents of an arraylist but I just can't make it happen. I tried in many ways but I'm stuck. I even tried using 2 adapters but the app crashed everytime or the "list_item_text" remained empty.
The arrayList is something like: [game_title='Name', release_date='date', platform=platform]
I seem so close to the solution but I just can't figure it out how to accomplish that. Im going crazy :(
tl;dr: problem: when I press the "search" button the arrayList content doesn't appear in the ListView "list_item_text".
Here is the code, tell me if something is wrong, thanks:
public class MainActovity extends AppCompatActivity {
EditText et_searchName;
Button btn_search;
ListView lv_listofgames;
ListView lv;
final GamesDataService gameDataService = new GamesDataService(MainActovity.this);
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
et_searchName = findViewById(R.id.et_searchName);
btn_search = findViewById(R.id.btn_search);
lv_listofgames= findViewById(R.id.lv_listofgames);
btn_search.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
gameDataService.getGameName(et_searchName.getText().toString(), new GamesDataService.searchGamesResponse() {
#Override
public void onError(String message) {
Toast.makeText(MainActovity.this, "Error", Toast.LENGTH_SHORT).show();
}
#Override
public void onResponse(List<GamesReportModel> gamesReportModels) {
List<GamesReportModel> newName = gamesReportModels;
List<String> stringsList = new ArrayList<>(newName.size());
for (Object object : newName) {
stringsList.add(Objects.toString(object, null));
}
System.out.println("stringsList:" + stringsList);
lv = (ListView) findViewById(R.id.lv_listofnames);
MyListAdapter adapter = new MyListAdapter(MainActovity.this, R.layout.details, stringsList);
lv.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
});
}
});
}
class MyListAdapter extends ArrayAdapter<String> {
private int layout;
public MyListAdapter(#NonNull Context context, int resource, #NonNull List<String> objects) {
super(context, resource, objects);
layout = resource;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
MainActovity.ViewHolder mainViewHolder = null;
if(convertView == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(layout, parent, false);
MainActovity.ViewHolder viewHolder = new MainActovity.ViewHolder();
viewHolder.thumbnail = (ImageView) convertView.findViewById(R.id.list_item_thumbnail);
viewHolder.title = (ListView) convertView.findViewById(R.id.list_item_text);
viewHolder.button = (Button) convertView.findViewById(R.id.list_item_btn);
convertView.setTag(viewHolder);
viewHolder.button.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
}
});
}
else {
mainViewHolder = (MainActovity.ViewHolder) convertView.getTag();
}
return convertView;
}
}
public class ViewHolder {
ImageView thumbnail;
ListView title;
Button button;
}
}
GamesReportModel:
public class GamesReportModel {
private String game_title;
private String release_date;
private String platform;
public GamesReportModel(String game_title, String release_date, String platform) {
this.game_title = game_title;
this.release_date = release_date;
this.platform = platform;
}
public GamesReportModel() {
}
#Override
public String toString() {
return "game_title='" + game_title + '\'' +
", release_date='" + release_date + '\'' +
", platform=" + platform;
}
public String getGame_title() {
return game_title;
}
public void setGame_title(String game_title) {
this.game_title = game_title;
}
public String getRelease_date() {
return release_date;
}
public void setRelease_date(String release_date) {
this.release_date = release_date;
}
public String getPlatform() {
return platform;
}
public void setPlatform(String platform) {
this.platform = platform;
}
}
There are two things you need to change in your code to get the desired effect.
In your row view layout (R.layout.details), replace the ListView with a TextView since you are just trying to show text for a given row (not a nested list inside each row). Then update the view holder to hold the correct view type as well
viewHolder.title = (TextView) convertView.findViewById(R.id.list_item_text);
//...
public class ViewHolder {
ImageView thumbnail;
TextView title;
Button button;
}
In the adapter's getView method you have to actually set the text to show for that row. You never set the text to show anywhere, which is why your rows are blank. That should look like this:
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
MainActovity.ViewHolder mainViewHolder = null;
if(convertView == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(layout, parent, false);
MainActovity.ViewHolder viewHolder = new MainActovity.ViewHolder();
viewHolder.thumbnail = (ImageView) convertView.findViewById(R.id.list_item_thumbnail);
viewHolder.title = (TextView) convertView.findViewById(R.id.list_item_text);
viewHolder.button = (Button) convertView.findViewById(R.id.list_item_btn);
convertView.setTag(viewHolder);
}
else {
mainViewHolder = (MainActovity.ViewHolder) convertView.getTag();
}
// Here, you need to set what values to show for this row - this
// is why your list is empty/blank
mainViewHolder.title.setText((String)getItem(position));
return convertView;
}

No Action while SmoothScrollToPosition in Custom List View

Hi I m using below code where when user touches the textview , list will be updated and touched list row will be in front of user.
public class AppAdapter extends BaseAdapter {
private LayoutInflater layoutInflater;
private List<AppList> listStorage;
private Context context;
SharedPreferences.Editor editor;
SharedPreferences sharedPreferences;
int pos = 0;
public AppAdapter(Context context, List<AppList> customizedListView) {
layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
listStorage = customizedListView;
this.context = context;
}
#Override
public int getCount() {
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
pos = sharedPreferences.getInt("pos", 0);
Log.e("POS",pos+"At Get cpiunt");
return listStorage.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
ViewHolder listViewHolder;
if (convertView == null) {
listViewHolder = new ViewHolder();
convertView = layoutInflater.inflate(R.layout.installed_app_list, parent, false);
listViewHolder.textInListView = (TextView) convertView.findViewById(R.id.list_app_name);
listViewHolder.imageInListView = (ImageView) convertView.findViewById(R.id.app_icon);
convertView.setTag(listViewHolder);
} else {
listViewHolder = (ViewHolder) convertView.getTag();
}
listViewHolder.textInListView.setText(listStorage.get(position).getName());
listViewHolder.imageInListView.setImageDrawable(listStorage.get(position).getIcon());
listViewHolder.textInListView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
editor.putInt("pos", position).apply();
Log.e("Pressed", position + "");
MainActivity.installedAppAdapter.notifyDataSetChanged();
Log.e("Saved", sharedPreferences.getInt("pos", 0) + "value");
}
});
if (pos != 0) {
MainActivity.userInstalledApps.setSelection(pos);
editor.putInt("pos",0).apply();
}
return convertView;
}
static class ViewHolder {
TextView textInListView;
ImageView imageInListView;
}
}
I read many questions but did not get clear picture about how to use SmoothScrolltopostion. Though I as per info got, I captured click position and retrieved during list load to set saved position of list to user.
If I use smoothscrolltoposition, there is no action, but if I use setselection as shown in above code, I could able to see the clicked item in top of view after reloading.
Why smoothscroll is not working and m I doing correct coding for required action. pls guide.

Access main activity view from fragment [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I have an activity that has container that contain fragments and this fragment has other fragments.
Now I want this second or child fragment to access views in main activity, but it returns null pointer exception.
class:
public class ImageListFragment extends AbsListViewBaseFragment implements ObservableScrollViewCallbacks {
public static final int INDEX = 0;
android.support.design.widget.FloatingActionButton mFab;
#Bind(R.id.ic_call)
ImageView mIcCall;
#Bind(R.id.ic_email)
ImageView mIcEmail;
#Bind(R.id.ic_forum)
ImageView mIcForum;
FabToolbar mFabToolbar;
ObservableListView mObservableListView;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fr_image_list, container, false);
listView = (ListView) rootView.findViewById(android.R.id.list);
((ListView) listView).setAdapter(new ImageAdapter(getActivity()));
final SubTaB mainActivity = (SubTaB)getActivity();
ButterKnife.bind(mainActivity);
//////////////// problem here
mFabToolbar = (FabToolbar) rootView.findViewById(R.id.fabtoolbar);
////////////////
getFragmentManager().findFragmentByTag("TAG");
// rootView.findViewById(R.id.fab);
mObservableListView = (ObservableListView)rootView.findViewById(android.R.id.list);
//
mObservableListView.setAdapter(this.listView.getAdapter());
mObservableListView.setScrollViewCallbacks(this);
mainActivity.mFab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(mainActivity.getApplicationContext(), "msg msg", Toast.LENGTH_LONG).show();
mainActivity.mFabToolbar.expandFab();
}
});
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
startImagePagerActivity(position);
}
});
return rootView;
}
#Override
public void onDestroy() {
super.onDestroy();
AnimateFirstDisplayListener.displayedImages.clear();
}
private static class ImageAdapter extends BaseAdapter {
private static final String[] IMAGE_URLS = Constants.IMAGES;
private LayoutInflater inflater;
private ImageLoadingListener animateFirstListener = new AnimateFirstDisplayListener();
private DisplayImageOptions options;
ImageAdapter(Context context) {
inflater = LayoutInflater.from(context);
options = new DisplayImageOptions.Builder()
.showImageOnLoading(R.drawable.ic_stub) // تغيير الفيو قبل تحميل الصورة
.showImageForEmptyUri(R.drawable.ic_empty) // لما الصورة فاضية
.showImageOnFail(R.drawable.ic_error) // عند الفشل
.cacheInMemory(true)
.cacheOnDisk(true)
.considerExifParams(true)
.displayer(new CircleBitmapDisplayer(Color.WHITE, 5))
.build();
}
#Override
public int getCount() {
return IMAGE_URLS.length;
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
final ViewHolder holder;
if (convertView == null) {
view = inflater.inflate(R.layout.item_list_image, parent, false);
holder = new ViewHolder();
holder.text = (TextView) view.findViewById(R.id.text);
holder.image = (ImageView) view.findViewById(R.id.image);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
holder.text.setText("Item " + (position + 1));
ImageLoader.getInstance().displayImage(IMAGE_URLS[position], holder.image, options, animateFirstListener);
return view;
}
}
static class ViewHolder {
TextView text;
ImageView image;
}
#Override
public void onScrollChanged(int i, boolean b, boolean b1) {
}
#Override
public void onDownMotionEvent() {
}
#Override
public void onUpOrCancelMotionEvent(ScrollState scrollState) {
Log.d("","Scroll scroll scroll");
if (scrollState == ScrollState.UP) {
mFabToolbar.slideOutFab();
} else if (scrollState == ScrollState.DOWN) {
mFabToolbar.slideInFab();
}
}
#OnClick(R.id.fab)
void onFabClick() {
mFabToolbar.expandFab();
}
#OnClick(R.id.call)
void onClickCall() {
iconAnim(mIcCall);
}
#OnClick(R.id.ic_email)
void onClickEmail() {
iconAnim(mIcEmail);
}
#OnClick(R.id.ic_forum)
void onClickForum() {
iconAnim(mIcForum);
}
private void iconAnim(View icon) {
Animator iconAnim = ObjectAnimator.ofPropertyValuesHolder(
icon,
PropertyValuesHolder.ofFloat("scaleX", 1f, 1.5f, 1f),
PropertyValuesHolder.ofFloat("scaleY", 1f, 1.5f, 1f));
iconAnim.start();
}
private static class AnimateFirstDisplayListener extends SimpleImageLoadingListener {
static final List<String> displayedImages = Collections.synchronizedList(new LinkedList<String>());
#Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
if (loadedImage != null) {
ImageView imageView = (ImageView) view;
boolean firstDisplay = !displayedImages.contains(imageUri);
if (firstDisplay) {
FadeInBitmapDisplayer.animate(imageView, 500);
displayedImages.add(imageUri);
}
}
}
}
}
It is not good practise to find and control a view in this way. Views can easily become detached from activities and cause unexpected exceptions.
You should rather look at using callbacks to communicate between fragments and activities if required. That way, it also keeps your code in the correct places - so the activity is the only one touching its own views and the fragment also only touches its own views. It merely tells the activity (via callbacks) that something has happened that the activity might want to know about. It also ensures that the fragments are completely self contained and can be easily reused.
You can read about how to implement callbacks here: http://developer.android.com/training/basics/fragments/communicating.html
Use EventBus to communicate between the activity and the fragment. riggarro suggestion is the correct way. But you can also able to update the base activity views using the EventBus.
For example we need to update a TextView text in a activity from the fragment, follow the steps.
First you need to add the following library as dependency to your project in build.gradle of your app.
compile 'de.greenrobot:eventbus:2.4.0'
First you need to create a Event Object class to communicate between the fragment and activity like below.
public class UpdateTextEvent {
private String sampleTextValue;
public UpdateTextEvent(String textValue) {
this.sampleTextValue = textValue;
}
public String getTextValue() {
return sampleTextValue;
}
}
You need to post a event to the event bus in the fragment to update the TextView in the activity.
public class TestingFragment extends Fragment{
private EventBus bus = EventBus.getDefault()
public TextingFragment(){}
public void onCreate(Bundle onSavedInstanceState){
super.onCreate(onSavedInstanceState);
}
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.sample_activity, parent, false);
...
Button b1 = (Button) v.findViewById(R.id.button1);
b1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//trigger a update to the activity
bus.post(new UpdateTextEvent("testing"));
}
});
}
}
After that you need to register the bus with the callback of the event in the activity like below.
public class MainActivity extends Activity{
private EventBus bus = EventBus.getDefault();
private TextView textView;
#Override
public void onCreate(Bundle onSavedInstanceState){
super.onCreate(onSavedInstanceState);
....
// The textview going to be updated on posting the event
textView = (TextView) findViewById(R.id.text1);
bus.register(this);
}
public void onEvent(UpdateTextEvent event){
textView.setText(event.getTextValue());
}
}
In this above example the onEvent method will be called when you post a event from the fragment..
Hope it will help you.

Refresh ListView Items upon button triggered

I was having some problem when trying to refresh the items in list view after the button was triggered. Here is how I populate the listview onCreate:
public class EventChat extends Fragment {
Context context;
View eventChat;
String userID, eventID;
private ListView listview;
public ArrayList<EventComment> _commentlist = new ArrayList<EventComment>();
TextView txtDisplayCommentBy, txtDisplayDateTime, txtDisplayCommentDesc,
txtEventChat;
Button btnChatSubmit;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
eventChat = inflater.inflate(R.layout.event_chat, container, false);
context = getActivity();
listview = (ListView) eventChat.findViewById(R.id.listview);
txtEventChat = (TextView) eventChat.findViewById(R.id.txtEventChat);
btnChatSubmit = (Button) eventChat.findViewById(R.id.btnChatSubmit);
btnChatSubmit.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
onSubmitChatClicked();
}
});
Intent i = getActivity().getIntent();
_commentlist = (ArrayList<EventComment>) i
.getSerializableExtra("eventCommentObj");
Event eventModel = (Event) i.getSerializableExtra("eventObj");
userID = "Gab";
eventID = eventModel.getEventID();
listview.setAdapter(new ListAdapter(getActivity()));
return eventChat;
}
private class ListAdapter extends BaseAdapter {
LayoutInflater inflater;
ViewHolder viewHolder;
public ListAdapter(Context context) {
inflater = LayoutInflater.from(context);
}
public int getCount() {
return _commentlist.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = inflater.inflate(R.layout.eventchat_listview_row,
null);
viewHolder = new ViewHolder();
viewHolder.txt_dcommentBy = (TextView) convertView
.findViewById(R.id.txtDisplayCommentBy);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.txt_dcommentBy.setText(_commentlist.get(position)
.getCommentBy().trim());
return convertView;
}
}
private class ViewHolder {
TextView txt_dcommentBy;
TextView txt_ddateTime;
TextView txt_dcommentDesc;
}
}
When my button was triggered and insert a new record into database, at the same time, I wanted the list view items to be refreshed:
public void onSubmitChatClicked() {
EventComment commentModel = new EventComment();
String currentDate = EventDateTime.getCurrentDate();
String currentTime = EventDateTime.getCurrentTime();
String commentDesc = String.valueOf(txtEventChat.getText());
commentModel.setCommentBy(userID);
commentModel.setEventID(eventID);
commentModel.setCommentDate(currentDate);
commentModel.setCommentTime(currentTime);
commentModel.setCommentDesc(commentDesc);
new CreateCommentAsyncTask(context).execute(commentModel);
txtEventChat.setText("");
}
However, it does not refresh. Any ideas?
Thanks in advance.
Well this looks pretty straightforward.
First make your adapter a class member, so you can access it later:
private ListAdapter mAdapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
mAdapter = new ListAdapter(getActivity();
listview.setAdapter(mAdapter);
...
}
Then, when you submit the item, also add it to your ArrayList and update your adapter:
public void onSubmitChatClicked() {
EventComment commentModel = new EventComment();
String currentDate = EventDateTime.getCurrentDate();
String currentTime = EventDateTime.getCurrentTime();
String commentDesc = String.valueOf(txtEventChat.getText());
commentModel.setCommentBy(userID);
commentModel.setEventID(eventID);
commentModel.setCommentDate(currentDate);
commentModel.setCommentTime(currentTime);
commentModel.setCommentDesc(commentDesc);
// Add the new element to your DB
new CreateCommentAsyncTask(context).execute(commentModel);
// Add the new element to your current ArrayList
_commentlist.add(commentModel)
// Update theListView, by updating the adapter
mAdapter.notifyDataSetChanged();
txtEventChat.setText("");
}
EDIT:
Little more explanation:
When your fragment is created you are passed an array of EventComment items. I guess these are the elements from your DB. When you update the database, however, your ArrayList won't get updated, unless you reload the whole fragment. That's why you add the item to the DB, and to the list manually, and with notifyDataSetChanged, you force your adapter to update the ListView.
You cant do listview.setAdapter(new ListAdapter(getActivity())); to achieve this. You should create an instance of adapter and call adapter.add + adapter.notifyDataSetChanged
This is a very good tutorial :
http://www.vogella.com/tutorials/AndroidListView/article.html
http://www.javacodegeeks.com/2013/09/android-listview-with-adapter-example.html

ListView items reordering and repeating using baseadapter

I am trying to implement a listview that displays a list of directories. and under each directory is a gridview with associated adapter (shown below) showing a list of image thumbnails (see below image). I have it working great except whenever the list item is off the screen then brought back on screen, the images are reloaded. I am using an asynctask to download the thumbnails and replace the placeholder image for each imageview so it is not acceptable that everytime an item is offscreen, all of its thumbnails are downloaded again. Does anyone have an example of this type of implementation (gridview adapter within a listview adapter) where the imageview (or images) are stored? What is the proper way to do this?
Thanks in advance for your help.
Gallery Adapter
public class GalleryAdapter extends BaseAdapter {
private Context mContext;
ArrayList<GalleryItem> GalleryList;
//MediaAdapter adapter;
public GalleryAdapter(Context c,ArrayList<GalleryItem> l) {
mContext = c;
GalleryList = l;
}
public int getCount() {
return GalleryList.size();
}
public Object getItem(int position) {
return GalleryList.get(position);
}
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
GalleryViewHolder viewHolder = null;
if(convertView==null){
// inflate the layout
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
convertView = inflater.inflate(R.layout.gallery_item, parent, false);
viewHolder = new GalleryViewHolder();
viewHolder.title = (TextView) convertView.findViewById(R.id.title);
viewHolder.folder_settings = (ImageView) convertView.findViewById(R.id.folder_settings);
viewHolder.mediaGrid = (GridView) convertView.findViewById(R.id.imagegrid);
viewHolder.gridHolder = (LinearLayout) convertView.findViewById(R.id.gridholder);
convertView.setTag(viewHolder);
}
else{
viewHolder = (GalleryViewHolder) convertView.getTag();
}
viewHolder.title.setText(GalleryList.get(position).getTitle());
//Formatting the gridView to fit the screen dim.
ImageTools mWidth = new ImageTools(mContext);
viewHolder.mediaGrid.setColumnWidth(mWidth.imageSize());
int rows = (int) Math.ceil((GalleryList.get(position).getMedia().size() / mWidth.columnNumber)+1);
LinearLayout.LayoutParams labelLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, mWidth.imageSize()*rows);
viewHolder.gridHolder.setLayoutParams(labelLayoutParams);
viewHolder.mediaGrid.setLayoutParams(labelLayoutParams);
viewHolder.mediaGrid.setMinimumHeight(mWidth.imageSize()*rows);
//Set Adapter for image views
viewHolder.mediaGrid.setAdapter(new MediaAdapter(convertView.getContext(),GalleryList.get(position).getMedia()));
viewHolder.folder_settings.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Dialogs.createListDialog(mContext,"Folder Actions", R.array.gallery_action_array).show();
}
});
viewHolder.mediaGrid.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
}
});
return convertView;
}
private class GalleryViewHolder {
private TextView title;
private ArrayList<ImageView> imageList;
private GridView mediaGrid;
private ImageView folder_settings;
private LinearLayout gridHolder;
private int position;
}
}
Media Adapter
public class MediaAdapter extends BaseAdapter {
private Context mContext;
ArrayList<MediaItem> mediaitems;
public MediaAdapter(Context c,ArrayList<MediaItem> l) {
mContext = c;
mediaitems = l;
}
public int getCount() {
return mediaitems.size();
}
public Object getItem(int position) {
return mediaitems.get(position);
}
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) { // if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setImageResource(R.drawable.loading);
imageView.setTag(R.integer.path,mediaitems.get(position).getPath().toString());
imageView.setTag(R.integer.fullsize,"false");
imageView.setTag(R.integer.parentpath,mediaitems.get(position).getParentPath().toString());
imageView.setTag(R.integer.index , String.valueOf(position));
try {
new thumbDownload(mContext).execute(imageView);
} catch (DbxException e) {
e.printStackTrace();
}
ImageTools mWidth = new ImageTools(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(mWidth.imageSize(), mWidth.imageSize()));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
} else {
imageView = (ImageView) convertView;
}
//imageView.setImageBitmap(mediaitems.get(position).getBitmap());
return imageView;
}
}
Try with this..may be its silly way, but its worked for me. Just add a line of code inside your method like this for gallery adapter:
public View getView(int position, View convertView, ViewGroup parent) {
GalleryViewHolder viewHolder = null;
// Add this line.
convertView = null;
if(convertView==null){
// inflate the layout
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
convertView = inflater.inflate(R.layout.gallery_item, parent, false);
viewHolder = new GalleryViewHolder();
viewHolder.title = (TextView) convertView.findViewById(R.id.title);
viewHolder.folder_settings = (ImageView) convertView.findViewById(R.id.folder_settings);
viewHolder.mediaGrid = (GridView) convertView.findViewById(R.id.imagegrid);
viewHolder.gridHolder = (LinearLayout) convertView.findViewById(R.id.gridholder);
convertView.setTag(viewHolder);
}
else{
viewHolder = (GalleryViewHolder) convertView.getTag();
}
// rest of your code
}
You can use StickyGridHeaders to implement your UI and Android-Universal-Image-Loader for flexible asynchronous image loading.
StickyGridHeaders is an Android library that provides a GridView that shows items in sections with headers. By default the section headers stick to the top like the People app in Android 4.x but this can be turned off.
Android-Universal-Image-Loader aims to provide a reusable instrument for asynchronous image loading, caching and displaying.
I ended up Using a HashMap<String,Bitmap> to store the images once they were downloaded. I made the hashMap static in my mediaAdapter so I could add the bitmap from my asynctask when it was downloaded. Then in my media Adapter getView(), I added a if statement to check if the image had already been downloaded. If it had, I used setImageBitmap(myHash.get(key)).

Categories