I have a custom Listview, where each item contains a progressbar. But when the list contains many items, and I use the scrollbar to navigate through listview, some ProgressBars disappear and facing same issue with imageview using to show status of uploaded image(s), what could be the reason and how can i resolve this ? see my code below
static class ViewHolder {
public ViewHolder(View convertView) {
// TODO Auto-generated constructor stub
}
TextView imageNameTextView;
ImageView sdCardImageView, statusImageView;
ProgressBar uploadProgressBar;
ImageButton uploadImageButton, dataImageButton, printImageButton, viewImageButton, deleteImageButton ;
}
public class ImageAdapter extends BaseAdapter
{
public ImageAdapter(Context c)
{
}
public int getCount() {
// TODO Auto-generated method stub
return ImageList.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(final int position, View convertView, ViewGroup parent) {
// Avoid unneccessary calls to findViewById() on each row, which is expensive!
holder = null;
// If this item is to be synced
if(flags.get(position)) {
startUpload(position);
// Mark as synced
flags.put(position, false);
}
/*
* If convertView is not null, we can reuse it directly, no inflation required!
* We only inflate a new View when the convertView is null.
*/
if (convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.list_upload, null);
holder = new ViewHolder(convertView);
// Create a ViewHolder and store references to the children views
holder.imageNameTextView = (TextView) convertView.findViewById(R.id.ColImgName);
holder.sdCardImageView = (ImageView) convertView.findViewById(R.id.ColImgPath);
holder.statusImageView = (ImageView) convertView.findViewById(R.id.ColStatus);
holder.uploadProgressBar = (ProgressBar) convertView.findViewById(R.id.progressBar);
holder.uploadImageButton = (ImageButton) convertView.findViewById(R.id.btnUpload);
holder.dataImageButton = (ImageButton) convertView.findViewById(R.id.btnData);
holder.printImageButton = (ImageButton) convertView.findViewById(R.id.btnPrint);
holder.viewImageButton = (ImageButton) convertView.findViewById(R.id.btnView);
holder.deleteImageButton = (ImageButton) convertView.findViewById(R.id.btnDelete);
// The tag can be any Object, this just happens to be the ViewHolder
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
strPath = ImageList.get(position).toString();
// Get File Name
fileName = strPath.substring( strPath.lastIndexOf('_')+1, strPath.length() );
file = new File(strPath);
@SuppressWarnings("unused")
long length = file.length();
holder.imageNameTextView.setText(fileName);
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap bm = BitmapFactory.decodeFile(strPath,options);
holder.sdCardImageView.setImageBitmap(bm);
holder.statusImageView.setImageResource(R.drawable.bullet_button);
holder.uploadProgressBar.setVisibility(View.GONE);
//btnUpload
holder.uploadImageButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Upload
cd = new ConnectionDetector(getApplicationContext());
// Check for internet connection
if (!cd.isConnectingToInternet()) {
// Internet Connection is not present
alert.showAlertDialog(UploadActivity.this, "Internet not available",
"Please connect to working Internet connection", false);
// stop executing code by return
return;
}
startUpload(position);
}
});
//Upload
public void startUpload(final int position) {
Runnable runnable = new Runnable() {
public void run() {
handler.post(new Runnable() {
public void run() {
v = lstView.getChildAt(position - lstView.getFirstVisiblePosition());
holder.uploadProgressBar.setVisibility(View.VISIBLE);
holder.statusImageView.setImageResource(R.drawable.bullet_button);
new UploadFileAsync().execute(String.valueOf(position));
}
});
}
};
new Thread(runnable).start();
}
// Async Upload
public class UploadFileAsync extends AsyncTask<String, Void, Void> {
String resServer;
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Void doInBackground(String... params) {
// TODO Auto-generated method stub
position = Integer.parseInt(params[0]);
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 1 * 1024 * 1024;
int resCode = 0;
String resMessage = "";
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
// File Path
String strSDPath = ImageList.get(position).toString();
// Upload to PHP Script
String strUrlServer = "http://domein/fiile.php";
try {
/** Check file on SD Card ***/
File file = new File(strSDPath);
if(!file.exists())
{
resServer = "{\"StatusID\":\"0\",\"Error\":\"Please check path on SD Card\"}";
return null;
}
FileInputStream fileInputStream = new FileInputStream(new File(strSDPath));
URL url = new URL(strUrlServer);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + boundary);
DataOutputStream outputStream = new DataOutputStream(conn
.getOutputStream());
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream
.writeBytes("Content-Disposition: form-data; name=\"filUpload\";filename=\""
+ strSDPath + "\"" + lineEnd);
outputStream.writeBytes(lineEnd);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
// Read file
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
outputStream.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0, bufferSize);
}
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// Response Code and Message
resCode = conn.getResponseCode();
if(resCode == HttpURLConnection.HTTP_OK)
{
InputStream is = conn.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int read = 0;
while ((read = is.read()) != -1) {
bos.write(read);
}
byte[] result = bos.toByteArray();
bos.close();
resMessage = new String(result);
}
Log.d("resCode=",Integer.toString(resCode));
Log.d("resMessage=",resMessage.toString());
fileInputStream.close();
outputStream.flush();
outputStream.close();
resServer = resMessage.toString();
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
protected void onPostExecute(Void unused) {
statusWhenFinish(position,resServer);
}
}
// When UPload Finish
@SuppressWarnings("unused")
protected void statusWhenFinish(int position, String resServer) {
View v = lstView.getChildAt(position - lstView.getFirstVisiblePosition());
// hide ProgressBar
holder.uploadProgressBar.setVisibility(View.GONE);
/*** Default Value ***/
String strStatusID = "0" ;
String strError = "" ;
try {
JSONObject c = new JSONObject(resServer);
strStatusID = c.getString("StatusID");
strError = c.getString("Message");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// using if - else if
if(strStatusID.equals("0"))
{
// already exist
holder.statusImageView.setImageResource(R.drawable.already_exist);
}
else if(strStatusID.equals("1")) {
// upload done
holder.statusImageView.setImageResource(R.drawable.upload_done);
}
else // if upload failed
{
// upload failed
holder.statusImageView.setImageResource(R.drawable.upload_failed);
}
}
}
In your ViewHolder
class :
static class ViewHolder {
//...
boolean isUploading = false;
//...
}
In your getView()
:
public View getView(final int position, View convertView, ViewGroup parent) {
//...
if(holder.isUploading) {
holder.uploadProgressBar.setVisibility(View.VISIBLE);
} else {
holder.uploadProgressBar.setVisibility(View.GONE);
}
//...
}
In your startUpload()
:
public void startUpload(final int position) {
//...
holder.uploadProgressBar.setVisibility(View.VISIBLE);
holder.isUploading = true;
//...
}
Hope it will work.
So for your ProgressBar.
Whenever getView() is called, you set its visibility to GONE.
holder.uploadProgressBar.setVisibility(View.GONE);
So when starts to upload something (and sets uploadProgressBar to VISIBLE), and you scroll down (makes the list item invisible), then scroll up, getView() will be called again, and it will make your ProgressBar invisible.
So you need wrap the state in an object, or use a list to record each item state. For example, in your ImageAdapter
boolean[] uploadings = new boolean[getCount()];
Arrays.fill(uploadings, false);
in your getView()
if (uploadings[position]) {
// You need this, since you are not sure whether you are
// using newly inflated view or ConvertView
holder.uploadProgressBar.setVisibility(View.VISIBLE);
} else {
holder.uploadProgressBar.setVisibility(View.GONE);
}
And in your startUpload()
method, whenever you set your prograss bar to GONE or VISIBILE, set uploadings[position]
to false
or true
correspondingly.
And I think your ImageView probably has the same problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With