From what I can gather it appears that this might be because my ListView is not being displayed, I've verified that getCount is returning a value not zero, but I can't see what I'm doing wrong.
Everything loads and acts like it's working but the ListView never appears, I put a background color on the fragment reference in mixed.xml and it is there and taking up the full screen, but when I set a background color on my ListView it does not appear, it's like it's not being rendered at all.
More odd, getView is not being called in my adapter, and this is all working code from regular activities that I ported to fragments.
I've tried calling notifyDataSetChanged which didn't changed anything, debugging shows the adapter is filled with data and getCount is indeed returning an accurate count greater than 0.
Thanks for any help, I'm stuck.
Project is open and can be viewed here http://code.google.com/p/shack-droid/source/browse/#svn%2FTrunk but I'm also including the pertinent code here.
This is the ListFragment:
public class FragmentTopicView extends ListFragment implements ShackGestureEvent {
private ArrayList<ShackPost> posts;
private String storyID = null;
private String errorText = "";
private Integer currentPage = 1;
private Integer storyPages = 1;
private String loadStoryID = null;
private Boolean threadLoaded = true;
private Hashtable<String, String> postCounts = null;
private AdapterLimerifficTopic tva;
public FragmentTopicView() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.topics, null);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final ShackGestureListener listener = Helper.setGestureEnabledContentView(R.layout.topics, getActivity());
if (listener != null) {
listener.addListener(this);
}
if (savedInstanceState == null) {
// get the list of topics
GetChattyAsyncTask chatty = new GetChattyAsyncTask(getActivity());
chatty.execute();
}
ListView lv = getListView();
lv.setOnScrollListener(new OnScrollListener() {
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// start loading the next page
if (threadLoaded && firstVisibleItem + visibleItemCount >= totalItemCount && currentPage + 1 <= storyPages) {
// get the list of topics
currentPage++;
GetChattyAsyncTask chatty = new GetChattyAsyncTask(getActivity());
chatty.execute();
}
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
});
}
class GetChattyAsyncTask extends AsyncTask<String, Void, Void> {
protected ProgressDialog dialog;
protected Context c;
public GetChattyAsyncTask(Context context) {
this.c = context;
}
#Override
protected Void doInBackground(String... params) {
threadLoaded = false;
try {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
final String feedURL = prefs.getString("shackFeedURL", getString(R.string.default_api));
final URL url;
if (loadStoryID != null) {
if (currentPage > 1)
url = new URL(feedURL + "/" + loadStoryID + "." + currentPage.toString() + ".xml");
else
url = new URL(feedURL + "/" + loadStoryID + ".xml");
}
else {
if (currentPage > 1)
url = new URL(feedURL + "/" + storyID + "." + currentPage.toString() + ".xml");
else
url = new URL(feedURL + "/index.xml");
}
// Get a SAXParser from the SAXPArserFactory.
final SAXParserFactory spf = SAXParserFactory.newInstance();
final SAXParser sp = spf.newSAXParser();
// Get the XMLReader of the SAXParser we created.
final XMLReader xr = sp.getXMLReader();
// Create a new ContentHandler and apply it to the XML-Reader
SaxHandlerTopicView saxHandler = new SaxHandlerTopicView(c, "topic");
xr.setContentHandler(saxHandler);
// Parse the xml-data from our URL.
xr.parse(new InputSource(HttpHelper.HttpRequestWithGzip(url.toString(), c)));
// Our ExampleHandler now provides the parsed data to us.
if (posts == null) {
posts = saxHandler.GetParsedPosts();
}
else {
ArrayList<ShackPost> newPosts = saxHandler.GetParsedPosts();
newPosts.removeAll(posts);
posts.addAll(posts.size(), newPosts);
}
storyID = saxHandler.getStoryID();
storyPages = saxHandler.getStoryPageCount();
if (storyPages == 0) // XML returns a 0 for stories with only
// one page
storyPages = 1;
}
catch (Exception ex) {
// TODO: implement error handling
}
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
if (currentPage == 1)
dialog = ProgressDialog.show(getActivity(), null, "Loading Chatty", true, true);
else
SetLoaderVisibility(View.VISIBLE);
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
ShowData();
SetLoaderVisibility(View.GONE);
try {
dialog.dismiss();
}
catch (Exception e) {
}
}
}
private void ShowData() {
if (posts != null) {
Hashtable<String, String> tempHash = null;
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
final String login = prefs.getString("shackLogin", "");
final int fontSize = Integer.parseInt(prefs.getString("fontSize", "12"));
try {
postCounts = GetPostCache();
}
catch (Exception ex) {
}
if (postCounts != null)
tempHash = new Hashtable<String, String>(postCounts);
if (tva == null) {
tva = new AdapterLimerifficTopic(getActivity(), R.layout.lime_topic_row, posts, login, fontSize, tempHash);
setListAdapter(tva);
}
else {
tva.SetPosts(posts);
tva.notifyDataSetChanged();
}
final ListView lv = getListView();
lv.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
menu.setHeaderTitle("Options");
menu.add(0, 1, 0, "Copy Post Url to Clipboard");
menu.add(0, 2, 0, "Watch Thread");
menu.add(0, 3, 0, "Thread Expires In?");
menu.add(0, 4, 0, "Shacker's Chatty Profile");
}
});
// update the reply counts for the listing of topics
try {
UpdatePostCache();
}
catch (Exception e) {
}
}
else {
if (errorText.length() > 0) {
try {
new AlertDialog.Builder(getActivity()).setTitle("Error").setPositiveButton("OK", null).setMessage(errorText).show();
}
catch (Exception ex) {
// could not create a alert for the error for one reason
// or another
Log.e("ShackDroid", "Unable to create error alert ActivityTopicView:468");
}
}
}
threadLoaded = true;
}
}
Here's my FragmentActivity:
public class FragmentActivityTopic extends FragmentActivity {
#Override
protected void onCreate(Bundle arg) {
// TODO Auto-generated method stub
super.onCreate(arg);
setContentView(R.layout.mixed);
}
}
This is the Adapter I'm using, and as mentioned above getView is not being called:
public class AdapterLimerifficTopic extends BaseAdapter {
// private Context context;
private List<ShackPost> topicList;
private final int rowResouceID;
private final String shackLogin;
private final Typeface face;
private final int fontSize;
private final Hashtable<String, String> postCache;
private final String showAuthor;
private final Resources r;
private int totalNewPosts = 0;
LayoutInflater inflate;// = LayoutInflater.from(context);
public AdapterLimerifficTopic(Context context, int rowResouceID, List<ShackPost> topicList, String shackLogin, int fontSize, Hashtable<String, String> postCache) {
this.topicList = topicList;
this.rowResouceID = rowResouceID;
this.shackLogin = shackLogin;
this.fontSize = fontSize;
this.postCache = postCache;
this.r = context.getResources();
face = Typeface.createFromAsset(context.getAssets(), "fonts/arial.ttf");
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
showAuthor = prefs.getString("showAuthor", "count");
inflate = LayoutInflater.from(context);
}
public void SetPosts(List<ShackPost> posts)
{
topicList = posts;
}
#Override
public int getCount() {
return topicList.size();
}
#Override
public Object getItem(int position) {
return topicList.get(position);
}
#Override
public long getItemId(int position) {
// return position;
final ShackPost post = topicList.get(position);
return Long.parseLong(post.getPostID());
}
static class ViewHolder {
TextView posterName;
TextView datePosted;
TextView replyCount;
TextView newPosts;
TextView postText;
TextView viewCat;
RelativeLayout topicRow;
ImageView postTimer;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TextView tmp;
// final View v;
ViewHolder holder;
final ShackPost post = topicList.get(position);
if (convertView == null) {
convertView = inflate.inflate(rowResouceID, parent, false);
holder = new ViewHolder();
holder.posterName = (TextView) convertView.findViewById(R.id.TextViewLimeAuthor);
holder.datePosted = (TextView) convertView.findViewById(R.id.TextViewLimePostDate);
holder.replyCount = (TextView) convertView.findViewById(R.id.TextViewLimePosts);
holder.newPosts = (TextView) convertView.findViewById(R.id.TextViewLimeNewPosts);
holder.postText = (TextView) convertView.findViewById(R.id.TextViewLimePostText);
holder.viewCat = (TextView) convertView.findViewById(R.id.TextViewLimeModTag);
// holder.topicRow = (RelativeLayout) convertView.findViewById(R.id.TopicRow);
// holder.postTimer = (ImageView) convertView.findViewById(R.id.ImageViewTopicTimer);
// holder.posterName.setTypeface(face);
// holder.datePosted.setTypeface(face);
// holder.replyCount.setTypeface(face);
// holder.newPosts.setTypeface(face);
holder.postText.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
// holder.postText.setTypeface(face);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
// holder.postTimer.setImageResource(Helper.GetTimeLeftDrawable(post.getPostDate()));
//
holder.posterName.setText(post.getPosterName());
//
// if (shackLogin.equalsIgnoreCase(post.getPosterName()))
// holder.posterName.setTextColor(Color.parseColor("#00BFF3"));
// else
// holder.posterName.setTextColor(Color.parseColor("#ffba00"));
//
holder.datePosted.setText(Helper.FormatShackDateToTimePassed(post.getPostDate()));
holder.replyCount.setText(post.getReplyCount());
//
// if (showAuthor.equalsIgnoreCase("count") && post.getIsAuthorInThread())
// holder.replyCount.setTextColor(Color.parseColor("#0099CC"));
// else
// holder.replyCount.setTextColor(Color.parseColor("#FFFFFF"));
// clipped code
holder.postText.setText(preview);
// if (showAuthor.equalsIgnoreCase("topic") && post.getIsAuthorInThread()) {
// final Drawable d = r.getDrawable(R.drawable.background_gradient_blue);
// holder.topicRow.setBackgroundDrawable(d);
// }
// else
// holder.topicRow.setBackgroundDrawable(null);
// TODO: clean this up a little / also replicated in ShackDroidThread ick
final String postCat = post.getPostCategory();
holder.viewCat.setVisibility(View.VISIBLE);
if (postCat.equals("offtopic")) {
holder.viewCat.setText("offtopic");
holder.viewCat.setBackgroundColor(Color.parseColor("#444444"));
}
else if (postCat.equals("nws")) {
holder.viewCat.setText("nws");
holder.viewCat.setBackgroundColor(Color.parseColor("#CC0000"));
}
else if (postCat.equals("political")) {
holder.viewCat.setText("political");
holder.viewCat.setBackgroundColor(Color.parseColor("#FF8800"));
}
else if (postCat.equals("stupid")) {
holder.viewCat.setText("stupid");
holder.viewCat.setBackgroundColor(Color.parseColor("#669900"));
}
else if (postCat.equals("informative")) {
holder.viewCat.setText("interesting");
holder.viewCat.setBackgroundColor(Color.parseColor("#0099CC"));
}
else
holder.viewCat.setVisibility(View.GONE);
return convertView;
}
public int getTotalNewPosts() {
return totalNewPosts;
}
}
And related XML:
mixed.xml (this is the layout for the fragments, only the one for now)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:id="#+id/LinearLayoutMixed">
<fragment
android:id="#+id/MixedThreads"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
class="com.stonedonkey.shackdroid.FragmentTopicView"
>
</fragment>
</LinearLayout>
Topics.xml (this contains the ListView as well as a sliding tray and some other stuff.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ListView
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#+id/TopicLoader"
android:divider="#333333"
android:dividerHeight="1dip"
android:textColor="#FFFFFF"
/>
<RelativeLayout
android:id="#+id/TopicLoader"
android:layout_width="fill_parent"
android:layout_height="35dip"
android:layout_alignParentBottom="true"
android:gravity="center_horizontal"
android:visibility="gone"
android:layout_marginTop="5dip" >
<TextView
android:id="#+id/TextViewTopicLoaderText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="Loading"
>
</TextView>
<ImageView
android:id="#+id/ImageViewTopicLoader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/TextViewTopicLoaderText"
android:src="#drawable/ic_action_refresh"
android:layout_alignBottom="#+id/TextViewTopicLoaderText"
/>
</RelativeLayout>
<SlidingDrawer
android:id="#+id/SlidingDrawer01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#+id/TopicLoader"
android:animateOnClick="true"
android:content="#+id/bookMarkParent"
android:handle="#+id/TextViewTrayHandle"
android:orientation="vertical"
android:paddingTop="200dip"
android:visibility="gone" >
<TextView
android:id="#+id/TextViewTrayHandle"
android:layout_width="fill_parent"
android:layout_height="35dip"
android:background="#drawable/darkgrey_gradient"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center_vertical" >
</TextView>
<RelativeLayout
android:id="#id/bookMarkParent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ListView
android:id="#+id/ListViewWatchedThreads"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="#333333"
android:dividerHeight="1dip"
android:textColor="#FFFFFF" >
</ListView>
</RelativeLayout>
</SlidingDrawer>
</RelativeLayout>
and finally lime_topic_row which is my custom row layout for the ListView in the above layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#FF0000" >
<TextView
android:id="#+id/TextViewLimeModTag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#FF0000"
android:layout_alignParentLeft="true"
android:layout_marginLeft="10dip"
android:textColor="#000000"
android:padding="2dip"
android:textSize="10dip"
/>
<TextView
android:id="#+id/TextViewLimePostText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="20dip"
android:padding="10dip"
android:layout_below="#+id/TextViewLimeModTag"
android:textColor="#FFFFFF" />
<TextView
android:id="#+id/TextViewLimeAuthor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/TextViewLimePostText"
android:paddingBottom="10dip"
android:paddingLeft="10dip"
android:textColor="#0099CC" />
<TextView
android:id="#+id/TextViewPosted"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/TextViewLimePostText"
android:layout_toRightOf="#+id/TextViewLimeAuthor"
android:paddingBottom="10dip"
android:text=" posted " />
<TextView
android:id="#+id/TextViewLimePostDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/TextViewLimePostText"
android:layout_toRightOf="#+id/TextViewPosted"
android:paddingBottom="10dip"
android:paddingRight="10dip"
android:textColor="#FF8800" />
<TextView
android:id="#+id/TextViewLimePosts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/TextViewLimePostDate"
android:layout_marginRight="3dip"
android:layout_below="#+id/TextViewLimePostText"
android:layout_marginBottom="15dip"
android:layout_toLeftOf="#+id/TextViewLimeNewPosts"
android:background="#BBBBBB"
android:padding="3dip"
android:minWidth="25dip"
android:gravity="center"
android:textColor="#000000" />
<TextView
android:id="#+id/TextViewLimeNewPosts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/TextViewLimePostDate"
android:layout_below="#+id/TextViewLimePostText"
android:layout_marginBottom="15dip"
android:layout_marginRight="10dip"
android:background="#669900"
android:padding="3dip"
android:minWidth="25dip"
android:gravity="center"
android:layout_alignParentRight="true"
android:textColor="#000000" />
</RelativeLayout>
I think I found the problem. The issue appears because of the ShackGestureListener that you setup at the start of the onActivityCreated method in the FragmentTopicView:
final ShackGestureListener listener = Helper.setGestureEnabledContentView(R.layout.topics, getActivity());
if (listener != null) {
listener.addListener(this);
}
In the setGestureEnabledContentView() method you check to see if the user enabled the gestures in the preferences or if the android version is bigger then 3. Either way, true or false you set the content view for the FragmentActivityTopic again(with the layout of the FragmentTopicView). Setting the content view again will, unfortunately, cover the current layout which holds the ListView with data(ListView that populates with no problems). When you run those AsyncTasks to get the data, at the end you set the data on the correct ListView(returned by getListView) because the getListView will hold a reference to the old correct ListView which was set in the onCreateView method, but you don't see anything because in the setGestureEnabledContentView you cover this ListView.
This behavior is easy to see if you simple comment out(or remove) the lines that set the content view for the activity in the Helper and HelperAPI4 classes. Another way to see that your ListView is covered is, for example to set the adapter for the ListView(tva) using getListView and using the getActivity().findViewById(android.R.id.list)(I've done this on selecting one of your menus items, so I can control when I replace the adapter):
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent intent;
switch (item.getItemId())
{
case R.id.topic_menu_newpost: // Launch post form
//this doesn't work as the getListView will return a reference to the old ListView
ListView lv = getListView();
lv.setAdapter(tva);
// this will work as you get a reference to the new ListView on top
ListView lv = (ListView) getActivity().findViewById(android.R.id.list);
lv.setAdapter(tva);
I don't know what to recommend as a solution as I don't quite understand what you're doing, but I doubt that it requires to set the content view for the activity again(and you should work from this).
Related
I want to give a little context: The app I'm currently involved in helping develop is an app a company has already developed for IOS and Android but the Android developer didn't delivered the expected results (mostly performance wise) so the leader gave me the code to see if I could fix it. Given the code I tried to improve it, now, the app is a picture sharing app somewhat like Instagram and it uses and endless scrolling list, the problem with the app is that every time I scroll a little bit, the app lags or freezes for a second and then loads a new row.
The listview only has one row visible at any moment.
What have I tried?:
The adapter wasn't using the ViewHolder pattern so I tried to implement it.
The programmer was defining a lot of click listeners on the getView method so I removed them.
still, every time I scroll ( a new row appears as there's only one visible row at any time) it lags. Are there any other noticeable problems here that could be the cause?
On another note, on this view there's a lot of overdraw so, maybe it's affecting the performance on the ListView? if so, tell me and I'll post the XML part.
Here's the code I adapted:
public class SomeFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
// declaration and constructors.....
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
//initialization......
//setting variables.......
//getting views.....
listview = (ListView)rootView.findViewById(R.id.listview);
listview.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
int threshold = 1;
int count = listview.getCount();
if (scrollState == SCROLL_STATE_IDLE) {
if (listview.getLastVisiblePosition() >= count - threshold) {
int position = listview.getLastVisiblePosition();
if (!loading) {
loading = true;
listview.addFooterView(footerView, null, false);
currentVal = position + 1;
LoadMoreStuffAsyncTask loadMoreStuffAsyncTask = new LoadMoreStuffAsyncTask();
loadMoreStuffAsyncTask.execute();
}
}
}
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
int topRowVerticalPosition = (listview == null || listview.getChildCount() == 0) ? 0 : listview.getChildAt(0).getTop();
swipeRefreshLayout.setEnabled(firstVisibleItem == 0 && topRowVerticalPosition >= 0);
}
});
LoadStuffAsyncTask loadStuffAsyncTask=new LoadStuffAsyncTask();
loadStuffAsyncTask.execute();
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.activity, container, false);
swipeRefreshLayout = (SwipeRefreshLayout)rootView.findViewById(R.id.swipe);
swipeRefreshLayout.setOnRefreshListener(SomeFragment.this);
return rootView;
}
private void LoadStuff () {
list=null;
ParseQuery<ParseObject> query = null;
query = ParseQuery.getQuery("Objects");
query.orderByDescending("createdAt");
query.include("User");
query.setLimit(20);
try {
list = query.find();
} catch (ParseException e) {
e.printStackTrace();
}
}
private void LoadMoreStuff () {
List<ParseObject> moreList=null;
ParseQuery<ParseObject> query = null;
query = ParseQuery.getQuery("Objects");
query.orderByDescending("createdAt");
query.include("User");
query.setLimit(20);
query.setSkip(currentVal);
try {
moreList = query.find();
if(moreList!=null|| moreList.size()!=0){
for(int i =0;i<moreList.size();i++){
list.add(moreList.get(i));
}
}else{
loading=false;
}
} catch (ParseException e) {
e.printStackTrace();
loading=false;
}
}
#Override
public void onRefresh() {
swipeRefreshLayout.setRefreshing(true);
listAdapter.notifyDataSetChanged();
LoadStuffAsyncTask loadStuffAsyncTask=new LoadStuffAsyncTask();
loadStuffAsyncTask.execute();
}
class LoadMoreStuffAsyncTask extends AsyncTask<Void, Void, Void>{
private ProgressDialog pDialog;
#Override
protected Void doInBackground(Void... params) {
LoadMoreStuff();
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
listAdapter.updateList(list);
listview.setAdapter(listAdapter);
loading=false;
listview.removeFooterView(footerView);
listview.setSelection(currentVal);
}
}
class LoadStuffAsyncTask extends AsyncTask<Void, Void, Void>{
private ProgressDialog pDialog;
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(activity);
pDialog.setMessage(activity.getString(R.string.loading));
pDialog.setCancelable(false);
pDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
pDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
LoadStuff();
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
pDialog.dismiss();
swipeRefreshLayout.setRefreshing(false);
listAdapter = new CustomAdapter(activity,momentosGeneral);
listview.setAdapter(listAdapter);
}
}
}
This is the adapter:
public class CustomAdapter extends BaseAdapter {
//declaration of variables.....
public CustomAdapter(ActionBarActivity activity, List<ParseObject> list) {
this.activity = activity;
this.list = list;
}
#Override
public int getCount() {
return list.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
private static class ViewHolder{
//holderfields......
}
#Override
public View getView(final int position, View v, ViewGroup parent) {
ViewHolder holder;
if (v == null) {
v = View.inflate(activity.getApplicationContext(), R.layout.customview, null);
holder = new ViewHolder();
holder.profilepicture = (CircularImageView) v.findViewById(R.id.profilepic);
holder.username = (TextView) v.findViewById(R.id.username);
holder.picture = (ParseImageView) v.findViewById(R.id.picture);
holder.container =(LinearLayout)v.findViewById(R.id.container);
holder.share=(LinearLayout)v.findViewById(R.id.share);
holder.comment= (TextView) v.findViewById(R.id.comment);
holder.likes= (TextView) v.findViewById(R.id.likes);
holder.publishDate =(TextView)v.findViewById(R.id.publisdate);
holder.liked = (ImageView)v.findViewById(R.id.liked);
v.setTag(holder);
}
holder = (ViewHolder)v.getTag();
CustomTypography customTypo = new CustomTypography(activity.getApplicationContext());
holder.username.setTypeface(customTypo.OpenSansSemibold());
if(list.get(position).getParseUser("User")!=null){
holder.username.setText(list.get(position).getParseUser("User").getString("name"));
profilePic = list.get(position).getParseUser("User").getParseFile("profilePic");
if (profilePic != null) {
try {
Drawable drawable = new BitmapDrawable(BitmapFactory.decodeByteArray(profilePic.getData(), 0, profilePic.getData().length));
holder.profilepicture.setImageDrawable(drawable);
holder.profilepicture.setDrawingCacheEnabled(true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
else{
holder.username.setText("");
}
final ParseFile picture = list.get(position).getParseFile("picture");
if (picture != null) {
try {
Drawable drawable = new BitmapDrawable(BitmapFactory.decodeByteArray(picture.getData(), 0, picture.getData().length));
holder.picture.setImageDrawable(drawable);
holder.picture.setDrawingCacheEnabled(true);
} catch (Exception e) {
e.printStackTrace();
}
}
else{
}
holder.container.setLayoutParams(customLayoutParams);
holder.comment.setText(capitalizarPrimeraLetra(list.get(postiion).getString("Comment")));
holder.comment.setTypeface(customTypo.OpenSansRegular());
final int likes= list.get(position).getInt("Likes");
if(likes==0|| likes<0){
holder.likes.setText("");
}else{
holder.likes.setText(String.valueOf(likes));
}
holder.likes.setTypeface(customTypo.OpenSansLight());
holder.publishDate.setText(timeBetween(list.get(position).getCreatedAt()));
ParseQuery<ParseObject> query = ParseQuery.getQuery("LikedPictures");
query.whereEqualTo("picture", list.get(position));
query.whereEqualTo("user", currentUser);
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> likelist, ParseException e) {
if (e == null) {
if (likelist.size() != 0) {
hasLiked = true;
holder.liked.setBackground(activity.getApplicationContext().getResources().getDrawable(R.drawable.like));
holder.likes.setTextColor(activity.getApplicationContext().getResources().getColor(R.color.red));
} else {
hasLiked = false;
}
} else {
hasLiked = false;
}
}
});
return v;
}
private String timeBetween(Date date){
String result="";
Date parsedPictureDate = null;
Date parsedCurrentDate=null;
Date today = new Date();
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
SimpleDateFormat dateFormatLocal = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
try {
parsedPictureDate= dateFormatLocal.parse(dateFormatGmt.format(date));
parsedCurrentDate=dateFormatLocal.parse(dateFormatGmt.format(hoy));
} catch (java.text.ParseException e) {
result="";
}
long milis=parsedCurrentDate.getTime()-parsedPictureDate.getTime();
final long MILISECS_PER_MINUTE=milis/(60 * 1000);
final long MILISECS_PER_HOUR=milis/(60 * 60 * 1000);
final long MILLSECS_PER_DAY=milis/(24 * 60 * 60 * 1000);
if(milis<60000){
result="Now";
}
if(milis>=60000&&milis<3600000){
result=MILISECS_PER_MINUTE+" min";
}
if(milis>=3600000&&milis<86400000){
result=MILISECS_PER_HOUR+" h";
}
if(milis>=86400000){
result=MILLSECS_PER_DAY+" d";
}
return result;
}
This is the item that always gets populated in the listview
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:layout_width="match_parent"
android:background="#android:color/white"
android:paddingBottom="20dp"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/somelayout"
android:layout_weight="0.5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="#dimen/margin_16dp_sw600"
android:layout_marginLeft="5dp"
android:paddingRight="#dimen/padding_16dp_sw600"
android:gravity="left"
android:layout_marginBottom="5dp">
<customImageView
android:layout_gravity="center"
android:layout_width="50dp"
android:layout_height="50dp"
android:id="#+id/profilepicture"
app:border_width="0dp"
/>
<TextView
android:layout_marginLeft="#dimen/margin_16dp_sw600"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/username"
android:textSize="14sp"
android:gravity="left"
android:singleLine="true"
android:minLines="1"
android:maxLines="1"
android:lines="1"
/>
</LinearLayout>
<LinearLayout
android:id="#+id/layoutTime"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="right"
android:layout_weight="0.5"
android:layout_gravity="center" >
<TextView
android:gravity="right"
android:id="#+id/publishdate"
android:layout_marginRight="#dimen/margin_16dp_sw600"
android:textSize="14sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:paddingLeft="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:id="#+id/container"
android:layout_gravity="center"
android:background="#drawable/border"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<com.parse.ParseImageView
android:layout_margin="1dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/picture" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<LinearLayout
android:id="#+id/layoutlikes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="left"
android:layout_weight="0.5"
android:layout_gravity="center" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:id="#+id/likes"
>
<TextView
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/numlikes"
android:text="0"
android:textSize="14sp"
android:layout_margin="#dimen/margin_16dp_sw600"
/>
<ImageView
android:layout_gravity="center"
android:layout_marginRight="#dimen/margin_16dp_sw600"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/likepic"
android:background="#drawable/like_off"
/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="#+id/sharelayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="right"
android:padding="10dp"
android:layout_weight="0.5"
android:layout_marginTop="#dimen/margin_16dp_sw600"
android:layout_gravity="center" >
<ImageView
android:layout_gravity="center"
android:layout_marginRight="#dimen/margin_16dp_sw600"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/sharepic"
android:background="#drawable/ellipsis"
/>
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="#dimen/division_2dp_sw_600"
android:layout_margin="#dimen/margin_16dp_sw600"
android:background="#color/loading" />
<TextView
android:layout_gravity="left"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/comment"
android:textSize= "14sp"
android:layout_marginLeft="#dimen/margin_16dp_sw600"
android:layout_marginRight="#dimen/margin_16dp_sw600"
/>
</LinearLayout>
Your biggest performance hit is probably the code below. You should use some sort of caching rather than decoding the Bitmap each time.
if (profilePic != null) {
try {
Drawable drawable = new BitmapDrawable(BitmapFactory.decodeByteArray(profilePic.getData(), 0, profilePic.getData().length));
holder.profilepicture.setImageDrawable(drawable);
holder.profilepicture.setDrawingCacheEnabled(true);
} catch (Exception e) {
e.printStackTrace();
}
Also, you are creating a new CustomTypography instance everytime getView() is called. I assume this class extends Typeface, in which case you could just use a single instance that gets initialised in the adapter's constructor.
Here are a couple of things:
1. in your adapter.getView() method, move the
holder = (ViewHolder)v.getTag();
to if/else scope:
if(view ==null){
//creation of viewHolder
}else{
holder = (ViewHolder)v.getTag();
}
2. There is too much code in the adapter.getView(), specially the parse query. You better call it once per item, by caching the result of query for each item in adapter. It is currently being called on every item get visible on scroll.
3. Try to reduce the count of views in your item's xml. Too many views in ListView items cause in memory leak and low performance.
4. Adding the hardwareAccelerated="true" to your activity in manifest might help.
5. Try to comment out the scroll listener, to find out if it is reducing the performance.
i am new to android development, and from java background , am developing an android app where i have to display of invites which user have got, so the layout will be like below
here invite response view (yes, no , may) will be shown on click of each invite view, but i want the response view to get closed or visibility = Gone when user clicks on another view. currently response views are shown once clicked on invite view.
so to solve this issue, i have added id (inviteId) to each response view as below
final LinearLayout second = (LinearLayout) inviteView.findViewById(R.id.hidden);
second.setId((int) currentInviteId);
now i am trying to get firstly opened response view id when user clicks on next invite view and trying to set the first response view to "GONE"
public class InvitationFragment extends Fragment {
private List<String> eventName = new ArrayList<>();
private List<Long> eventId = new ArrayList<>();
private List<String> eventPlace = new ArrayList<>();
private List<EventMO> eventMOs = new ArrayList<>();
private List<UserMO> userMO = new ArrayList<>();
private Context context;
private UserOccasions userOccasions;
private UserDelegate userDelegate = new UserDelegate();
private EventDelegates eventDelegates = new EventDelegates();
private Gson gson = new Gson();
private ProgressDialog prgDialog;
private EventMO eventMO;
// private long compareEventId;
private SharedPreferences prefs;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final View view = inflater.inflate(R.layout.invitation_tab, container, false);
context = getActivity().getApplicationContext();
prgDialog = new ProgressDialog(getActivity());
eventId.clear();
eventName.clear();
eventPlace.clear();
// Set Progress Dialog Text
prgDialog.setMessage("Please wait...");
// Set Cancelable as False
prgDialog.setCancelable(false);
prgDialog.show();
DatabaseHelper dbHelper = new DatabaseHelper(context);
final UserMO userMO = dbHelper.getRingeeUserData(1);
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... arg0) {
return eventDelegates.getAllEventForUser(userMO, context);
}
#Override
protected void onPostExecute(String eventlists) {
if (eventlists != "null") {
eventMOs = gson.fromJson(eventlists, new TypeToken<List<EventMO>>() {
}.getType());
Toast.makeText(context, "total items of eventMo" + eventMOs.size(), Toast.LENGTH_LONG).show();
for (EventMO eventMO : eventMOs) {
eventName.add(eventMO.getText());
eventId.add(eventMO.getEventId());
eventPlace.add(eventMO.getPlace());
}
DatabaseHelper dbHelper = new DatabaseHelper(context);
//long totalInsertion = dbHelper.insertUserRelationTable(userMOs);
prgDialog.dismiss();
//Toast.makeText(context, "total userMos size " + userMOs.size() + "total db insertion size " + totalInsertion, Toast.LENGTH_LONG).show();
ListView occasionView = (ListView) view.findViewById(R.id.invitation_list_view);
userOccasions = new UserOccasions();
occasionView.setAdapter(userOccasions);
occasionView.setItemsCanFocus(false);
occasionView.setTextFilterEnabled(true);
occasionView.setOnItemClickListener(occasionView.getOnItemClickListener());
}
}
}.execute(null, null, null);
return view;
}
private class UserOccasions extends BaseAdapter {
LayoutInflater mInflater;
TextView eventNameTxtV, eventPlaceTxtV;
UserOccasions() {
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return eventMOs.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return 0;
}
// show list values name and mobile number in contact page
#Override
public View getView(final int position,View inviteView, ViewGroup parent) {
if (inviteView == null) {
inviteView = mInflater.inflate(R.layout.invitation, null);
}
EventMO eventMO = eventMOs.get(position);
final long currentEventId = eventMO.getEventId();
eventNameTxtV = (TextView) inviteView.findViewById(R.id.invitation_title);
eventPlaceTxtV = (TextView) inviteView.findViewById(R.id.invitation_place);
eventNameTxtV.setText(eventMO.getText());
eventPlaceTxtV.setText(eventMO.getPlace());
inviteView.setTag(position);
View v = inviteView.findViewById(R.id.invitation_single);
final LinearLayout first = (LinearLayout) inviteView.findViewById(R.id.invitation_single);
Button yesBtn = (Button) inviteView.findViewById(R.id.yesbutton);
Button noBtn = (Button) inviteView.findViewById(R.id.nobutton);
Button mayBeBtn = (Button) inviteView.findViewById(R.id.buttonmaybe);
final LinearLayout second = (LinearLayout) inviteView.findViewById(R.id.hidden);
second.setId((int) currentEventId);
// to store current event id into shared preference, to compare event ids and close child layout if ids are differents
prefs = context.getSharedPreferences(InvitationFragment.class.getSimpleName(), Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putLong("compareEventId", currentEventId);
editor.commit();
yesBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
second.setVisibility(View.GONE);
final String response = "yes";
final EventMO event = new EventMO();
event.setIs_Attend(response);
new AsyncTask<Void, Void, String>() {
protected String doInBackground(Void... arg0) {
return eventDelegates.updateEvent(event, context);
}
}.execute(null, null, null);
}
});
noBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
second.setVisibility(View.GONE);
final String response = "no";
final EventMO event = new EventMO();
event.setIs_Attend(response);
new AsyncTask<Void, Void, String>() {
protected String doInBackground(Void... arg0) {
return eventDelegates.updateEvent(event, context);
}
}.execute(null, null, null);
}
});
mayBeBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
second.setVisibility(View.GONE);
final String response = "maybe";
final EventMO event = new EventMO();
event.setIs_Attend(response);
new AsyncTask<Void, Void, String>() {
protected String doInBackground(Void... arg0) {
return eventDelegates.addEvent(event, context);
}
}.execute(null, null, null);
}
});
first.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View invitationView) {
final long compareEventId = prefs.getLong("compareEventId", 0);
final long currentEventId = second.getId();
if(compareEventId != 0 && compareEventId != currentEventId){
LayoutInflater inflater = (LayoutInflater)context.getSystemService
(Context.LAYOUT_INFLATER_SERVICE);
View inflatedView = inflater.inflate(R.layout.invitation, null);
final View inviteResponseView = (View) inflatedView.findViewById((int) compareEventId);
inviteResponseView.setVisibility(View.GONE);
}
switch (invitationView.getId()) {
case R.id.invitation_single:
second.setVisibility(View.VISIBLE);
break;
}
}
});
return inviteView;
}
}
}
but inviteResponseView is always returning null. need direction to solve this functionality. Thanks for your valuable response.
EDIT :-
my layout xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/invitation_single"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="?android:dividerVertical"
android:dividerPadding="5dp"
android:showDividers="middle"
tools:context=".MainActivity">
<ImageButton
android:id="#+id/image"
android:layout_width="50dp"
android:layout_height="50dp"
android:src="#drawable/ic_action_event" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_weight="1"
android:clickable="false"
android:focusable="true"
android:orientation="vertical">
<TextView
android:id="#+id/invitation_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingRight="0dp"
android:paddingTop="3dp"
android:textColor="#color/black"
android:textSize="18sp" />
<TextView
android:id="#+id/invitation_place"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:paddingRight="0dp"
android:textColor="#color/black"
android:textSize="15sp" />
</LinearLayout>
<LinearLayout
android:id="#+id/hidden"
android:layout_width="0dp"
android:layout_height="50dp"
android:layout_marginLeft="-270dp"
android:layout_marginTop="60dp"
android:layout_weight="1"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
android:paddingTop="1dp"
android:visibility="gone"
android:weightSum="3">
<Button
android:id="#+id/yesbutton"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="7dp"
android:layout_weight="1"
android:background="#color/blue"
android:text="Yes"
android:textColor="#color/black"></Button>
<Button
android:id="#+id/nobutton"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="25dp"
android:layout_weight="1"
android:background="#color/blue"
android:text="No"
android:textColor="#color/black"></Button>
<Button
android:id="#+id/buttonmaybe"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="25dp"
android:layout_marginRight="10dp"
android:layout_weight="1"
android:background="#color/blue"
android:text="Maybe"
android:textColor="#color/black"></Button>
</LinearLayout>
</LinearLayout>
Why don't you use an onFocusChangeListener ?
First of all:
Set in your invitationView layout .xml file (the one which contains the buttons yes, no, maybe) like this:
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"
Note: You must also do this to your parent layout (the layout of the Activity) so when the user touch outside the invitationView, the parent layout will catch the focus.
Then, what you have to do is to set the invitationView.setOnFocusChangeListener to your invitationView, inside your Activity or inside your listAdapater (or recyclerViewAdapter) if you are using it to the invitationView (what I highly recommend).
Like this:
invitationView.setOnFocusChangeListener(new OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if(!hasFocus)
{
inviteResponseView.setVisibility(view.GONE)
}else
inviteResponseView.setVisibility(view.VISIBLE)
}
});
Recommendation:
Recommend you to use a recyclerView instead of fragments to make this job, it pretty easy to use and memory usage efficient. Now it supports most of the devices with the design support library that already has a bunch of tutorials, like the linked ones.
I recommend you use some third-party dependency in your project.
As a matter of fact, nhaarman's ListViewAnimations can do that very well. Download the demo in Play Store and check it.
There's a fully customizable ListView that can expand on user click and show more items. Plus, it supports very cool animations. I've used it in one of my projects and it's very good. You can even set the maximum number of views that can be expanded at once.
In your BaseAdapter add
private boolean showActionView = false;
private int showActionViewFor;
public void showActionView(boolean show, int position) {
showActionView = show;
showActionViewFor = position;
notifyDataSetChanged();
}
Then in your BaseAdapter's getView() add
if(showActionView && position == showActionViewFor) {
second.setVisibility(View.VISIBLE);
} else {
second.setVisibility(View.INVISIBLE);
//Don't use View.GONE
}
Then in your Fragment's onCreateView(), add
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mAdapter.showActionView(true, position);
}
});
Bam! It should work as you need. Whenever you need to hide all action views just call
mAdapter.showActionView(false, 0);
UPDATE:
You need to remove your
first.setOnClickListener(new View.OnClickListener() {}
from your Adapter.
EXTRA: To improve your ListView performance, you should consider implementing the View Holder pattern.
I know there are a lot of this kind of questions, but here is my problem.
I have a gallery with images and when I click, there is an ImageView to display the selected image in the gallery.
I also have a TextView witch displays a message.
When I click an image in the gallery, my ImageView gets the image and the TextTiew doesnt update its data.
I tried to put the code in a try/catch block and it doesn't throw any exception.
In my Log, the TextView has the exact text I have provided.
I tried using a new thread, but the result is the same: the TextView doesn't update, but my ImageView does.
I tried using runOnUiThread (as far as I know it's the same as a Thread), but still nothing.
I also changed from TextView to EditText, but I have the same problem.
Everyone says: "use a thread" - I did and it didn't work.
I ran out of ideas...
public class VODInterface extends Activity {
public static String[] values;
private static int itemPosition;
public static Activity thisActivity;
public Gallery gallery;
public ListView listView;
public LinearLayout MovieView;
public ImageView imgview;
public boolean submenus=false;
public boolean listviewVisibility = true;
private Handler handler = new Handler() ;
private SharedPreferences ep;
public ArrayList<VODObject> vod;
private ArrayList<Bitmap> tempimg;
private static int MovieSetNumber = 1;
public static int VODIndexPosition = 0;
public VODInterface(){
}
public void onDestroy(){
MainActivity.inChild=false;
super.onDestroy();
}
public void onCreate(Bundle bundle){
super.onCreate(bundle);
this.setContentView(R.layout.listview2);
ep = getSharedPreferences("Settings", 0);
listView = (ListView) this.findViewById(R.id.listView1);
MovieView = (LinearLayout) this.findViewById(R.id.movieView);
imgview = (ImageView)this.findViewById(R.id.imageView2);
// Defined Array values to show in ListView
values = new String[] { "A..Z",
"Category",
"Most Rated",
"Most Watched",
"Recently"
};
//this shows whitch movie should me load images
//we show always only 10 movies
MovieSetNumber = 1;
// Define a new Adapter
// First parameter - Context
// Second parameter - Layout for the row
// Third parameter - ID of the TextView to which the data is written
// Forth - the Array of data
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, android.R.id.text1, values);
// Assign adapter to ListView
listView.setAdapter(adapter);
// ListView Item Click Listener
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// ListView Clicked item index
itemPosition = position;
handler.post(goDeep);
}
});
}
private Runnable goDeep = new Runnable(){
public void run(){
new goDeep().execute("");
}
};
class goDeep extends AsyncTask<String, String, String>{
ProgressDialog mProgressDialog = new ProgressDialog(VODInterface.this);
String result="";
boolean failLoadVOD=false;
protected void onPreExecute(){
mProgressDialog.setMessage(getString(R.string.downloading));
mProgressDialog.setIndeterminate(true);
mProgressDialog.setCancelable(false);
mProgressDialog.show();
}
#Override
protected String doInBackground(String... arg0) {
// TODO Auto-generated method stub
//START check if servers are Ok
if(!Server.isOnline()){
Server.getAvailableServer();
Log.i("good", "");
}
if(!Server.isOnline()){
Log.i("WEW", "SERVERS are off");
return null;
}
//END check if servers are Ok
//START synchronize local database with online database
try{
if(ep.contains("downloaded")){
Log.i("localDatabase", "is full");
}
else{
Editor ed = ep.edit();
ed.putString("downloaded", "");
ed.commit();
//load data from database
if(!MainActivity.web.parseVODAndVODCategories()){
failLoadVOD=true;
}
}
}
catch(NullPointerException ee)
{
//lets go get datas from Tibodatabase
Editor ed = ep.edit();
ed.putString("downloaded", "");
ed.commit();
if(!MainActivity.web.parseVODAndVODCategories()){
failLoadVOD=true;
}
}
//END synchronize local database with online database
//START handle menus
if(!submenus) //MainMenu
{
if(itemPosition == 1){
//get all movies ordered by name
List<String> val = MainActivity.voddb.selectAllCategories();
values = new String[val.size()+1];
values[0] ="[...]";
for(int i=0;i<val.size();i++){
values[i+1] = val.get(i);
}
listviewVisibility = true;
}
else{
//show movies
listviewVisibility = false;
}
submenus = true;
}
else{
if(itemPosition == 0){
values = new String[] { "A..Z",
"Category",
"Most Rated",
"Most Watched",
"Recently"
};
submenus = false;
listviewVisibility = true;
}
else{
listviewVisibility = false;
}
}
//END handle menu
if(!listviewVisibility){
getData();
for(int i=0;i<vod.size();i++){
if(!FileExciste(vod.get(i).Icon)){
try{
Bitmap bmp ;
URL newurl = new URL(vod.get(i).Icon);
bmp = BitmapFactory.decodeStream(newurl.openConnection() .getInputStream());
saveImageToSD(bmp,vod.get(i).Icon);
Log.i(i+"", "done");
}
catch(Exception e){
Log.i("exciste", "exciste");
}
}
else{
Log.i(i+"", "exciste");
}
}
}
runOnUiThread(new Runnable() {
#Override
public void run() {
if(!listviewVisibility){
listView.setVisibility(View.GONE);
MovieView.setVisibility(View.VISIBLE);
populateMovieView();
}
else{
ArrayAdapter<String> adapter = new ArrayAdapter<String>(VODInterface.this,
android.R.layout.simple_list_item_1, android.R.id.text1, values);
listView.setAdapter(adapter);
}
}
});
mProgressDialog.dismiss();
return "";
}
protected void onPostExecute(){
//start adding to cache
super.onPostExecute("");
}
}
private void getData(){
vod = new ArrayList<VODObject>();
for(int i=1;i<MainActivity.voddb.getVODCount()+1;i++){
vod.add(MainActivity.voddb.getVOD(i+""));
if(vod.get(i-1).Icon.contains(" ")){
vod.get(i-1).Icon = vod.get(i-1).Icon.replaceAll(" ", "%20");
Log.i("u korrigjua", vod.get(i-1).Icon);
}
}
}
private void populateMovieView(){
gallery = (Gallery) findViewById(R.id.gallery1);
GalleryImageAdapter gia= new GalleryImageAdapter(this,vod);
gallery.setAdapter(gia);
gallery.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, final int position, long id) {
// show the selected Image
/*here is the problem
*
*----------------------------/
*/
try{
LayoutInflater factory = getLayoutInflater();
View view = factory.inflate(R.layout.listview2, null);
EditText title = (EditText) view.findViewById(R.id.editText2);
title.setText(vod.get(position).title);
TextView desc = (TextView) view.findViewById(R.id.editText4);
desc.setText(vod.get(position).description);
Log.i("info", title.getText()+" "+desc.getText());
}
catch(Exception ee){
Log.i("info", ee.getMessage()+" nnn");
}
/*----------------------*/
try{
imgview.setImageBitmap(getImageFromSD(vod.get(position).Icon));
}
catch(Exception ee){
imgview.setImageResource(R.drawable.untitled);
}
}
});
}
public static Bitmap getImageFromSD(String url){
String path = Environment.getExternalStorageDirectory().toString();
File imgFile = new File(path+"/"+WebHelper.getFilenameFromUrl(url));
Bitmap myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
return myBitmap;
}
private void saveImageToSD(Bitmap bmp,String url) throws IOException {
String path = Environment.getExternalStorageDirectory().toString();
OutputStream fOut = null;
File file = new File(path, "/"+WebHelper.getFilenameFromUrl(url));
fOut = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
fOut.flush();
fOut.close();
MediaStore.Images.Media.insertImage(getContentResolver(),file.getAbsolutePath(),file.getName (),file.getName());
}
private boolean FileExciste(String url){
String path = Environment.getExternalStorageDirectory().toString();
File file = new File(path, "/"+WebHelper.getFilenameFromUrl(url));
return file.exists();
}
AND this is my XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/vod"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="top" >
<ListView
android:id="#+id/listView1"
android:layout_width="274dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginBottom="20dp"
android:layout_marginLeft="20dp"
android:layout_marginTop="20dp"
android:background="#color/translucent_bblack" >
</ListView>
<LinearLayout
android:id="#+id/movieView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/translucent_black"
android:orientation="vertical"
android:visibility="invisible" >
<Gallery
android:id="#+id/gallery1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:background="#color/translucent_bblack" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<ImageButton
android:id="#+id/imageView2"
android:layout_width="400dp"
android:layout_height="fill_parent"
android:layout_marginBottom="20dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="#drawable/bord" />
<LinearLayout
android:id="#+id/MovieDesc"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="20dp"
android:layout_marginRight="20dp"
android:background="#color/translucent_bblack"
android:orientation="vertical" >
<TextView
android:id="#+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="30dp"
android:inputType="textPersonName"
android:text="Title:"
android:textColor="#FFFFFF"
android:textSize="20sp"
android:textStyle="bold" >
</TextView>
<TextView
android:id="#+id/editText2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:textColor="#FFFFFF"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="#+id/editText3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="30dp"
android:text="Description:"
android:textColor="#FFFFFF"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="#+id/editText4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:textColor="#FFFFFF"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="#+id/editText5"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginTop="60dp"
android:text="Duration:"
android:textColor="#FFFFFF"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
Declare your TextViews as field as like as ImageView---- "imgview" as follows...
public ImageView imgview;
public TextView title;
public TextView desc;
Initialize them in onCreate method as "imgview"
imgview = (ImageView)this.findViewById(R.id.imageView2);
title = (TextView) view.findViewById(R.id.editText2);
desc = (TextView) view.findViewById(R.id.editText4);
And update your gallery.setOnItemClickListener code as follows...
gallery.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View v, final int position, long id) {
title.setText(vod.get(position).title);
desc.setText(vod.get(position).description);
Log.i("info", title.getText()+" "+desc.getText());
imgview.setImageBitmap(getImageFromSD(vod.get(position).Icon));
}
});
How do I create a neverending listview of list items with checkboxes that can be removed with a delete item button? The answer is below.
In order to create a neverending listview the first thing you need to have is a set of two runnables. These threads will update the array of data in your adapter.
final int itemsPerPage = 100;
ArrayList<HashMap<String,String>> listItems = new ArrayList<HashMap<String,String>>();
boolean loadingMore = false;
int item = 0;
//Since we cant update our UI from a thread this Runnable takes care of that!
public Runnable returnRes = new Runnable() {
#Override
public void run() {
//Loop thru the new items and add them to the adapter
if(groceries.getGroceries().size() > 0){
for(int i=0;i < listItems.size();i++) {
HashMap<String,String> grocery = listItems.get(i);
adapter.add(grocery);
}
//Update the Application title
setTitle("Grocery List with " + String.valueOf(groceries.getGroceries().size()) + " items");
//Tell to the adapter that changes have been made, this will cause the list to refresh
adapter.notifyDataSetChanged();
//Done loading more.
loadingMore = false;
}
}
};
//Runnable to load the items
public Runnable loadMoreListItems = new Runnable() {
#Override
public void run() {
//Set flag so we cant load new items 2 at the same time
loadingMore = true;
//Reset the array that holds the new items
listItems = new ArrayList<HashMap<String,String>>();
//Get 8 new listitems
for (int i = 0; i < itemsPerPage; i++) {
if (i < groceries.getGroceries().size()) {
listItems.add(groceries.getGroceries().get(i));
item++;
}
}
//Done! now continue on the UI thread
runOnUiThread(returnRes);
}
};
Then your onCreate() method should look something like this with an array passed to your adapter:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_create_grocery_list);
//add the footer before adding the adapter, else the footer will not load!
View footerView = ((LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE))
.inflate(R.layout.activity_footer_view, null, false);
this.getListView().addFooterView(footerView);
adapter = new ListViewAdapter(this,groceries);
setListAdapter(adapter);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
//Here is where the magic happens
this.getListView().setOnScrollListener(new OnScrollListener(){
//useless here, skip!
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {}
//dumdumdum
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
//what is the bottom iten that is visible
int lastInScreen = firstVisibleItem + visibleItemCount;
//is the bottom item visible & not loading more already ? Load more !
if((lastInScreen == totalItemCount) && !loadingMore && item < groceries.getGroceries().size()){
Thread thread = new Thread(null, loadMoreListItems);
thread.start();
}
}
});
}
You will also need a delete method to remove the items with checkboxes and a checkOff method as well. They look like this:
ArrayList<Integer> checkedBoxes = new ArrayList<Integer>();
ArrayList<HashMap<String,String>> checkedItems = new ArrayList<HashMap<String,String>>();
public void deleteItem(View view) {
if (checkedBoxes.size() > 1 || checkedBoxes.size() == 0) {
Toast.makeText(getApplicationContext(), "You can only delete one item at a time. Sorry :(", Toast.LENGTH_LONG).show();
return;
} else {
checkedItems.add(groceries.getGroceries().get(checkedBoxes.get(0)));
groceries.getGroceries().removeAll(checkedItems);
checkedBoxes.clear();
try {
groceries.serialize();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Intent intent = new Intent(getApplicationContext(),CreateGroceryList.class);
startActivity(intent);
}
}
public void checkOff(View view) {
CheckBox box = (CheckBox)view;
DataModel d = (DataModel)box.getTag();
if(!checkedBoxes.contains(d.index)) {
checkedBoxes.add(d.index);
} else {
checkedBoxes.remove((Integer)d.index);
}
}
In order to communicate with the adapter it is helpful to have a DataModel class that will model our information. My DataModel has an index variable to keep track of the selected item.
public class DataModel {
int index;
HashMap<String,String> data;
boolean selected;
public DataModel(int i) {
index = i;
data = new HashMap<String,String>();
selected = false;
}
public HashMap<String, String> getData() {
return data;
}
public void setData(HashMap<String, String> data) {
this.data = data;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
}
Finally, here is the code for the BaseAdapter:
public class ListViewAdapter extends BaseAdapter {//To create an adapter we have to extend BaseAdapter instead of Activity, or whatever.
private ListActivity activity;
private View vi;
private ArrayList<DataModel> data;
private static LayoutInflater inflater=null;
public ListViewAdapter(ListActivity a, GroceryList g) {
activity = a;
data = new ArrayList<DataModel>();
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
groceries = g;
}
public void add(HashMap<String,String> a){
DataModel d = new DataModel(data.size());
d.setData(a);
d.setSelected(false);
data.add(d);
}
public ArrayList<DataModel> getData() {
return data;
}
public int getCount() { //get the number of elements in the listview
return data.size();
}
public Object getItem(int position) { //this method returns on Object by position
return position;
}
public long getItemId(int position) { //get item id by position
return position;
}
public View getView() {
return vi;
}
public View getView(int position, View convertView, ViewGroup parent) { //getView method is the method which populates the listview with our personalized rows
vi=convertView;
final ViewHolder holder = new ViewHolder();
if(convertView==null) {
vi = inflater.inflate(R.layout.custom_row_view, null);
//every item in listview uses xml "listview_row"'s design
holder.name = (CheckBox)vi.findViewById(R.id.name);
holder.price = (TextView)vi.findViewById(R.id.price); // You can enter anything you want, buttons, radiobuttons, images, etc.
holder.quantity = (TextView)vi.findViewById(R.id.quantity);
holder.name
.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
DataModel element = (DataModel) holder.name
.getTag();
element.setSelected(buttonView.isChecked());
}
});
vi.setTag(holder);
holder.name.setTag(data.get(position));
ViewHolder vholder = (ViewHolder) vi.getTag();
vholder.name.setChecked(data.get(position).isSelected());
HashMap<String, String> hash = new HashMap<String, String>(); //We need a HashMap to store our data for any item
hash = data.get(position).getData();
vholder.name.setText(hash.get("brand") + " " + hash.get("name")); //We personalize our row's items.
vholder.price.setText("$" + hash.get("price"));
vholder.quantity.setText("Quantity: " + hash.get("quantity"));
} else {
vi = convertView;
((ViewHolder) vi.getTag()).name.setTag(data.get(position));
}
if (holder.name == null) {
ViewHolder vholder = (ViewHolder) vi.getTag();
vholder.name.setChecked(data.get(position).isSelected());
HashMap<String, String> hash = new HashMap<String, String>(); //We need a HashMap to store our data for any item
hash = data.get(position).getData();
vholder.name.setText(hash.get("brand") + " " + hash.get("name")); //We personalize our row's items.
vholder.price.setText("$" + hash.get("price"));
vholder.quantity.setText("Quantity: " + hash.get("quantity"));
}
return vi;
}
}
class ViewHolder {
CheckBox name;
TextView price;
TextView quantity;
public CheckBox getName() {
return name;
}
public void setName(CheckBox name) {
this.name = name;
}
public TextView getPrice() {
return price;
}
public void setPrice(TextView price) {
this.price = price;
}
public TextView getQuantity() {
return quantity;
}
public void setQuantity(TextView quantity) {
this.quantity = quantity;
}
}
You also need a few xml files in your layout folder this is what they will look like:
You need a footerview that will tell your list when to load new items:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:gravity="center_horizontal"
android:padding="3dp"
android:layout_height="fill_parent">
<TextView
android:id="#id/android:empty"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:gravity="center"
android:padding="5dp"
android:text="Add more grocery items..."/>
A custom row view that is populated by your BaseAdapter:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<CheckBox
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CheckBox"
android:focusable="false"
android:textSize="25dip"
android:onClick="checkOff"
/>
<TextView
android:id="#+id/quantity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="40dip"
android:text="Lastname"
android:textSize="15dip" />
<TextView
android:id="#+id/price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="40dip"
android:text="Lastname"
android:textSize="15dip" />
</LinearLayout>
And a parent view, mine is called create_grocery_list because I'm writing a grocery list editor: This one must contain a ListView with the proper id.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="400dp" >
<ListView
android:id="#android:id/list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" >
</ListView>
</LinearLayout>
<AbsoluteLayout
android:layout_width="match_parent"
android:layout_height="72dp" >
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_x="105dp"
android:layout_y="0dp"
android:onClick="deleteItem"
android:text="#string/deleteItem" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_x="8dp"
android:layout_y="0dp"
android:onClick="goToAddItemScreen"
android:text="#string/addItem" />
<Button
android:id="#+id/button3"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_x="221dp"
android:layout_y="0dp"
android:onClick="scanner"
android:text="#string/scanCode" />
</AbsoluteLayout>
</LinearLayout>
And that's about it... hope this helps anyone. It's the most complete tutorial you'll find.
I learned all this from this tutorial: http://www.vogella.com/articles/AndroidListView/article.html#androidlists_overview then added the two runnables to make a neverending grocery list :) have fun programming...
below is my code which works fine for showing listview horizontally. how can I change it to gridvew. What changes should I make to change it to gridview? help me please
public class fifthscreen extends Activity {
int IOConnect = 0;
String _response;
String status;
HorizontalListView listview;
CategoryListAdapter3 cla;
String URL, URL2;
String SelectMenuAPI;
static ArrayList<Long> Category_ID = new ArrayList<Long>();
static ArrayList<String> Category_name = new ArrayList<String>();
static ArrayList<String> Category_image = new ArrayList<String>();
public static String allergen2;
String name;
String url1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fifthscreen);
listview = (HorizontalListView) this.findViewById(R.id.listview2);
cla = new CategoryListAdapter3(fifthscreen.this);
new TheTask().execute();
}
public class TheTask extends AsyncTask<Void, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(Void... arg0) {
try {
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
HttpEntity resEntity = response.getEntity();
_response = EntityUtils.toString(resEntity);
} catch (Exception e) {
e.printStackTrace();
}
return _response;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
try {
JSONObject json2 = new JSONObject(result);
status = json2.getString("status");
if (status.equals("1")) {
JSONArray school4 = json2.getJSONArray("dish_allergen");
//
for (int i = 0; i < school4.length(); i++) {
JSONObject object = school4.getJSONObject(i);
Category_ID.add((long) i);
Category_name.add(object.getString("name"));
Category_image.add(object.getString("image"));
}
}
else {
JSONArray school2 = json2.getJSONArray("data");
for (int i = 0; i < school2.length(); i++) {
JSONObject object = school2.getJSONObject(i);
Category_ID.add((long) i);
Category_name.add(object.getString("name"));
}
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
listview.setAdapter(cla);
}
}
}
public class CategoryListAdapter3 extends BaseAdapter {
private Activity activity;
private AQuery androidAQuery;
public CategoryListAdapter3(Activity act) {
this.activity = act;
// imageLoader = new ImageLoader(act);
}
public int getCount() {
// TODO Auto-generated method stub
return fifthscreen.Category_ID.size();
}
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder;
androidAQuery = new AQuery(getcontext());
if(convertView == null){
LayoutInflater inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.viewitem2, null);
holder = new ViewHolder();
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
holder.txtText = (TextView) convertView.findViewById(R.id.title2);
holder.imgThumb = (ImageView) convertView.findViewById(R.id.image2);
holder.txtText.setText(fifthscreen.Category_name.get(position));
// imageLoader.DisplayImage(fifthscreen.Category_image.get(position),
activity, holder.imgThumb);
androidAQuery.id(holder.imgThumb).image(fifthscreen.Category_image.get(position), false,
false);
return convertView;
}
private Activity getcontext() {
// TODO Auto-generated method stub
return null;
}
static class ViewHolder {
TextView txtText;
ImageView imgThumb;
}
}
<!--- fifithscreen.xml--->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_below="#+id/test_button_text5"
android:orientation="vertical" >
<com.example.examplecode.HorizontalListView
android:id="#+id/listview2"
android:layout_width="wrap_content"
android:layout_height="120dp"
android:layout_below="#+id/test_button_text5"
android:background="#ffffff"/>
</LinearLayout>
<!--viewitem2.xml--->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<ImageView
android:id="#+id/image2"
android:layout_width="90dp"
android:layout_height="70dp"
android:scaleType="fitXY"
android:padding="5dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:src="#drawable/ic_launcher"
/>
<TextView
android:id="#+id/title2"
android:layout_width="90dp"
android:layout_height="wrap_content"
android:textColor="#000"
android:paddingTop="10dp"
android:gravity="center_horizontal"
/>
</LinearLayout>
No change at all. Just set adapter of GridView as your are setting for ListView.
I'd suggest that you use RecyclerView intead.
You might want to refer to the documentation and learn more about it.
I'm sharing my piece of code in which I'm changing my gridview to listview using RecyclerView
If you're using Android Studio then you might need to add dependencies in gradle build. In my case I added as follows:
dependencies {
.
.
.
compile 'com.android.support:recyclerview-v7:24.0.0'
}
First I'm defining a grid cell which is to be used in grid layout
recycler_cell.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:id="#+id/imageView2"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:background="#FF000000"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="#+id/textView2"
android:layout_below="#+id/imageView2"
android:layout_alig=nParentStart="true"
android:layout_alignEnd="#+id/imageView2"
android:gravity="center"/>
</RelativeLayout>
Now I'm defining a list row which is to be used in list layout
recycler_row.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:id="#+id/imageView"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:background="#FF000000"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/textView"
android:layout_alignParentTop="true"
android:layout_alignBottom="#+id/imageView"
android:layout_alignParentEnd="true"
android:layout_toEndOf="#+id/imageView"
android:gravity="center_vertical"
android:background="#FF333333"
android:textColor="#FFF"
android:padding="10dp"/>
</RelativeLayout>
recycler_view_test.xml
And of course define a layout which would contain RecyclerView
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/recyclerView"
android:layout_alignParentLeft="true"
android:layout_marginLeft="0dp"
android:layout_alignParentTop="true"
android:layout_marginTop="0dp"
android:layout_centerHorizontal="true"
>
</android.support.v7.widget.RecyclerView>
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Change Layout"
android:id="#+id/btnChange"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="62dp"/>
</RelativeLayout>
I'm sharing my piece of code but I'd strongly recommend that you go through the documentation and tutorials to understand RecyclerView to its full extent.
public class RecyclerViewTest extends AppCompatActivity
{
final int GRID = 0;
final int LIST = 1;
int type;
RecyclerView recyclerView;
RecyclerView.LayoutManager gridLayoutManager, linearLayoutManager;
MyAdapter adapter;
Button btnChange;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.recycler_view_test);
// Display contents in views
final List<Person> list = new ArrayList<>();
list.add(new Person("Ariq Row 1"));
list.add(new Person("Ariq Row 2"));
list.add(new Person("Ariq Row 3"));
// Finding views by id
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
btnChange = (Button) findViewById(R.id.btnChange);
// Defining Linear Layout Manager
linearLayoutManager = new LinearLayoutManager(getApplicationContext());
// Defining Linear Layout Manager (here, 3 column span count)
gridLayoutManager = new GridLayoutManager(getApplicationContext(), 3);
//Setting gird view as default view
type = GRID;
adapter = new MyAdapter(list, GRID);
recyclerView.setLayoutManager(gridLayoutManager);
recyclerView.setAdapter(adapter);
//Setting click listener
btnChange.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
if (type == LIST)
{
// Change to grid view
adapter = new MyAdapter(list, GRID);
recyclerView.setLayoutManager(gridLayoutManager);
recyclerView.setAdapter(adapter);
type = GRID;
}
else
{
// Change to list view
adapter = new MyAdapter(list, LIST);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(adapter);
type = LIST;
}
}
});
}
}
//Defining Adapter
class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>
{
List<Person> list;
int type;
final int GRID = 0;
final int LIST = 1;
MyAdapter(List<Person> list, int type)
{
this.list = list;
this.type = type;
}
// Inflating views if the existing layout items are not being recycled
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View itemView;
if (viewType == GRID)
{
// Inflate the grid cell as a view item
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_cell, parent, false);
}
else
{
// Inflate the list row as a view item
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_row, parent, false);
}
return new ViewHolder(itemView, viewType);
}
// Add data to your layout items
#Override
public void onBindViewHolder(ViewHolder holder, int position)
{
Person person = list.get(position);
holder.textView.setText(person.name);
}
// Number of items
#Override
public int getItemCount()
{
return list.size();
}
// Using the variable "type" to check which layout is to be displayed
#Override
public int getItemViewType(int position)
{
if (type == GRID)
{
return GRID;
}
else
{
return LIST;
}
}
// Defining ViewHolder inner class
public class ViewHolder extends RecyclerView.ViewHolder
{
TextView textView;
final int GRID = 0;
final int LIST = 1;
public ViewHolder(View itemView, int type)
{
super(itemView);
if (type == GRID)
{
textView = (TextView) itemView.findViewById(R.id.textView2);
}
else
{
textView = (TextView) itemView.findViewById(R.id.textView);
}
}
}
}
// Data Source Class
class Person
{
String name;
Person(String name)
{
this.name = name;
}
}
If you end up with the issue to auto fit the number of columns in case of grid layout then you might want to check #s-marks's answer in which he extended the GridLayoutManager class and added his own patch of code, and also my fix if you start having weird column width.
In my case, using his solution I made a class as follows:
class GridAutofitLayoutManager extends GridLayoutManager
{
private int mColumnWidth;
private boolean mColumnWidthChanged = true;
public GridAutofitLayoutManager(Context context, int columnWidth)
{
/* Initially set spanCount to 1, will be changed automatically later. */
super(context, 1);
setColumnWidth(checkedColumnWidth(context, columnWidth));
}
public GridAutofitLayoutManager(Context context, int columnWidth, int orientation, boolean reverseLayout)
{
/* Initially set spanCount to 1, will be changed automatically later. */
super(context, 1, orientation, reverseLayout);
setColumnWidth(checkedColumnWidth(context, columnWidth));
}
private int checkedColumnWidth(Context context, int columnWidth)
{
if (columnWidth <= 0)
{
/* Set default columnWidth value (48dp here). It is better to move this constant
to static constant on top, but we need context to convert it to dp, so can't really
do so. */
columnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48,
context.getResources().getDisplayMetrics());
}
else
{
columnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, columnWidth,
context.getResources().getDisplayMetrics());
}
return columnWidth;
}
public void setColumnWidth(int newColumnWidth)
{
if (newColumnWidth > 0 && newColumnWidth != mColumnWidth)
{
mColumnWidth = newColumnWidth;
mColumnWidthChanged = true;
}
}
#Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state)
{
int width = getWidth();
int height = getHeight();
if (mColumnWidthChanged && mColumnWidth > 0 && width > 0 && height > 0)
{
int totalSpace;
if (getOrientation() == VERTICAL)
{
totalSpace = width - getPaddingRight() - getPaddingLeft();
}
else
{
totalSpace = height - getPaddingTop() - getPaddingBottom();
}
int spanCount = Math.max(1, totalSpace / mColumnWidth);
setSpanCount(spanCount);
mColumnWidthChanged = false;
}
super.onLayoutChildren(recycler, state);
}
}
Then you simply have to change:
gridLayoutManager = new GridLayoutManager(getApplicationContext(), 3);
and use your custom grid layout object, here 100 is the width of columns in dp
gridLayoutManager = new GridAutofitLayoutManager(getApplicationContext(), 100);
You can do something like this:
For the layout of the grid/list use a merge:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ViewStub android:id="#+id/list"
android:inflatedId="#+id/showlayout"
android:layout="#layout/list_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"/>
<ViewStub android:id="#+id/grid"
android:inflatedId="#+id/showlayout"
android:layout="#layout/grid_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"/>
</merge>
then define the layout for the list and the grid (and also for their items), and manage the passage between them inflating the layouts, and then use a method like this to change the current view:
private void changeView() {
//if the current view is the listview, passes to gridview
if(list_visibile) {
listview.setVisibility(View.GONE);
gridview.setVisibility(View.VISIBLE);
list_visibile = false;
setAdapters();
}
else {
gridview.setVisibility(View.GONE);
listview.setVisibility(View.VISIBLE);
list_visibile = true;
setAdapters();
}
}
If you need the complete code, it is available in this article:
http://pillsfromtheweb.blogspot.it/2014/12/android-passare-da-listview-gridview.html
Just take a GridView object instead of Listview like :
GridView gridView;
gridView= (GridView) this.findViewById(R.id.gridView1);
And in you getView method of CategoryListAdapter3 do like :
convertView = inflater.inflate(R.layout.your_grid_item_leyout, null);
And at last in onPostExecute of TheTask do like :
gridView.setAdapter(cla);
That's It.
Use GridView instead of below:
Then replace
listview = (HorizontalListView) this.findViewById(R.id.listview2);
to
GridView gridview;
gridview=(GridView) findViewById(R.id.gridview);
Everything else are fine, just set Adapter using GridView object. And you are done.