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);
}
}
}
ViewHolder
is created,attached,referenced to ingetView(..)
method, and nowhere else. Your problems are caused by illegal usage of theViewHolder
and one of the most terrific Thread/Runnable usage I've ever seen. Rework your code, I'm pretty sure you have no need for those "matrioshka" threads at all. – Exceed