I want to ask,
I have 2 classes:
1. an activity class (to get data from json)
2. a fragment class (not to do something)
and I want to get data from json of activity via fragment class.
Can be combine Activity and Fragment in a class ? and how to do ?
I combined activity and fragment in a Fragment class, I have used a GridView to get data and display
JSON, execute the AsyncTask in the this Fragment
This is my code after updated 25/10:
public class FeedBackFragment extends Fragment {
ProgressDialog pDialog;
JSONParser jsonParser = new JSONParser();
MyAdapter adapter;
JSONArray manufacturers = null;
// manufacturers JSON url
private static final String URL_MANUFACTURERS ="MYURL";
public FeedBackFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.feedback_gridview_manufacturer, container, false);
GridView gridView = (GridView) view.findViewById(R.id.gridview);
gridView.setAdapter(new MyAdapter(getActivity(), manufacturersList));
gridView.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View view, int arg2, long arg3) {
// on selecting a single manufacturer
// CategoryCarActivity will be launched to show category car inside the manufacturer
Intent i = new Intent(getActivity(), CategoryCarActivity.class);
// send manufacturer id to activity to get list of cars under that manufacturer
String manufacturer_id = ((TextView) view.findViewById(R.id.manufacturer_id)).getText().toString();
i.putExtra("manufacturer_id", manufacturer_id);
startActivity(i);
}
});
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
// manufacturersList = new ArrayList<>();
new LoadAllManufacturers().execute();
}
class LoadAllManufacturers extends AsyncTask<String, String, String> {
/**
* Before starting background thread Show Progress Dialog
* */
#Override
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(getActivity());
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
/**
* After completing background task Dismiss the progress dialog
* **/
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
adapter.notifyDataSetChanged();
// dismiss the dialog after getting all manufacturers
if (pDialog.isShowing())
pDialog.dismiss();
}
}
private class MyAdapter extends BaseAdapter
{
// List<POJOManufacturer> listData = null;
LayoutInflater inflater;
Context context;
public MyAdapter(Context context, ArrayList<HashMap<String, String>> arrayList)
{
// this.context = context;
this.manufacturersList = arrayList;
inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
if (manufacturersList != null)
return manufacturersList.size();
return 0;
}
#Override
public Object getItem(int i)
{
if (manufacturersList != null)
return manufacturersList.get(i);
return null;
}
#Override
public long getItemId(int i)
{
if (manufacturersList != null)
return manufacturersList.get(i).hashCode();
return 0;
}
#Override
public View getView(int i, View convertView, ViewGroup viewGroup)
{
ViewHolder holder;
if (convertView == null)
{
convertView = inflater.inflate(R.layout.gridview_item, null);
holder = new ViewHolder();
holder.name = (TextView) convertView.findViewById(R.id.text);
holder.iconName = (ImageView) convertView.findViewById(R.id.picture);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
holder.name.setText(this.manufacturersList.get(i).getClass().getName());
// holder.iconName.setImageResource(this.manufacturersList.get(i).image);
return convertView;
}
public class ViewHolder
{
TextView name;
ImageView iconName;
}
}
}
I have updated and added: manufacturerList = new ArrayList<>. everything seem is better, and it happen some issues in getView() method,
I have try and it's only display with 7 empty items in gridview, and not display content and image
So How fill data from Adapter into Gridview?
constructor ManufacturerFragment in class ManufacturerFragment cannot be applied to given types;
gridView.setAdapter() takes an adapter, not a Fragment
And new ManufacturerFragment() doesn't accept an Context.
I am not really sure why you think you need to create a new ManufacturerFragment within the Fragment class you already are in. Did you mean to do gridView.setAdapter(new MyAdapter(getActivity()))?
Also, your manufacturersList needs to be loaded into that adapter, so you'll need to figure that out.
And you need to use getActivity() instead of getActivity().getApplicationContext() in most places.
Then, you should only call new LoadAllManufacturers().execute(); in either onCreateView or onActivityCreated, not both. Otherwise, you're running two AsyncTasks.
Then, onPostExecute already runs on the UI thread, no need to use getActivity().runOnUiThread(new Runnable() {...
Once you do figure out how to put that ArrayList into the Adapter class, you'll want to call adapter.notifyDataSetChanged() within onPostExecute to tell the adapter to refresh the data, thereby updating the GridView to display the data.
Related
I am having issues converting my previously working FragmentActivity and Customlistadapter to a ListFragment to be used with my navigation drawer. Currently, the navigation drawer is working correctly.
Below is the modified code for GetContacts
public class GetContacts extends android.support.v4.app.ListFragment {
// Log tag
private static final String TAG = MainActivity.class.getSimpleName();
// json URL
private static final String url = "http://url.json.php";
private ProgressDialog pDialog;
private List<Contacts> contactList = new ArrayList<Contacts>();
private ListView listView;
private ContactListAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootview = inflater.inflate(R.layout.fragment_contacts, container, false);
return rootview;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//See the second issue about wotking with ListFragment's list.
adapter = new ContactListAdapter(this, contactList);
setListAdapter(adapter);
// pDialog = new ProgressDialog(this);
// Showing progress dialog before making http request
// pDialog.setMessage("Loading...");
//pDialog.show();
// Creating volley request obj
JsonArrayRequest contactReq = new JsonArrayRequest(url,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
hidePDialog();
// Parsing json
for (int i = 0; i < response.length(); i++) {
try {
JSONObject obj = response.getJSONObject(i);
Contacts contacts = new Contacts();
contacts.setDivision(obj.getString("Division"));
contacts.setName(obj.getString("name"));
contacts.setNumber(obj.getString("number"));
// adding contacts to contacts array
contactList.add(contacts);
} catch (JSONException e) {
e.printStackTrace();
}
}
// notifying list adapter about data changes
// so that it renders the list view with updated data
adapter.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
hidePDialog();
}
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(contactReq);
//end volley code paste
}
public void onDestroy() {
super.onDestroy();
hidePDialog();
}
private void hidePDialog() {
if (pDialog != null) {
pDialog.dismiss();
pDialog = null;
}
}
}
Additionally, I have modified the code for ContactListAdapter. Currently I am getting the following compile error. "Error:(49, 56) error: cannot find symbol method getContext()". I checked this SO question and tried to understand what is causing this issue with no luck.
public class ContactListAdapter extends BaseAdapter {
private Activity activity;
private Fragment fragment;
private LayoutInflater inflater;
private List<Contacts> contactItems;
public ContactListAdapter(Fragment fragment, List<Contacts> contactItems) {
this.fragment = fragment;
this.contactItems = contactItems;
}
#Override
public int getCount() {
return contactItems.size();
}
#Override
public Object getItem(int location) {
return contactItems.get(location);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null){
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.list_rowcontacts, null);
}
TextView division = (TextView) convertView.findViewById(R.id.division);
TextView name = (TextView) convertView.findViewById(R.id.name);
TextView number = (TextView) convertView.findViewById(R.id.number);
// getting contact data for the row
Contacts m = contactItems.get(position);
// Division
division.setText(m.getDivision());
// Name
name.setText("Name: " + m.getName());
// number
number.setText("Number: " + m.getNumber());
return convertView;
}
}
The main problem is that a FragmentActivity isn't a Fragment, is an Activity (see the reference here). You can't instantiate it as a Fragment like you do in selectItem().
If you want contacts to be loaded in your main activity (the one with the navigation drawer) then GetContacts should inherit from Fragment instead of FragmentActivity.
UPDATE
There are three issues with your code.
Null pointer exception (setting the adapter in the right place)
First you should move everything related to setting up the adapter to a method that is called after the Fragment is attached to its Activity (more info about the Fragment's lifecycle here). In onCreateView the Activity hasn't attached the Fragment yet so the Context of the adapter won't be available (see the third issue). Override onAttach() and place it there:
public class GetContacts extends ListFragment {
// Log tag
private static final String TAG = MainActivity.class.getSimpleName();
// json URL
private static final String url = "http://url.json.php";
private ProgressDialog pDialog;
private List<Contacts> contactList = new ArrayList<Contacts>();
private ListView listView;
public ContactListAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_contacts, container, false);
return rootView;
}
#Override
public void onAttach(Activity activity) {
//See the third issue about the Context passed to the adapter.
adapter = new ContactListAdapter(activity, contactList);
//See the second issue about working with ListFragment's list.
setListAdapter(adapter);
// pDialog = new ProgressDialog(this);
// Showing progress dialog before making http request
// pDialog.setMessage("Loading...");
//pDialog.show();
// Creating volley request obj
JsonArrayRequest contactReq = new JsonArrayRequest(url,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
hidePDialog();
// Parsing json
for (int i = 0; i < response.length(); i++) {
try {
JSONObject obj = response.getJSONObject(i);
Contacts contacts = new Contacts();
contacts.setDivision(obj.getString("Division"));
contacts.setName(obj.getString("name"));
contacts.setNumber(obj.getString("number"));
// adding contacts to contacts array
contactList.add(contacts);
} catch (JSONException e) {
e.printStackTrace();
}
}
// notifying list adapter about data changes
// so that it renders the list view with updated data
adapter.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
hidePDialog();
}
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(mcontactReq);
//end volley code paste
}
public void onDestroy() {
super.onDestroy();
hidePDialog();
}
private void hidePDialog() {
if (pDialog != null) {
pDialog.dismiss();
pDialog = null;
}
}
}
Null pointer exception (working with ListFragment's list
ListFragments provide some methods like setListAdapter() to work with the inner ListView without having to get it first with findViewById(), but they work with their "default" ListView. For identifying this ListView they look in the layout for a ListView with the id #id/android:list. You're using a custom id for your ListView so setListAdapter() cannot find the default ListView (more info about ListFragment here). You have three posible solutions:
First:
If your layout doesn't contain more than a ListView you don't have to use a custom layout. Don't override onCreateView, removing everything about inflating a custom view.
Second:
Change the id of your ListView to #id/android:list in the xml layout file.
Third:
Maintain your custom layout and id, but always use the ListView getting it first with findViewById(), not with the ListFragment's methods for dealing with lists (like when GetContacts was a FragmentActivity). So this:
listView = (ListView) rootView.findViewById(android.R.id.list);
adapter = new ContactListAdapter(this, contactList);
setListAdapter(adapter);
would become this:
listView = (ListView) getView().findViewById(android.R.id.list);
adapter = new ContactListAdapter(this, contactList);
listView.setListAdapter(adapter);
The first two allow you to work with the default list. I don't recomend you to go for the third, since ListFragments are designed for helping you in dealing with lists faster and you wouldn't be using their helper methods, and therefore using a ListFragment like any other Fragment.
P.S. The code for GetContacts I posted before use the second solution.
LayoutInflater in Adapter
With BaseAdapter you have to keep a reference of the Context in wich the adapter will work. Since Fragment isn't a Context, fragments have to use the Activity they're attached to as the Context. Look a this line in the GetContact's code I just updated (in GetContact's onAttached()):
adapter = new ContactListAdapter(activity, contactList);
Then in the adapter you use that as the Context to get the LayoutInflater:
public class ContactListAdapter extends BaseAdapter {
//There is no need for this two
//private Activity activity;
//private Fragment fragment;
//We use this instead
private Context context
private LayoutInflater inflater;
private List<Contacts> contactItems;
//Now the constructor receives a Context
public ContactListAdapter(Context context, List<Contacts> contactItems) {
this.context = context;
this.contactItems = contactItems;
}
//Every other method remains the same
...
#Override
public View getView(int position, View convertView, ViewGroup parent) {
//Now we use context to get the LayoutInflater
if (convertView == null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.list_rowcontacts, null);
}
//The rest of the code is the same
...
}
}
EDIT
Added the changed code for the "set up the adapter in the right place".
Changed the third issue for using a BaseAdapter (I got confused).
i have parsed Json data from the server. On which im showing all the data in listview and i have Load more option below the ListView. Now when i click load more option, this application reload whole list and did not show previous list data. Please help me find out the solution. Here is footer view click listener :
lFooter.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
page += 1;
new ParseIssues().execute();
listView.removeFooterView(v);
}
});
in above code ParseIssues class parse json values and displays all the data in ListView Here is code for onPostExecute of AsynkTask class :
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if(page < totalPage){
listView.addFooterView(v);
}
listAdapter = new ListAdapterForSearch(activity, mainList);
listView.setAdapter(listAdapter);
// get listview current position - used to maintain scroll position
int currentPosition = listView.getFirstVisiblePosition();
listView.setSelection(currentPosition);
}
Here is BaseAdapter class:
public class ListAdapterForSearch extends BaseAdapter {
private Activity activity;
private ArrayList<HashMap<String, String>> data;
private static LayoutInflater inflater = null;
public ListAdapterForSearch(Activity a, ArrayList<HashMap<String, String>> d) {
activity = a;
data = d;
inflater = LayoutInflater.from(activity);
}
#Override
public int getCount() {
return data.size();
}
#Override
public Object getItem(int position) {
return data.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
View vi = convertView;
if (convertView == null) {
vi = inflater.inflate(R.layout.list_row_item, null);
}
TextView title = (TextView)vi.findViewById(R.id.title);
HashMap<String, String> hash = new HashMap<String, String>();
hash = data.get(position);
title.setText(hash.get("title"));
return vi;
}
}
The answer to your question lies with the variable "mainList", which the adapter uses. You need to add the new data to it, basically this list needs to contain all the data you want to show in your ListView.
You should set adapter on create, after that first add loaded data to mainlist(add new loaded data) & then after loading notify adapter like listadapter.notifydatachange()
Edit: Because every time you are creating adapter that's why you are facing this problem, instead after loading just notify your adapter..
Check in your code you may have clear your mainList.
I have ListView with items. I'm using XML to parse data. In that moment I parse data for one item in DetailsView. When I clicked on item, how to make DetailsView for items with SwipeViews beetween items? How to implement with ViewPager? I try to develop some examples, but didn't work. I would be grateful if someone help me.
So first create a Fragment for your detail. This is for a single detail. The detail that you'll swipe. So apply your layout to this.
#SuppressLint("ValidFragment")
public class Detail extends Fragment {
private final String detail;
public DetailView(String detail) {
this.detail = detail;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.detailfragment, container, false);
TextView textView = (TextView) view.findViewById(R.id.detailText);
textView.setText(detail);
return view;
}
}
Now create your Activity. This is the Activity that you will go when you clicked. Now the code adds a Fragment for every detail.
public class Main extends FragmentActivity {
public static ViewPager mPager;
private MyAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mPager = (ViewPager) findViewById(R.id.viewPager1);
mAdapter = new MyAdapter(getSupportFragmentManager());
mPager.setAdapter(mAdapter);
}
public static class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public int getCount() {
//The count of details. This will return 5 swipeable views.
return 5;
}
#Override
public Fragment getItem(int position) {
return new Detail("I'm a detail!");
}
}
}
This will create 5 details with text "I'm a detail!". Now, i assume you are using ArrayList that storing details. Then you can get the details like this:
public static class MyAdapter extends FragmentPagerAdapter {
public MyAdapter(FragmentManager fm, ArrayList<HashMap<String, String>> d) {
super(fm);
data = d;
}
#Override
public int getCount() {
return 5;
}
#Override
public Fragment getItem(int position) {
HashMap<String, String> map = new HashMap<String, String>();
map = data.get(position);
Log.d("", data.get(position).toString());
return new Detail(map.get('KeyForYourDetail'));
}
}
Also on your MainActivity change
mAdapter = new MyAdapter(getSupportFragmentManager());
to this
mAdapter = new MyAdapter(getSupportFragmentManager(), yourArrayList);
EDIT
Let's start from the beginning. First, you have your MainActivity which contains a ListView. In the ListView, you are calling items from ArrayList. When you click a item, you get the detail about it from (?). Now my above code can't do that. You have to do that your own first. After you get the detail, just replace the title part below. To summarize, the code i post should work if you can get the "detail", if you don't know how to get detail, then you should create another question.
return new Detail(title);
EDIT 2
OK, here is the other part. Below code is for FragmentActivity.
First, we need to declare our adapter and ViewPager.
public static ViewPager mPager;
private MyAdapter mAdapter;
ArrayList<HashMap<String, String>> detailList= new ArrayList<HashMap<String, String>>();
MyAdapter is the adapter that puts the details into ViewPager. To hold details, we also need an ArrayList as i declared above. Now, you said you don't have problem with parsing. So I'm skipping that part. While you're parsing, I assume you are using NodeList(i took that part from here)
NodeList nl = doc.getElementsByTagName(KEY_ITEM);
// looping through all item nodes
for (int i = 0; i < nl.getLength(); i++) {
String name = parser.getValue(e, KEY_NAME); // name child value
String cost = parser.getValue(e, KEY_COST); // cost child value
String description = parser.getValue(e, KEY_DESC); // description child value
}
Inside of your for loop, create a HashMap like this
HashMap<String, String> map = new HashMap<String, String>();
Remember while we were creating our ArrayList? It's object was HashMap. Now we are going to fill our data to map, then add map to ArrayList. (Again, this goes inside of for loop)
map.put(TAG_DETAIL, detail);
detailList.add(map);
Now this part is over, only thing left is setting the adapter.
mAdapter = new MyAdapter(getSupportFragmentManager(), detailList);
mPager.setAdapter(mAdapter);
And we are done! Let me explain what's going to happen next. Do you remember our adapter?
public MyAdapter(FragmentManager fm, ArrayList<HashMap<String, String>> d) {
super(fm);
data = d;
}
Here as you see, it takes a FragmentManger and an ArrayList with Hashmap inside of it. we set those with getSupportFragmentManager() and detailList. Adapter takes the detailList with details inside of it, then creates Fragments with it. I hope it was clear enough. If wasn't, ask again.
This is the code of MyAdapter.java:
public class MyAdapter extends ArrayAdapter {
ImageLoader imageLoader;
DisplayImageOptions options;
public MyAdapter(Context ctx, int textViewResourceId, List<NewsFeed> sites) {
super(ctx, textViewResourceId, sites);
//Setup the ImageLoader, we'll use this to display our images
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(ctx).build();
imageLoader = ImageLoader.getInstance();
imageLoader.init(config);
//Setup options for ImageLoader so it will handle caching for us.
options = new DisplayImageOptions.Builder()
.cacheInMemory()
.cacheOnDisc()
.build();
}
/*
* (non-Javadoc)
* #see android.widget.ArrayAdapter#getView(int, android.view.View, android.view.ViewGroup)
*
* This method is responsible for creating row views out of a StackSite object that can be put
* into our ListView
*/
#Override
public View getView(int pos, View convertView, ViewGroup parent){
RelativeLayout row = (RelativeLayout)convertView;
Log.i("Feed", "getView pos = " + pos);
// if(null == row){
// //No recycled View, we have to inflate one.
// LayoutInflater inflater = (LayoutInflater)parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// row = (RelativeLayout)inflater.inflate(R.layout.list_item, null);
// }
if (pos != 0){
LayoutInflater inflater = (LayoutInflater)parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = (RelativeLayout)inflater.inflate(R.layout.list_item, null);
}
else
{
//No recycled View, we have to inflate one.
LayoutInflater inflater = (LayoutInflater)parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = (RelativeLayout)inflater.inflate(R.layout.list_first_item, null);
}
//Get our View References
final ImageView iconImg = (ImageView)row.findViewById(R.id.iconImg);
TextView titleTxt = (TextView)row.findViewById(R.id.titleTxt);
final ProgressBar indicator = (ProgressBar)row.findViewById(R.id.progress);
//Initially we want the progress indicator visible, and the image invisible
indicator.setVisibility(View.VISIBLE);
iconImg.setVisibility(View.INVISIBLE);
//Setup a listener we can use to swtich from the loading indicator to the Image once it's ready
ImageLoadingListener listener = new ImageLoadingListener(){
#Override
public void onLoadingStarted(String arg0, View arg1) {
// TODO Auto-generated method stub
}
#Override
public void onLoadingCancelled(String arg0, View arg1) {
// TODO Auto-generated method stub
}
#Override
public void onLoadingComplete(String arg0, View arg1, Bitmap arg2) {
indicator.setVisibility(View.INVISIBLE);
iconImg.setVisibility(View.VISIBLE);
}
#Override
public void onLoadingFailed(String arg0, View arg1, FailReason arg2) {
// TODO Auto-generated method stub
}
};
//Load the image and use our options so caching is handled.
imageLoader.displayImage(getItem(pos).getImgUrl(), iconImg,options, listener);
//Set the relavent text in our TextViews
titleTxt.setText(getItem(pos).getTitle());
return row;
}
}
I've tried searching for a solution for this problem for a couple of days and I'm stumped.
Here's what I have so far:
Custom BaseAdapter class:
public static class ImageAdapter extends BaseAdapter {
private static LayoutInflater mInflater;
// Keep all Images in array
private static Bitmap[] mThumbIds;
private static int mViewResourceId, pos;
private static CheckBox cb;
// Constructor
public ImageAdapter(Context ctx, int viewResourceId, Bitmap[] pics) {
mInflater = (LayoutInflater) ctx
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mThumbIds = pics;
mViewResourceId = viewResourceId;
}
#Override
public int getCount() {
return mThumbIds.length;
}
#Override
public Object getItem(int position) {
return mThumbIds[position];
}
#Override
public long getItemId(int position) {
return 0;
}
#SuppressWarnings("deprecation")
#Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = mInflater.inflate(mViewResourceId, list, false);
cb = (CheckBox) convertView.findViewById(R.id.select);
Drawable background = new BitmapDrawable(mThumbIds[position]);
cb.setBackgroundDrawable(background);
pos = position;
System.out.println("Setting checkbox set: "+imageIsDup[pos]);
cb.setChecked(imageIsDup[pos]);
System.out.println("Has checkbox been set? "+cb.isChecked());
cb.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (cb.isChecked()) {
imageIsDup[pos] = true;
} else
imageIsDup[pos] = false;
}
});
return convertView;
}
}
Code for setting the gridView:
final Dialog dialog = new Dialog(longOperationContext);
dialog.setContentView(R.layout.activity_list);
TextView no = (TextView) dialog
.findViewById(R.id.noOfDups);
no.setText("Found " + noOfImages
+ " duplicates. Please verify.");
dialog.setTitle("Images Found");
dialog.setCancelable(false);
list = (GridView) dialog
.findViewById(R.id.grid_view);
ImageAdapter empty=new ImageAdapter(longOperationContext, R.layout.row, new Bitmap[0]);
imageAdapter = new ImageAdapter(
longOperationContext, R.layout.row, thumb);
dialog.show();
imageAdapter.notifyDataSetChanged();
list.invalidateViews();
list.setAdapter(empty);
list.setEmptyView(new View(longOperationContext));
list.invalidateViews();
list.setAdapter(imageAdapter);
I assumed that this code would set the gridView to an empty view in the beginning and then to the adapter's contents.
I read from the documentation that the removeView functions cannot be called as they throw an Unsupported Exception. How do I clear the previous contents of the grid view if any and set the new contents?
The whole idea with refreshing adapter's elements in Android is just repopulate them using the same array of objects. For example if I have a GridView like in your case and I want to repopulate the objects the thing you need to do is declare an array of objects first :
private ArrayList<Object> mMyObjects;
populate it with data and create your adapter.
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
mMyObjects = new ArrayList<Object>();
mMyObject.add("StringObject"); // just an example
mMyAdapter = new MyCustomAdapter(this, mMyObject);
mMyGridView.setAdapter(mMyAdapter);
}
So we populate the array of objects and create our adapter. The thing we should do before updating the adapter / gridview's children is just repopulate your array :
mMyObjects.clear();
mMyObjects.add("NewStringObject");
and call : mMyAdapter.notifySetDataChanged(); Doing that BaseAdapter knows that there are changes in out data and it's redrawing it's views and your ListView / GridView will get updated with the new items.
So in your case, to update your GridView just need to clear your array of bitmaps and repopulate it.
I solved my problem with this piece of code:
try{
imageAdapter.notifyDataSetChanged();
}
catch(NullPointerException e)
{
imageAdapter = new ImageAdapter(
longOperationContext, R.layout.row, thumb);
}
I should write in the title instead of 'doesn't work' something like 'I
don't know how to do it' but the first version feels better :).
What I am trying to do is the following:
Download the xml from the web, parse it and create ArrayList of some
objects (done and working)
Display the objects using custom Adapter (doesn't work)
The second one works if I add the items to my ArrayList before I add it to
the view using
m_orderAdapter = new OrderAdapter(this,m_orders); //code for orderadapter
below
setListAdapter(m_orderAdapter);
I have found on the web something like this: (in my onCreate method)
handler = new Handler();
viewOrders = new Runnable(){
#Override
public void run() {
getOrders();
}
};
new Thread(){
#Override
public void run(){
handler.post(viewOrders);
}
}.start();
then, the following code for the methods:
private void getOrders(){
try{
OrderManager om = new OrderManager();
m_orders = om.getOrdersFromWeb();
Log.i("ARRAY", ""+ m_orders.size());
} catch (Exception e) {
Log.e("BACKGROUND_PROC", e.getMessage());
}
runOnUiThread(returnRes);
}
OrderManager downloads and parse the xml into Order objects and returns
array list of those. Then I set this list to my member array list m_orders.
Once downloading and parsing is done I run returnRes method on the ui thread
using runOnUiThread method
private Runnable returnRes = new Runnable() {
#Override
public void run() {
if(m_orders != null && m_orders.size() > 0){
Log.i("ORDER",m_orders.get(0).getOrder_id());
setListAdapter(m_orderAdapter);
m_orderAdapter.notifyDataSetChanged();
}
m_orderAdapter.notifyDataSetChanged();
}
};
and I call notifyDataSetChanged() on my adapter.
The view I do all this stuff extends ListView and the code for the adapter
itself is listed below:
public class OrderAdapter extends BaseAdapter{
private Context ctx;
private List<Order> orders;
public OrderAdapter(Context ctx, List<Order> orderLst){
this.ctx = ctx;
this.orders = orderLst;
}
#Override
public int getCount() {
return orders.size();
}
#Override
public Object getItem(int pos) {
return orders.get(pos);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Order o = orders.get(position);
return new OrderListAdapterView(this.ctx,o);
}
}
When I debug I have the data inside my m_orders list but when I call
notifyDataSetChanged nothing happens, I've read that I have to execute that
on the UI thread which I think I do. So whats the problem ?
any help highly appreciated, or maybe just a link to the nice tutorial on
the web explaining this issue on how to update the list view at runtime ?
Hey Arutha - why don't you see my answer for this post - I think it is what you need.
Or just let me repost it here
You can extend ArrayAdapter. Here's code example for you. In this example - SearchItem is some custom POJO. Basically you need to override getView() method to build your row by inflating row layout and then populating values based on List of items and current position
class SearchItemsAdapter extends ArrayAdapter<SearchItem> {
Activity context;
List<SearchItem> items;
SearchHeader header;
#SuppressWarnings("unchecked")
public SearchItemsAdapter(final Activity context,
final Map<SearchHeader, List<SearchItem>> result) {
super(context, R.layout.item, (List) ((Object[]) result.values()
.toArray())[0]);
this.context = context;
this.header = result.keySet().iterator().next();
this.items = result.get(this.header);
}
#Override
public View getView(final int position, final View convertView,
final ViewGroup parent) {
final View view = this.context.getLayoutInflater().inflate(
R.layout.item, null);
final SearchItem item = this.items.get(position);
((TextView) view.findViewById(R.id.jt)).setText(item.jt);
((TextView) view.findViewById(R.id.dp)).setText(item.dp);
((TextView) view.findViewById(R.id.cn)).setText(item.cn);
((TextView) view.findViewById(R.id.loc)).setText(item.loc.name);
final TextView body = ((TextView) view.findViewById(R.id.e));
body.setText(item.e);
body.setTag(item.src[0]);
((TextView) view.findViewById(R.id.src)).setText(item.src[1]);
return view;
}
}