Android: How to write customize array adapter for objects - android

I am trying to make customize array adapter that can be used for object "data"
public class theAdapter extends ArrayAdapter {
private ArrayList <listToDo> list;
public theAdapter(Context context, ArrayList<listToDo>list) {
super(context, R.layout.my_layout, list);
this.list = list;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(R.layout.my_layout,parent,false);
listToDo activity = (listToDo) getItem(position);
TextView theTextView = (TextView) view.findViewById(R.id.textView);
theTextView.setText(activity.things);
CheckBox checkBox = (CheckBox) view.findViewById(R.id.checkbox);
checkBox.setChecked(activity.checked);
return view;
}
}
However, this prints out same thing over and over again.
For instance if the ArrayList has 1,2,3,4,5. (this is not exact object I have)
It prints out 5,5,5,5,5.
EDIT---------------------------------
protected void dataRead (){
File f = new File( Environment.getExternalStorageDirectory(),"user.txt");
listToDo original = new listToDo ();
try {
FileInputStream fis = new FileInputStream(f);
InputStreamReader temp = new InputStreamReader(fis);
BufferedReader bis = new BufferedReader(temp);
String activity;
while ((activity = bis.readLine()) != null){
String[] parts = activity.split("\t");
original.things = parts[0];
if (parts[1] == "1"){
original.checked=true;
}
else{
original.checked=false;
}
data.add(original);
Log.v(TAG, original.things);
}
for (int i =0; i < data.size(); i++){
Log.d(TAG,data.get(i).things);
}
bis.close();
}
catch (Exception e) {
}
}

Explanation : the current way you are creating your list items only ever creates ONE listToDo named "original" and changes the values in it during each loop. Also in the loop you add the same original object over again for however many lines you have in user.txt. So, lets move the listToDo instance creation inside your loop so it will create a new listTodo class object named original each loop, set some values (checked and things), and then add to the data List
protected void dataRead (){
File f = new File( Environment.getExternalStorageDirectory(),"user.txt");
try {
FileInputStream fis = new FileInputStream(f);
InputStreamReader temp = new InputStreamReader(fis);
BufferedReader bis = new BufferedReader(temp);
String activity;
while ((activity = bis.readLine()) != null){
listToDo original = new listToDo ();
String[] parts = activity.split("\t");
original.things = parts[0];
if ("1".equals(parts[1])) {
original.checked=true;
}
else{
original.checked=false;
}
data.add(original);
Log.v(TAG, original.things);
}
for (int i =0; i < data.size(); i++){
Log.d(TAG,data.get(i).things);
}
bis.close();
}
catch (Exception e) {
}
}
Also, I think your adapter class is a bit off.
public class theAdapter extends ArrayAdapter<listToDo> {
public theAdapter(Context context, ArrayList<listToDo> list) {
super(context, R.layout.my_layout, list);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
listToDo activity = (listToDo) getItem(position);
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.my_layout, parent, false);
}
TextView theTextView = (TextView) convertView.findViewById(R.id.textView);
theTextView.setText(activity.things);
CheckBox checkBox = (CheckBox) convertView.findViewById(R.id.checkbox);
checkBox.setChecked(activity.checked);
return convertView;
}
}
Here is a full on tutorial just in case :
https://github.com/codepath/android_guides/wiki/Using-an-ArrayAdapter-with-ListView

Related

ArrayAdapter views duplicating after scrolling list

I created a custom ArrayAdapter and inside the ArrayAdapter there's a LinearLayout that adds views via iteration. Now after showing the data that needs to be shown on a ListView all will be well until I scroll down or up the list, when a row undergoes recycling and binding the new view to display on the recycled row I get duplicates, however this duplicates have show no data(text) on the views. Here is the view ListView before scrolling
https://postimg.org/image/z36eqhacd/
and here is the ListView after scrolling
https://postimg.org/image/dzv28kj9t/
I've tried multiple methods but can't seem to get it to work.
public class SurveyAdapter extends ArrayAdapter<SurveyModel> {
public SurveyAdapter(Context context, ArrayList<SurveyModel> objects) {
super(context, R.layout.survey_card, objects);
}
#NonNull
#Override
public View getView(int position, View convertView, #Nullable ViewGroup parent) {
//Get the data item for this position
SurveyModel surveyModel = getItem(position);
//Construct the ViewHolder
ViewHolder viewHolder = new ViewHolder();
//Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
//If there's no view to re-use, inflate a new view for a row
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.survey_card, parent, false);
viewHolder.mContainer = (LinearLayout) convertView.findViewById(R.id.choice_container);
viewHolder.question = (TextView) convertView.findViewById(R.id.question);
//Cache the viewHolder object inside the new view
convertView.setTag(viewHolder);
} else {
//View is being recycled, retrieve the viewHolder object from tag
viewHolder = (ViewHolder) convertView.getTag();
}
assert surveyModel != null;
//Populate the data from the data object
String choices = surveyModel.getChoice();
//Scan each string separately
//Strings are separated with a comma ','
Scanner scanner = new Scanner(choices).useDelimiter(",\\s*");
//Create an array list to store each string separately
ArrayList<String> choiceList = new ArrayList<>();
//Get all strings from scanner separately
while (scanner.hasNext()) {
String choice = scanner.next(); //Get each string from scanner
choiceList.add(choice); //Store the string in an ArrayList(choiceList)
}
//Convert choiceList(ArrayList) to a StringArray(choiceArray)
String[] choiceArray = choiceList.toArray(new String[choiceList.size()]);
int choiceNum; //Will store number of choices to be displayed
if (choices.contains("Other,true") || choices.contains("Other,false")) {
//Set number or choices to the length(number of items) of the choiceList(ArrayList)
//Minus 1 to avoid showing "true" as an option
choiceNum = choiceArray.length - 1;
} else {
//Set number or choices to the length(number of items) of the array
choiceNum = choiceArray.length;
}
//Get number of choices from choiceNum
final int numOfChoices = choiceNum;
//Populate each choice string from choiceArray
for (int i = 0; i < numOfChoices; i++) {
//Create a new CheckBox for each choice
AppCompatCheckBox checkBox = new AppCompatCheckBox(getContext());
checkBox.setLayoutParams(new LinearLayoutCompat.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
//Add the CheckBox to its survey_view_list view(mContainer)
viewHolder.mContainer.addView(checkBox);
if (viewHolder.mContainer.getChildAt(i) instanceof AppCompatCheckBox) {
//Set each data item in the choiceArray on its own CheckBox according to position
((AppCompatCheckBox) viewHolder.mContainer.getChildAt(i)).setText(choiceArray[i]);
final ViewHolder finalViewHolder = viewHolder; //Get viewHolder for inner class access
final int checkBoxPosition = i; //Set position of the checked CheckBox
((AppCompatCheckBox) viewHolder.mContainer.getChildAt(i)).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
if (checked) {
for (int i = 0; i < numOfChoices; i++) {
//Disable all CheckBoxes when a CheckBox is checked
finalViewHolder.mContainer.getChildAt(i).setEnabled(false);
//Re-enable the checked CheckBox only
finalViewHolder.mContainer.getChildAt(checkBoxPosition).setEnabled(true);
}
} else {
for (int i = 0; i < numOfChoices; i++) {
//Enable all CheckBoxes when the checked CheckBox is unchecked
finalViewHolder.mContainer.getChildAt(i).setEnabled(true);
}
}
}
});
}
}
//Populate the data from the data object via the viewHolder object into the view
viewHolder.question.setText(surveyModel.getQuestion());
//Return the completed view to render on screen
return convertView;
}
//View lookup cache
private static class ViewHolder {
LinearLayout mContainer;
TextView question;
}`
Here is the Object Model
public class SurveyModel {
private String question, choice;
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getChoice() {
return choice;
}
public void setChoice(String choice) {
this.choice = choice;
}
}
Here is the method from the Activity I attach the ArrayAdapter to a ListView
//Method to populate and display data populated from the database
private void populateAndDisplayData() {
//Construct ArrayList
ArrayList<SurveyModel> surveyModelArrayList = new ArrayList<>();
//Construct adapter
SurveyAdapter adapter = new SurveyAdapter(CreateFromScratch.this, surveyModelArrayList);
//Attach the adapter to the ListView
binding.list.setAdapter(adapter);
//Create a ListView
ListView listView = new ListView(CreateFromScratch.this);
//Get all the data from the database
Cursor allDataCursor = tempSurveyDatabase.fetchAllData();
//StringArray to hold the strings from the database
String[] from = new String[]{CustomSurveyDatabase.QUESTION, CustomSurveyDatabase.CHOICES};
//Views to display the string data from StringArray(from)
int[] to = new int[]{R.id.question, R.id.choices};
//Construct a SimpleCursorAdapter
SimpleCursorAdapter simpleCursorAdapter = new SimpleCursorAdapter(CreateFromScratch.this, R.layout.survey_card, allDataCursor, from, to);
// /Attach the adapter to the ListView
listView.setAdapter(simpleCursorAdapter);
//Construct StringBuilder
StringBuilder jsonBuilder = new StringBuilder();
//Strings to hold the item's data from the database
String question = null;
String choices = null;
//Proceed with collecting each item's data if the SimpleCursorAdapter is not empty
if (simpleCursorAdapter.getCount() > 0) {
//Get every item's id from the database
for (int i = 0; i < simpleCursorAdapter.getCount(); i++) {
//Get each item's database id
long itemId = listView.getAdapter().getItemId(i);
//Get each item from the database
try {
//Construct cursor to fetch an item's data from the database
Cursor cursor = tempSurveyDatabase.fetchItem(itemId);
question = tempSurveyDatabase.questionHolder;
choices = tempSurveyDatabase.choiceHolder;
} catch (SQLException e) {
Log.v(TAG, e.getMessage());
}
if (i == 0) {
jsonBuilder.append("{\"survey\": [").append("{\"question\":\"").append(question).append("\",");
jsonBuilder.append("\"choices\":\"").append(choices).append("\"},");
} else {
jsonBuilder.append("{\"question\":\"").append(question).append("\",");
jsonBuilder.append("\"choices\":\"").append(choices).append("\"},");
}
}
//Remove the last comma from the StringBuilder
jsonBuilder.deleteCharAt(jsonBuilder.length() - 1);
//Close JSON file scopes
jsonBuilder.append("]}");
//Save temporary survey file on the SDCARD
try {
//Delete existing temporary survey
if (TEMP_SURVEY.exists()) {
//noinspection ResultOfMethodCallIgnored
TEMP_SURVEY.delete();
}
FileWriter fileWriter = new FileWriter(TEMP_SURVEY);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write(String.valueOf(jsonBuilder));
bufferedWriter.close();
} catch (IOException e) {
Log.v(TAG, "Temp Survey JSON file failed to write.\nReason: " + e.getMessage());
}
//Check if the temporary survey file exists
if (TEMP_SURVEY.exists()) {
//Read the temporary survey file if it exists
new ReadFile(ReadFile.data, ReadFile.output, TEMP_SURVEY);
//Parse JSON string from StringBuilder
try {
JSONObject jsonObjectMain = new JSONObject(ReadFile.output);
JSONArray jsonArray = jsonObjectMain.getJSONArray(SurveyJSONKeys.ARRAY_KEY);
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
SurveyModel surveyModel = new SurveyModel();
surveyModel.setQuestion(jsonObject.getString(SurveyJSONKeys.QUESTION_KEY));
surveyModel.setChoice(jsonObject.getString(SurveyJSONKeys.CHOICES_KEY));
surveyModelArrayList.add(surveyModel);
}
} catch (JSONException e) {
Log.v(TAG, "Unable to parse JSON file.\nReason: " + e.getMessage());
}
//Notify the adapter for changes in order to refresh views
adapter.notifyDataSetChanged();
}
}
}`
Since your item view is recycled every time, the container of your answers are just appended with more answers. You have 2 options:
Remove all child views in your container before populating with answers
Do not force a recycle by using getViewTypeCount() and getItemViewType(int).

Android - Listview .remove() function is not working as expected

I have a listview that is able to delete a specific image via onLongClick, but it isn't working so far. When testing, the dialog appears If i want to delete or not, i press Yes/Ok and the toast appears saying Item deleted, however the item is still there.
UPDATED ( I got the remove and delete function working thanks to user1140237)
UPDATED MAIN ACTIVITY
private String[] FilePathStrings;
private String[] FileNameStrings;
private File[] listFile;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_yearbook);
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"/CapturyGallery");
// Check for SD Card
if (!Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
Toast.makeText(this, "Error! No SDCARD Found!", Toast.LENGTH_LONG)
.show();
} else {
// Locate the image folder in your SD Card
file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"/CapturyGallery");
// Create a new folder if no folder named CapturyGallery exist
file.mkdirs();
}
if (file.isDirectory())
{
listFile = file.listFiles();
// Create a String array for FilePathStrings
FilePathStrings = new String[listFile.length];
// Create a String array for FileNameStrings
FileNameStrings = new String[listFile.length];
for (int i = 0; i < listFile.length; i++)
{
//Get the path image file
FilePathStrings[i] = listFile[i].getAbsolutePath();
// Get the name image file
FileNameStrings[i] = listFile[i].getName();
}
}
Arrays.sort(listFile);
final ListAdapter listAdapter = new CustomAdapter(Yearbook.this, FilePathStrings, FileNameStrings);
ListView lv = (ListView) findViewById(R.id.ListingView);
lv.setAdapter(listAdapter);
final ArrayList<String> list = new ArrayList(Arrays.asList(FilePathStrings));
lv.setOnItemClickListener(this);
lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {
//Deletes item
AlertDialog.Builder adb=new AlertDialog.Builder(Yearbook.this);
adb.setTitle("Delete?");
adb.setMessage("Are you sure you want to delete " + FileNameStrings[position]);
final int positionToRemove = position;
adb.setNegativeButton("Cancel", null);
adb.setPositiveButton("Ok", new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
File file = new File(list.get(positionToRemove));
if (file.delete()) {
list.remove(position);
((CustomAdapter) listAdapter).updateMyData(FilePathStrings, FileNameStrings);
Toast.makeText(getApplicationContext(), FileNameStrings[position] + " deleted", Toast.LENGTH_LONG).show();
}
}
});
adb.show();
return true;
}
});
}
CUSTOMADAPTER
public class CustomAdapter extends BaseAdapter {
private Activity activity;
private String[] filepath;
private String[] filename;
private static LayoutInflater inflater = null;
public CustomAdapter(Activity a, String[] fpath, String[] fname) {
activity = a;
filepath = fpath;
filename = fname;
inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void updateMyData(String[] fpath, String[] fname) {
filepath = fpath;
filename = fname;
notifyDataSetChanged();
}
#Override
public int getCount() {
return filepath.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
class MyViewHolder {
ImageView myImage;
TextView timestamp;
TextView myName;
TextView myHeader;
MyViewHolder(View v) {
myImage = (ImageView) v.findViewById(R.id.PicView);
timestamp = (TextView) v.findViewById(R.id.timestamp);
myName = (TextView) v.findViewById(R.id.myName);
myHeader = (TextView) v.findViewById(R.id.textSeparator);
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
MyViewHolder holder = null;
if (vi == null) {
vi = inflater.inflate(R.layout.custom_row, null);
holder = new MyViewHolder(vi);
vi.setTag(holder);
} else {
holder = (MyViewHolder) vi.getTag();
}
Bitmap bmp = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(filepath[position]),100,100);
holder.myImage.setImageBitmap(bmp);
//PicImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
holder.myImage.setPadding(8, 8, 8, 8);
//Set Title
holder.myName.setText(filename[position]);
ExifInterface intf = null;
try {
intf = new ExifInterface(filepath[position]);
} catch(IOException e) {
e.printStackTrace();
}
if(intf != null) {
String dateString = intf.getAttribute(ExifInterface.TAG_DATETIME);
holder.timestamp.setText("Date Taken: " + dateString.toString());
}
return vi;
}
And so my last problem is, whenever i remove something from my listview it crashed. However, the file was indeed removed. Im not sure what is the error because i tested it on my mobile phone
You need to update list data in your custom adapter too. after removing than call notifydatasetchanged
Keep below method in you customadapter to udpate list data & after that call it in longpress
public void updateMyData(String[] fpath, String[] fname) {
filepath = fpath;
filename = fname;
notifyDataSetChanged();
}
You need to call this from longPress
list.remove(position);
((CustomAdapter )listAdapter).updateMyData( FilePathStrings, FileNameStrings); /// here in your case you need to define both array global sorry not time to clean up your code
Toast.makeText(getApplicationContext(), FileNameStrings[position] +" deleted",Toast.LENGTH_LONG).show();
UPDATED
To remove file from the mentioned dir & updating listview you need to delete file from that location first and than you need to update listview
File file = new File(list.get(position));
if (file.delete()) {// this will required permission in Manifest for Write_EXTERNAL_STORATE
// if file is deleted from SD CARD
list.remove(position);
((CustomAdapter )listAdapter).updateMyData( FilePathStrings, FileNameStrings); /// here in your case you need to define both array global sorry not time to clean up your code
Toast.makeText(getApplicationContext(), FileNameStrings[position] + " deleted", Toast.LENGTH_LONG).show();
}
*CustomAdapter *
public class CustomAdapter extends BaseAdapter {
private Activity activity;
private ArrayList<String> filepath;
private ArrayList<String> filename;
private JSONArray jListData;
private int size = 0;
public CustomAdapter(Activity a, JSONArray jListData) {
activity = a;
this.jListData = jListData;
if (filepath != null)
size = jListData.length();
}
public void updateMyData(JSONArray jListData) {
this.jListData = jListData;
size = jListData.length();
notifyDataSetChanged();
}
#Override
public int getCount() {
return size;
}
public JSONObject getItem(int position) {
try {
return (JSONObject) jListData.get(position);
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
public long getItemId(int position) {
return position;
}
class MyViewHolder {
ImageView myImage;
TextView timestamp;
TextView myName;
TextView myHeader;
MyViewHolder(View v) {
myImage = (ImageView) v.findViewById(R.id.PicView);
timestamp = (TextView) v.findViewById(R.id.timestamp);
myName = (TextView) v.findViewById(R.id.myName);
myHeader = (TextView) v.findViewById(R.id.textSeparator);
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
MyViewHolder holder = null;
try {
if (vi == null) {
vi = LayoutInflater.from(activity).inflate(R.layout.custom_row, parent, false);
holder = new MyViewHolder(vi);
vi.setTag(holder);
} else {
holder = (MyViewHolder) vi.getTag();
}
JSONObject rowObject = this.jListData.getJSONObject(position);
Bitmap bmp = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(rowObject.optString("filename")), 100, 100);
holder.myImage.setImageBitmap(bmp);
//PicImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
holder.myImage.setPadding(8, 8, 8, 8);
//Set Title
holder.myName.setText(rowObject.optString("filename"));
ExifInterface intf = null;
try {
intf = new ExifInterface(rowObject.optString("filepath"));
} catch (IOException e) {
e.printStackTrace();
}
if (intf != null) {
String dateString = intf.getAttribute(ExifInterface.TAG_DATETIME);
holder.timestamp.setText("Date Taken: " + dateString.toString());
}
} catch (JSONException e) {
}
return vi;
}
}
ACTIVITY
private JSONArray jArrayFileData;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_yearbook);
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "/CapturyGallery");
// Check for SD Card
if (!Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
Toast.makeText(this, "Error! No SDCARD Found!", Toast.LENGTH_LONG)
.show();
} else {
// Locate the image folder in your SD Card
file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "/CapturyGallery");
// Create a new folder if no folder named CapturyGallery exist
file.mkdirs();
}
jArrayFileData = new JSONArray();
if (file.isDirectory()) {
listFile = file.listFiles();
// Create a String array for FilePathStrings
FilePathStrings = new String[listFile.length];
// Create a String array for FileNameStrings
FileNameStrings = new String[listFile.length];
for (int i = 0; i < listFile.length; i++) {
JSONObject jObject = new JSONObject();
//Get the path image file
// FilePathStrings[i] = listFile[i].getAbsolutePath();
// Get the name image file
// FileNameStrings[i] = listFile[i].getName();
jObject.put("filepath", listFile[i].getAbsolutePath());
jObject.put("filename", listFile[i].getName());
jArrayFileData.put(jObject);
}
}
// Arrays.sort(listFile);
final ListAdapter listAdapter = new CustomAdapter(Yearbook.this, jArrayFileData);
ListView lv = (ListView) findViewById(R.id.ListingView);
lv.setAdapter(listAdapter);
// final ArrayList<String> list = new ArrayList(Arrays.asList(FilePathStrings));
lv.setOnItemClickListener(this);
lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> parent, View view, final int position, long id) {
//Deletes item
AlertDialog.Builder adb = new AlertDialog.Builder(Yearbook.this);
adb.setTitle("Delete?");
adb.setMessage("Are you sure you want to delete " + FileNameStrings[position]);
final int positionToRemove = position;
adb.setNegativeButton("Cancel", null);
adb.setPositiveButton("Ok", new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
try {
File file = new File(list.get(positionToRemove));
if (file.delete()) {
Toast.makeText(getApplicationContext(), jArrayFileData.getJSONObject(position).optString("filename") + " deleted", Toast.LENGTH_LONG).show();
jArrayFileData.remove(position);
// list.remove(position);
((CustomAdapter) listAdapter).updateMyData(jArrayFileData);
}
} catch (JSONException e) {
}
}
});
adb.show();
return true;
}
});
}
Use Arraylist<String> for fpath and fname in your code: Then to delete data from your listview.
Use this:
fpath.remove(index_toDelete);
fpath.remove(index_toDelete);
customAdapter.notifyDataSetChanged();

Image in listview ordering is not correct and download again

Here is how I set up the list view and how I get the image by downloading it.
Some variable explanation :
The PostItem is the model object that contain the data for a listview item
The ImageLoader is the async task class to download the image by getting the image url from PostItem
The problem are , the ordering of the image in the listview is incorrect , for example, the image should appear in 1st is appear in both 1st , 4th, and if I scroll , the display pattern change as well.
Also, I find the image are download again if I scroll, even I have check the imageView whether has drawable
Thanks for helping.
====================================================
Here is how I generate the listview:
static class ViewHolderItem {
TextView name;
TextView date;
ImageView img;
TextView msg;
TextView count;
ImageView likeBtn;
ImageView commentBtn;
ImageView shareBtn;
}
private class MyPostAdapter extends ArrayAdapter<PostItem> {
#Override
public boolean isEnabled(int position) {
return false;
}
public MyPostAdapter(Context context, int resource, List<PostItem> items) {
super(context, resource, items);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
ViewHolderItem viewHolder;
if (v == null) {
LayoutInflater vi;
vi = LayoutInflater.from(getContext());
v = vi.inflate(R.layout.post_item, parent, false);
viewHolder = new ViewHolderItem();
viewHolder.name = (TextView) v.findViewById(R.id.postName);
viewHolder.date = (TextView) v.findViewById(R.id.postDate);
viewHolder.img = (ImageView) v.findViewById(R.id.postImg);
viewHolder.msg = (TextView) v.findViewById(R.id.postMsg);
viewHolder.count = (TextView) v.findViewById(R.id.count);
viewHolder.likeBtn = (ImageView) v.findViewById(R.id.likeBtn);
viewHolder.commentBtn = (ImageView) v.findViewById(R.id.commentBtn);
viewHolder.shareBtn = (ImageView) v.findViewById(R.id.shareBtn);
v.setTag(viewHolder);
} else {
viewHolder = (ViewHolderItem) convertView.getTag();
}
final PostItem post = getItem(position);
if (post != null) {
viewHolder.name.setText(post.name);
try {
c.setTime(sdf.parse(post.createDate));
} catch (ParseException e) {
e.printStackTrace();
}
relative_date = DateUtils.getRelativeDateTimeString (ctx, c.getTimeInMillis() , DateUtils.MINUTE_IN_MILLIS,DateUtils.WEEK_IN_MILLIS, 0).toString();
viewHolder.date.setText(relative_date);
viewHolder.msg.setText(post.txtMsg);
viewHolder.count.setText(post.likeCount + " " + getString(R.string.pro_like) + " " + post.commentCount + " " + getString(R.string.reply));
if (post.isLike) {
viewHolder.likeBtn.setImageResource(R.drawable.like);
} else {
viewHolder.likeBtn.setImageResource(R.drawable.before_like);
}
if (!post.imageURL.equals("null") && viewHolder.img.getDrawable() == null ) {
new ImageLoader(ctx).execute(viewHolder.img,Constant.comment_imageFolder + post.imageURL);
} else {
viewHolder.img.setImageDrawable(null);
}
viewHolder.likeBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
new APIManager("like", ctx, Constant.likeAPI + "/"
+ post.commentID + "/" + userID, jsonListener,
getResources().getString(R.string.update_data));
}
});
viewHolder.commentBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ArrayList<PostItem> filterReplyList = new ArrayList<PostItem>();
Intent i = new Intent(ctx, ReplyActivity.class);
i.putExtra("commentID", post.commentID);
// get reply list
for (PostItem reply : replyItemList) {
if (reply.postID.equals(post.commentID)
|| reply.commentID.equals(post.commentID)) {
filterReplyList.add(reply);
}
}
i.putExtra("replyItemList", filterReplyList);
startActivityForResult(i, 0);
}
});
viewHolder.shareBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
String data = "date: " + post.createDate + "\nmsg:" + post.txtMsg;
sendIntent.putExtra(Intent.EXTRA_TEXT, data);
sendIntent.setType("text/plain");
startActivity(sendIntent);
}
});
}
return v;
}
}
And Here is the imageloader, take the imageview, url as input and put the bitmap in the imageview
public class ImageLoader extends AsyncTask<Object, Void, Bitmap> {
private static String TAG = "ImageLoader";
private InputStream input;
private ImageView view;
private ProgressBar loadingIcon;
private ListView myListView;
private String imageURL;
private Context ctx;
public ImageLoader(Context _ctx) {
ctx = _ctx;
}
#Override
protected Bitmap doInBackground(Object... params) {
try {
view = (ImageView) params[0];
// handle Chinese characters in file name
// String[] imgUrlArray = ((String) params[1]).split("/");
// String fileName = imgUrlArray[imgUrlArray.length - 1];
// String newfileName = URLEncoder.encode(fileName, "utf-8");
// imageURL = ((String) params[1]).replace(fileName, newfileName);
imageURL = ((String) params[1]);
if (params.length > 2 && (ProgressBar) params[2] != null)
loadingIcon = (ProgressBar) params[2];
URL url = new URL(imageURL);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setDoInput(true);
connection.connect();
input = connection.getInputStream();
final BitmapFactory.Options options = new BitmapFactory.Options();
BufferedInputStream bis = new BufferedInputStream(input, 4*1024);
ByteArrayBuffer baf = new ByteArrayBuffer(50);
int current = 0;
while ((current = bis.read()) != -1) {
baf.append((byte)current);
}
byte[] imageData = baf.toByteArray();
BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
options.inJustDecodeBounds = true;
options.inSampleSize = 2;
options.inJustDecodeBounds = false;
return BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options);
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
try {
if (input != null)
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
protected void onPostExecute(Bitmap result) {
if (result != null && view != null) {
if (loadingIcon != null)
loadingIcon.setVisibility(View.GONE);
view.setVisibility(View.VISIBLE);
view.setImageBitmap(result);
}
}
Updated code (implement volley library):
static class ViewHolderItem {
TextView name;
TextView date;
NetworkImageView img;
TextView msg;
TextView count;
ImageView likeBtn;
ImageView commentBtn;
ImageView shareBtn;
}
private class MyPostAdapter extends ArrayAdapter<PostItem> {
#Override
public boolean isEnabled(int position) {
return false;
}
public MyPostAdapter(Context context, int resource, List<PostItem> items) {
super(context, resource, items);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
ViewHolderItem viewHolder;
if (v == null) {
LayoutInflater vi;
vi = LayoutInflater.from(getContext());
v = vi.inflate(R.layout.post_item, parent, false);
viewHolder = new ViewHolderItem();
viewHolder.name = (TextView) v.findViewById(R.id.postName);
viewHolder.date = (TextView) v.findViewById(R.id.postDate);
viewHolder.img = (NetworkImageView) v.findViewById(R.id.postImg);
viewHolder.msg = (TextView) v.findViewById(R.id.postMsg);
viewHolder.count = (TextView) v.findViewById(R.id.count);
viewHolder.likeBtn = (ImageView) v.findViewById(R.id.likeBtn);
viewHolder.commentBtn = (ImageView) v.findViewById(R.id.commentBtn);
viewHolder.shareBtn = (ImageView) v.findViewById(R.id.shareBtn);
v.setTag(viewHolder);
} else {
viewHolder = (ViewHolderItem) convertView.getTag();
}
final PostItem post = getItem(position);
if (post != null) {
viewHolder.name.setText(post.name);
try {
c.setTime(sdf.parse(post.createDate));
} catch (ParseException e) {
e.printStackTrace();
}
relative_date = DateUtils.getRelativeDateTimeString (ctx, c.getTimeInMillis() , DateUtils.MINUTE_IN_MILLIS,DateUtils.WEEK_IN_MILLIS, 0).toString();
viewHolder.date.setText(relative_date);
viewHolder.msg.setText(post.txtMsg);
viewHolder.count.setText(post.likeCount + " " + getString(R.string.pro_like) + " " + post.commentCount + " " + getString(R.string.reply));
if (post.isLike) {
viewHolder.likeBtn.setImageResource(R.drawable.like);
} else {
viewHolder.likeBtn.setImageResource(R.drawable.before_like);
}
if (!post.imageURL.equals("null")) {
viewHolder.img.setImageUrl(Constant.comment_imageFolder + post.imageURL, mImageLoader);
}
viewHolder.likeBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
new APIManager("like", ctx, Constant.likeAPI + "/"
+ post.commentID + "/" + userID, jsonListener,
getResources().getString(R.string.update_data));
}
});
viewHolder.commentBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ArrayList<PostItem> filterReplyList = new ArrayList<PostItem>();
Intent i = new Intent(ctx, ReplyActivity.class);
i.putExtra("commentID", post.commentID);
// get reply list
for (PostItem reply : replyItemList) {
if (reply.postID.equals(post.commentID)
|| reply.commentID.equals(post.commentID)) {
filterReplyList.add(reply);
}
}
i.putExtra("replyItemList", filterReplyList);
startActivityForResult(i, 0);
}
});
viewHolder.shareBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
String data = "date: " + post.createDate + "\nmsg:" + post.txtMsg;
sendIntent.putExtra(Intent.EXTRA_TEXT, data);
sendIntent.setType("text/plain");
startActivity(sendIntent);
}
});
}
return v;
}
For the task you are trying to do I would strongly recommend you to use Volley library.
Read from here
All you need to do is as below
mRequestQueue = Volley.newRequestQueue(context);
mImageLoader = new ImageLoader(mRequestQueue, new BitmapLruCache());
mImageView.setImageUrl(BASE_URL + item.image_url, mImageLoader);
Where mImageView is com.android.volley.NetworkImageView instead of a regular ImageView.
Volley takes care of maintaining the cache and the ordering of the images.
if you scroll the listview you will get back recycled convertview, it is not null but it has incorrect imageview. convertView is a view thats created and recycled through scrolling the list. this view makes GC be called less and also save memory for you. it first assigned by your earliest items of list. after you scroll the list, for example item one of list disappears and you see item 15 the convertView of item one is passed again to you. in this time it is not null and it holdes the reference of last imageview, the imageview of item 1.
so this is your problem, you skipped assigning correct imageview to your viewHolder.img.
Ok, what should you do?
the best thing you can do is create in memory cache that holds your downloaded imageview by their URLs as keys of the cache. in getview you check the cache, if it has your URL of current imageview position read from it and set it to viewHolder.img else download the image from internet.
Golden rule is:
ALWAYS OVERWRITE VIEWHOLDER VALUES WITH VALUES OF YOUR ITEM AT INDEX POSITON THAT
GETVIEW PASSES TO YOU
how to create cache? look at Example LRU cache at
http://developer.android.com/training/volley/request.html
and if you want you can also use volley library instead.
if (!post.imageURL.equals("null") && viewHolder.img.getDrawable() == null ) {
new ImageLoader(ctx).execute(viewHolder.img,Constant.comment_imageFolder + post.imageURL);
}
I am guessing that the problem lies here. What happens when you get a recycled view which already has an image from the previous view it was used for? That explains why the image appears in both 1st and 4th position and the change in the display pattern when you scroll.
Get the point? Remove the viewHolder.img.getDrawable() == null and try. See if that helps.

i have one error passing of constructor as this in listfragments

I am newer to the fragments. In oncreate method i pass this value to Appetizerlist. but it shows an error. How to clear the error? Please help me.
public class MyListFragment1 extends ListFragment {
ImageView back;
String url = Main.url;
String Qrimage;
Bitmap bmp;
ListView list;
AppetiserFragment adapter;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.applistviewfragment, null);
list = (ListView) view.findViewById(R.id.list);
return view;
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
InputStream is = null;
String result = "";
JSONObject jArray = null;
try {
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url + "test.php3");
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
} catch (Exception e) {
// TODO: handle exception
Log.e("Log", "Error in Connection" + e.toString());
// Intent intent = new Intent(ViewQRCode.this, PimCarder.class);
// startActivity(intent);
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
result = sb.toString();
jArray = new JSONObject(result);
JSONArray json = jArray.getJSONArray("appetiser");
adapter = new AppetiserFragment(this, json);
list.setAdapter(adapter);
} catch (Exception e) {
// TODO: handle exception
Log.e("log", "Error in Passing data" + e.toString());
}
}
}
AppetiserFragment.java
public class AppetiserFragment extends BaseAdapter {
String url = Main.url;
public Context Context;
String qrimage;
Bitmap bmp, resizedbitmap;
Bitmap[] bmps;
Activity activity = null;
private LayoutInflater inflater;
private ImageView[] mImages;
String[] itemimage;
TextView[] tv;
String itemname, price, desc, itemno;
String[] itemnames, checkeditems, itemnos;
String[] prices;
String[] descs;
HashMap<String, String> map = new HashMap<String, String>();
public AppetiserFragment(Context context, JSONArray imageArrayJson) {
Context = context;
// inflater =
System.out.println(imageArrayJson);
// (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// imageLoader=new ImageLoader(activity);
inflater = LayoutInflater.from(context);
this.mImages = new ImageView[imageArrayJson.length()];
this.bmps = new Bitmap[imageArrayJson.length()];
this.itemnames = new String[imageArrayJson.length()];
this.prices = new String[imageArrayJson.length()];
this.descs = new String[imageArrayJson.length()];
this.itemnos = new String[imageArrayJson.length()];
try {
for (int i = 0; i < imageArrayJson.length(); i++) {
JSONObject image = imageArrayJson.getJSONObject(i);
qrimage = image.getString("itemimage");
itemname = image.getString("itemname");
itemno = new Integer(i + 1).toString();
price = image.getString("price");
desc = image.getString("itemdesc");
System.out.println(price);
itemnames[i] = itemname;
prices[i] = price;
descs[i] = desc;
itemnos[i] = itemno;
byte[] qrimageBytes = Base64.decode(qrimage.getBytes());
bmp = BitmapFactory.decodeByteArray(qrimageBytes, 0,
qrimageBytes.length);
int width = 100;
int height = 100;
resizedbitmap = Bitmap.createScaledBitmap(bmp, width, height,
true);
bmps[i] = bmp;
mImages[i] = new ImageView(context);
mImages[i].setImageBitmap(resizedbitmap);
mImages[i].setScaleType(ImageView.ScaleType.FIT_START);
// tv[i].setText(itemname);
}
System.out.println(map);
} catch (Exception e) {
// TODO: handle exception
}
}
public AppetiserFragment() {
// TODO Auto-generated constructor stub
}
public int getCount() {
return mImages.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
final ViewHolder viewHolder;
if (view == null) {
view = inflater.inflate(R.layout.appetiserlistview, null);
System.out.println("prakash");
viewHolder = new ViewHolder();
viewHolder.image = (ImageView) view
.findViewById(R.id.appetiserimage);
viewHolder.text = (TextView) view.findViewById(R.id.appetisertext);
viewHolder.desc = (TextView) view.findViewById(R.id.appetiserdesc);
viewHolder.price = (TextView) view
.findViewById(R.id.appetiserprice);
viewHolder.appitemnum = (TextView) view
.findViewById(R.id.appitemno);
// viewHolder.checkbox = (CheckBox) view.findViewById(R.id.bcheck);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.image.setImageBitmap(bmps[position]);
viewHolder.appitemnum.setText(itemnos[position]);
viewHolder.price.setText(prices[position]);
viewHolder.desc.setText(descs[position]);
// viewHolder.checkbox.setTag(itemnames[position]);
ViewHolder holder = (ViewHolder) view.getTag();
holder.text.setText(itemnames[position]);
return view;
}
static class ViewHolder {
protected TextView text, price, desc, appitemnum;
protected ImageView image;
public static CheckBox checkbox = null;
}
}
i Given whole code i want custom listview using listfragments
In the above code in this line, I'm getting an error at adapter = new Appetizerlist(this, json); Please tell me how to solve the problem. Help me.
as onCreate called before onCreateView so list will null there in onCreate ...........
http://developer.android.com/guide/topics/fundamentals/fragments.html
in oncreate
list.setAdapter(adapter);
in onCreateView you initlized that
list = (ListView) view.findViewById(R.id.list);
......
so move this line list.setAdapter(adapter); in onCreateView
You have error in following line.
adapter = new Appetizerlist(this, json);
Change it to
adapter = new Appetizerlist(getActivity().getApplicationContext(), json);

How to display the custom listview using base adapter in listfragments?

I want do custom listview using base adapter in listfragment
I try this code:
public class MyListFragment1 extends ListFragment {
ImageView back;
String url = Main.url;
String Qrimage;
Bitmap bmp;
ListView list;
AppetiserFragment adapter;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View tmp_view = inflater.inflate(R.layout.applistviewfragment, container, false);
ListView list = (ListView) tmp_view.findViewById(R.id.list);
InputStream is = null;
String result = "";
JSONObject jArray = null;
try {
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url + "test.php3");
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
is = entity.getContent();
} catch (Exception e) {
// TODO: handle exception
Log.e("Log", "Error in Connection" + e.toString());
// Intent intent = new Intent(ViewQRCode.this, PimCarder.class);
// startActivity(intent);
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
result = sb.toString();
jArray = new JSONObject(result);
JSONArray json = jArray.getJSONArray("appetiser");
adapter = new AppetiserFragment(getActivity(), json);
list.setAdapter(adapter);
} catch (Exception e) {
// TODO: handle exception
Log.e("log", "Error in Passing data" + e.toString());
}
return tmp_view;
}
}
AppetiserFragment.java
public class AppetiserFragment extends BaseAdapter {
public static ArrayList<String> arr = new ArrayList<String>();
public static ArrayList<String> itemprice = new ArrayList<String>();
public static ArrayList<Bitmap> image = new ArrayList<Bitmap>();
String url = Main.url;
public Context Context;
String qrimage;
Bitmap bmp, resizedbitmap;
Bitmap[] bmps;
Activity activity = null;
private LayoutInflater inflater;
private ImageView[] mImages;
String[] itemimage;
TextView[] tv;
String itemname, price, desc, itemno;
String[] itemnames, checkeditems, itemnos;
String[] prices;
String[] descs;
HashMap<String, String> map = new HashMap<String, String>();
public AppetiserFragment(Context context, JSONArray imageArrayJson) {
Context = context;
// inflater =
System.out.println(imageArrayJson);
// (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// imageLoader=new ImageLoader(activity);
inflater = LayoutInflater.from(context);
this.mImages = new ImageView[imageArrayJson.length()];
this.bmps = new Bitmap[imageArrayJson.length()];
this.itemnames = new String[imageArrayJson.length()];
this.prices = new String[imageArrayJson.length()];
this.descs = new String[imageArrayJson.length()];
this.itemnos = new String[imageArrayJson.length()];
try {
for (int i = 0; i < imageArrayJson.length(); i++) {
JSONObject image = imageArrayJson.getJSONObject(i);
qrimage = image.getString("itemimage");
itemname = image.getString("itemname");
itemno = new Integer(i + 1).toString();
price = image.getString("price");
desc = image.getString("itemdesc");
**System.out.println(price);**
itemnames[i] = itemname;
prices[i] = price;
descs[i] = desc;
itemnos[i] = itemno;
byte[] qrimageBytes = Base64.decode(qrimage.getBytes());
bmp = BitmapFactory.decodeByteArray(qrimageBytes, 0,
qrimageBytes.length);
int width = 100;
int height = 100;
resizedbitmap = Bitmap.createScaledBitmap(bmp, width, height,
true);
bmps[i] = bmp;
mImages[i] = new ImageView(context);
mImages[i].setImageBitmap(resizedbitmap);
mImages[i].setScaleType(ImageView.ScaleType.FIT_START);
// tv[i].setText(itemname);
}
System.out.println(map);
} catch (Exception e) {
// TODO: handle exception
}
}
public AppetiserFragment() {
// TODO Auto-generated constructor stub
}
public int getCount() {
return mImages.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
final ViewHolder viewHolder;
if (view == null) {
view = inflater.inflate(R.layout.appetiserlistview, null);
viewHolder = new ViewHolder();
viewHolder.image = (ImageView) view
.findViewById(R.id.appetiserimage);
viewHolder.text = (TextView) view.findViewById(R.id.appetisertext);
viewHolder.desc = (TextView) view.findViewById(R.id.appetiserdesc);
viewHolder.price = (TextView) view
.findViewById(R.id.appetiserprice);
viewHolder.appitemnum = (TextView) view
.findViewById(R.id.appitemno);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.image.setImageBitmap(bmps[position]);
viewHolder.appitemnum.setText(itemnos[position]);
viewHolder.price.setText(prices[position]);
viewHolder.desc.setText(descs[position]);
ViewHolder holder = (ViewHolder) view.getTag();
holder.text.setText(itemnames[position]);
return view;
}
static class ViewHolder {
protected TextView text, price, desc, appitemnum;
protected ImageView image;
public static CheckBox checkbox = null;
}
}
I can able to print price value. If I do separately as custom listview I can able to image, text, desc, price. But in MyFragmentlist1 extends with listfragment means I cannot able to view in custom listview. I thought MyListFragment1 in this class only I have problem.
First Create a separate layout layout_txtview. I am just using a textview. You can create layout according to items you want to show in a single row.
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/textView1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:textColor="#000000"
android:textAppearance="?android:attr/textAppearanceSmall" />
Now Use this layout to inflate in getView() method of your custom adapter.
Now in onCreate() method of MyListFragment1 class just set the adapter to your custom adapter
setAdapter(new MyListFragment1 (<apss your constructor argument>));
and its done.
Try moving the setAdapter in the onActivityCreated callback, in this way
#Override
public void onActivityCreated(Bundle savedInstanceState) {
ListView list = getListView();
list.setAdapter(adapter);
adapter.notifyDataSetChanged();
}

Categories

Resources