tamtoum1987 tamtoum1987 - 27 days ago 6
Android Question

adapter holder on listener cannot be final

I need to add a progress listener to each element of the horizontal list view, how can I do that?

For each item I upload a file.

I wanna to do something like that but holder is not final, so I have an error.

public class UploadsViewAdapter extends BaseAdapter {
private Context mContext;
private int mLayoutResourceId;
List<Upload> listFileToUpload;

public UploadsViewAdapter(Context context, int layoutResourceId, List<Upload> data) {
this.mLayoutResourceId = layoutResourceId;
this.mContext = context;
this.listFileToUpload = data;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
ViewHolder holder = null;

if (row == null) {
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
row = inflater.inflate(mLayoutResourceId, parent, false);
holder = new ViewHolder();
holder.image = (ImageView) row.findViewById(R.id.upload_item_image);
holder.progressUpdate = (ProgressBar) row.findViewById(R.id.progressUpdate);
row.setTag(holder);
} else {
holder = (ViewHolder) row.getTag();
}

final Upload item = getItem(position);
holder.image.setImageBitmap(item.getThumbnail(160, 160));
item.setProgressListener(new ProgressListener() {
@Override
public void onProgress(int progress) {
holder.progressUpdate.setProgress(item.getProgress());
}
});
holder.progressUpdate.setProgress(item.getProgress());
return row;
}

static class ViewHolder {
ImageView image;
ProgressBar progressUpdate;
}

public void updateListFileToUpdate(List<Upload> listFileToUpload) {
this.listFileToUpload = listFileToUpload;
}

@Override
public int getCount() {
return listFileToUpload.size();
}

@Override
public Upload getItem(int location) {
return listFileToUpload.get(location);
}

@Override
public long getItemId(int position) {
return 0;
}
}


Class Update.java

public class Upload {
public String path;
public String type;
private int mProgress = 0;
private ProgressListener mListener;

public Upload(String path, String type) {
this.path = path;
this.type = type;
}

public void setProgressListener(ProgressListener listener) {
mListener = listener;
}

public void setProgress(int progress) {
mProgress = progress;
if (mListener != null) {
mListener.onProgress(progress);
}
}

public int getProgress() {
return mProgress;
}

public Bitmap getThumbnail(int reqWidth, int reqHeight) {

// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);

// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(path, options);
}

private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;

if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;

// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while (
(halfHeight / inSampleSize) > reqHeight &&
(halfWidth / inSampleSize) > reqWidth
) {
inSampleSize *= 2;
}
}

return inSampleSize;
}

public interface ProgressListener {
public void onProgress(int progress);
}

}


Class which updates the file:

public class TheFormFragment extends Fragment {

private AmazonS3Client mS3Client = new AmazonS3Client(
new BasicAWSCredentials(Config.AWS_ACCESS_KEY, Config.AWS_SECRET_KEY));

public static final int RESULT_PHOTO_DISK = 10;
public static final int RESULT_PHOTO_APN = 100;
public static final int RESULT_VIDEO_APN = 1000;

public static final String INTENT_PHOTO_APN_PATH = "INTENT_PHOTO_APN_PATH";
public static final String INTENT_VIDEO_APN_PATH = "INTENT_VIDEO_APN_PATH";

private List<Medias> mTheFormPictures;

private static Activity mActivity;
private static ArrayList<Upload> mQueue;

private KeyboardEventLinearLayout mLinearLayoutBackground;
private LinearLayout mLinearLayoutPublish;
private TextView mTextViewPublish;
private ImageView mImageViewPublish; // todo image du bouton
private EditText mEditTextText;
private TextView mTextViewTitle;
private CircularImageView mCircularImageViewAvatar;
private ImageButton mImageButtonClose;
private ImageButton mImageButtonCamera;
private ImageButton mImageButtonLibrary;

private Tag[] mTags = null;
private Range mAutocompleting;
private LinearLayout mAutocompleteContainer;

private HorizontalListView mUploadsList;
private UploadsViewAdapter mUploading;
/**Contains list of images, vidoe to update*/
private List<Upload> listFileToUpload;

private KeyboardEventLinearLayout.KeyboardListener mKeyboardListener = new KeyboardEventLinearLayout.KeyboardListener() {
@Override
public void onShow() {
if (mUploadsList != null) {
mUploadsList.setVisibility(View.GONE);
}
}
@Override
public void onHide() {
if (mUploadsList != null) {
mUploadsList.setVisibility(View.VISIBLE);
}
}
};

private class Range {
public int start;
public int end;
public String value;

public Range(int start, int end, String value) {
this.start = start;
this.end = end;
this.value = value;
}
}

private TextWatcher textWatcher = new TextWatcher() {
@Override
public void onTextChanged(CharSequence text, int start, int oldCount, int newCount) {
String before = text.subSequence(0, start + newCount).toString();
Range range = findEditingTag(before);
autocompete(range);
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

@Override
public void afterTextChanged(Editable s) {}
};

private OnClickListener mAutocompleteItemClickListener = new OnClickListener() {
@Override
public void onClick(View view) {
Editable text = mEditTextText.getText();
CharSequence tag = ((TextView) view).getText();
text.replace(mAutocompleting.start, mAutocompleting.end, tag);
}
};

@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mActivity = activity;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_the_form, container, false);
return rootView;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {

mTheFormPictures = new ArrayList<Medias>();
mQueue = new ArrayList<Upload>();

mS3Client.setRegion(Region.getRegion(Config.AWS_REGION));

mLinearLayoutBackground = (KeyboardEventLinearLayout) mActivity.findViewById(R.id.linearLayoutBackground);
mLinearLayoutPublish = (LinearLayout) mActivity.findViewById(R.id.linearLayoutPublish);

mTextViewPublish = (TextView) mActivity.findViewById(R.id.textViewPublish);
mTextViewTitle = (TextView) mActivity.findViewById(R.id.textViewTitle);

mImageViewPublish = (ImageView) mActivity.findViewById(R.id.imageViewPublish);

mCircularImageViewAvatar = (CircularImageView) mActivity.findViewById(R.id.circularImageViewAvatar);

mEditTextText = (EditText) mActivity.findViewById(R.id.editTextText);

mImageButtonClose = (ImageButton) mActivity.findViewById(R.id.imageButtonClose);
mImageButtonCamera = (ImageButton) mActivity.findViewById(R.id.imageButtonCamera);
mImageButtonLibrary = (ImageButton) mActivity.findViewById(R.id.imageButtonLibrary);

mAutocompleteContainer = (LinearLayout) mActivity.findViewById(R.id.autocompleteLayout);

mUploadsList = (HorizontalListView) mActivity.findViewById(R.id.uploadsList);
listFileToUpload =new ArrayList<Upload>();
mUploading = new UploadsViewAdapter(mActivity, R.layout.upload_item, listFileToUpload);
mUploadsList.setAdapter(mUploading);

mLinearLayoutBackground.setKeyboardListener(mKeyboardListener);

configure();

super.onActivityCreated(savedInstanceState);
}

@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
private void configure() {
AQuery aq = new AQuery(mActivity);

ImageOptions options = new ImageOptions();
//options.round = 180;
options.fileCache = false;
options.memCache = true;
//options.animation = AQuery.FADE_IN;

User user = Preferences.getUser(mActivity);

if (user != null) {
mTextViewTitle.setText(user.getFirst_name() + " " + user.getLast_name());

if (user.getAvatar() != null && user.getAvatar().length() > 0) {
aq.id(mCircularImageViewAvatar).image(user.getAvatar(), options);
}
}

StatusConfigTheForm configTheForm = Preferences.getConfigTheForm(mActivity);

if (configTheForm != null) {
Log.i("theform config success");

Log.d("avatar: " + user.getAvatar() + " " + configTheForm.getBorderWidth());

if (configTheForm.getColors().getBackground().length == 3) {
mLinearLayoutBackground.setBackgroundColor(Color.parseColor(Utils.getHexaColor(configTheForm.getColors().getBackground())));
}

if (configTheForm.getColors().getBackgrounPublishButton().length == 3) {
// mButtonPublish.setBackgroundColor(Color.parseColor(Utils.getHexaColor(configTheForm.getColors().getBackgrounPublishButton())));

// prepare
int roundRadius = 6;

// normal state
GradientDrawable background_normal = new GradientDrawable();
background_normal.setColor(Color.parseColor(Utils.getHexaColor(configTheForm.getColors().getBackgrounPublishButton())));
background_normal.setCornerRadius(roundRadius);

// pressed state
GradientDrawable bacground_pressed = new GradientDrawable();
bacground_pressed.setColor(Color.parseColor(Utils.getHexaColor(configTheForm.getColors().getBackgrounPublishButton()).replace("#", "#CC"))); // opacity
bacground_pressed.setCornerRadius(roundRadius);

// states (normal and pressed)
StateListDrawable states = new StateListDrawable();
states.addState(new int[] {android.R.attr.state_pressed}, bacground_pressed);
states.addState(new int[] {-android.R.attr.state_pressed}, background_normal);

if (Build.VERSION.SDK_INT >= 16) {
mLinearLayoutPublish.setBackground(states);
} else {
mLinearLayoutPublish.setBackgroundDrawable(states);
}
}

if (configTheForm.getColors().getBackgroundTextView().length == 3) {
mEditTextText.setBackgroundColor(Color.parseColor(Utils.getHexaColor(configTheForm.getColors().getBackgroundTextView())));
}

if (configTheForm.getColors().getBorderColorPicture().length == 3) {
mCircularImageViewAvatar.setBorderColor(Utils.getHexaColor(configTheForm.getColors().getBorderColorPicture()));
}

// add color tag here

if (configTheForm.getColors().getColorTextPublish().length == 3) {
mTextViewPublish.setTextColor(Color.parseColor(Utils.getHexaColor(configTheForm.getColors().getColorTextPublish())));
}

if (configTheForm.getColors().getColorTextAttachment().length == 3) {
mCircularImageViewAvatar.setBorderColor(Utils.getHexaColor(configTheForm.getColors().getColorTextAttachment()));
}

if (configTheForm.getColors().getColorTextUser().length == 3) {
mTextViewTitle.setTextColor(Color.parseColor(Utils.getHexaColor(configTheForm.getColors().getColorTextUser())));
}

if (configTheForm.getBorderWidth() > 0) {
mCircularImageViewAvatar.setBorderWidth(configTheForm.getBorderWidth() * Integer.valueOf(Float.valueOf(getResources().getDisplayMetrics().density).intValue()));
}

// pictures
if (configTheForm.getPictures() != null) {
String baseUrl = configTheForm.getUrlPicto() + configTheForm.getFolder() + File.separator;
String ext = Utils.setExtension(mActivity, Config.PICTURE_EXTENSION);
Pictures pics = configTheForm.getPictures();

if (configTheForm.getPictures().getPictureBack() != null) {
aq.id(mImageButtonClose).image(baseUrl + pics.getPictureBack() + ext, options);
}

if (configTheForm.getPictures().getPictureCamera() != null) {
aq.id(mImageButtonCamera).image(baseUrl + pics.getPictureCamera() + ext, options);
}

if (configTheForm.getPictures().getPictureLibrary() != null) {
aq.id(mImageButtonLibrary).image(baseUrl + pics.getPictureLibrary() + ext, options);
}

if (configTheForm.getPictures().getPicturePublish() != null) {
mImageViewPublish.setVisibility(View.VISIBLE);
aq.id(mImageViewPublish).image(baseUrl + pics.getPicturePublish() + ext, options);
} else {
mImageViewPublish.setVisibility(View.GONE);
}
}
}

mEditTextText.addTextChangedListener(textWatcher);
}

private Range findEditingTag(String text) {
Pattern pattern = Pattern.compile("#[A-z0-9_]+$");
Matcher match = pattern.matcher(text);
if (match.find()) {
String value = text.substring(match.start());
return new Range(match.start(), match.end(), value);
}

return null;
}

private void autocompete(Range range) {
mAutocompleting = range;
mAutocompleteContainer.removeAllViews();

if (range != null && mTags != null) {
String tag;
for (int i = 0; i < mTags.length; i++) {
tag = "#" + mTags[i].getName();
if (tag.startsWith(range.value) && tag.equals(range.value) == false) {
addAutocompleteItem(tag);
}
}
}
}

@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
private void addAutocompleteItem(String text) {
Drawable background = mActivity.getResources().getDrawable(R.drawable.autocomplete_item);
int textColor = mActivity.getResources().getColor(R.color.autocomplete_item_text);

TextView view = new TextView(mActivity);
view.setText(text);
view.setTextColor(textColor);

view.setPadding(20, 10, 20, 10);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
params.setMargins(10, 0, 10, 0);
view.setLayoutParams(params);

if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
view.setBackgroundDrawable(background);
} else {
view.setBackground(background);
}

view.setClickable(true);
view.setOnClickListener(mAutocompleteItemClickListener);

mAutocompleteContainer.addView(view);
}

private void updateProgress() {
//int progress = 0;
//for (Upload file: mUploading) {
// progress += file.getProgress();
//}
//progress /= mUploading.size();

//mProgressBarFile.setProgress(progress);
//mTextViewFileProgress.setText(String.format(getString(R.string.theform_text_file_progress), Integer.valueOf(progress).toString()));
}

private class S3PutObjectTask extends AsyncTask<Upload, Integer, S3TaskResult> {
//private Dialog progressDialog;
ObjectMetadata mMetadata = new ObjectMetadata();

private String mS3Filename;
private Upload mFile;

@Override
protected void onPreExecute() {
updateProgress();
}

@Override
protected void onProgressUpdate(Integer... values) {
int progress = Integer.valueOf( (int) ((values[0] * 100) / mMetadata.getContentLength()) );

mFile.setProgress(progress);
updateProgress();

super.onProgressUpdate(values);
}

protected S3TaskResult doInBackground(Upload... files) {
if (files == null || files.length != 1 || files[0] == null) {
return null;
} else {
mFile = files[0];
}

ContentResolver resolver = mActivity.getContentResolver();

// The file location of the image selected.
Uri selectedSource = Uri.parse(mFile.path);

if (mFile.type.equals("image")) {
String size = null;
String fileSizeColumn[] = { OpenableColumns.SIZE };

Cursor cursor = resolver.query(selectedSource, fileSizeColumn, null, null, null);

if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
// If the size is unknown, the value stored is null. But since an int can't be
// null in java, the behavior is implementation-specific, which is just a fancy
// term for "unpredictable". So as a rule, check if it's null before assigning
// to an int. This will happen often: The storage API allows for remote
// files, whose size might not be locally known.

if (!cursor.isNull(sizeIndex)) {
// Technically the column stores an int, but cursor.getString will do the
// conversion automatically.
size = cursor.getString(sizeIndex);
}

cursor.close();
}

mMetadata.setContentType(resolver.getType(selectedSource));

if (size != null) {
mMetadata.setContentLength(Long.parseLong(size));
}
}

if (mMetadata.getContentType() == null) {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inJustDecodeBounds = true;
BitmapFactory.decodeFile(selectedSource.toString(), opt);

mMetadata.setContentType(opt.outMimeType);
}

if (mMetadata.getContentLength() <= 0) {
mMetadata.setContentLength(new File(selectedSource.toString()).length());
}

selectedSource = Uri.parse("file://" + selectedSource.toString().replace("content://", ""));

S3TaskResult result = new S3TaskResult();

// Put the image data into S3.
try {
Calendar cal = Calendar.getInstance();

if (mFile.type.equals("image")) {
mS3Filename = Long.valueOf(cal.getTime().getTime()).toString() + ".jpg";
} else {
mS3Filename = Long.valueOf(cal.getTime().getTime()).toString() + ".mp4";
}

PutObjectRequest por = new PutObjectRequest(
Config.getPictureBucket(cal.getTime().getTime()), mS3Filename,
resolver.openInputStream(selectedSource), mMetadata
).withGeneralProgressListener(new ProgressListener() {
int total = 0;

@Override
public void progressChanged(ProgressEvent pv) {
total += (int) pv.getBytesTransferred();
publishProgress(total);
}
});

mS3Client.putObject(por);

result.setName(mS3Filename);

} catch (Exception exception) {
exception.printStackTrace();
result.setName(null);
result.setErrorMessage(exception.getMessage());
}

return result;
}

protected void onPostExecute(S3TaskResult result) {
//mProgressBarFile.setProgress(0);
//mTextViewFileProgress.setText("");

// AWS Error
if (result != null && result.getErrorMessage() != null && result.getName() == null) {
FastDialog.showDialog(mActivity, FastDialog.SIMPLE_DIALOG, result.getErrorMessage());
} else {
// add picture name
mTheFormPictures.add(new Medias(result.getName()));
}
}
}

public static String getRealPathFromUri(Context context, Uri contentUri) {
Cursor cursor = null;

try {
String[] proj = { MediaStore.Images.Media.DATA };
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} finally {
if (cursor != null) {
cursor.close();
}
}
}

/** close activity **/
public void close(View v) {
mActivity.finish();
}

/** select picture **/
public void selectPicture(View v) {
//Intent intent;
Intent intent = new Intent(
Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
/*if (Build.VERSION.SDK_INT < 19) {
intent = new Intent();
intent.setAction(Intent.ACTION_GET_CONTENT);
} else {
intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
}
if (Build.VERSION.SDK_INT >= 18) {
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
}*/

intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.setType("image/* video/*");
startActivityForResult(intent, RESULT_PHOTO_DISK);
}

/** take picture **/
public void tackePicture(View v) {
ApnActivity.show(mActivity, RESULT_PHOTO_APN);
}

/** record video **/
public void recordVideo(View v) {
RecordVideoActivity.show(mActivity, RESULT_VIDEO_APN);
}

/** publish button **/
public void publish(View v) {
// object
WebViewTheFormResult theFormResult = new WebViewTheFormResult(mEditTextText.getText().toString(), mTheFormPictures);

if (theFormResult.isEmpty()) {
FastDialog.showDialog(mActivity, FastDialog.SIMPLE_DIALOG, getString(R.string.theform_publish_error));
} else {
// intent
Intent dataIntent = new Intent();

Bundle bundle = new Bundle();
bundle.putSerializable(WebViewActivity.INTENT_OBJECT, (Serializable) theFormResult);

dataIntent.putExtras(bundle);

mActivity.setResult(Activity.RESULT_OK, dataIntent);
mActivity.finish();
}
}

@SuppressLint("NewApi")
public static void actionOnActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_CANCELED) {
return;
}
if (requestCode != RESULT_PHOTO_APN && requestCode != RESULT_VIDEO_APN) {
requestCode = RESULT_PHOTO_DISK;
}

switch (requestCode) {
case RESULT_PHOTO_DISK:
if (Build.VERSION.SDK_INT >= 18 && data.getData() == null) {
ClipData clipdata = data.getClipData();
for (int i = 0, l = clipdata.getItemCount(); i < l; i++) {
onDiskResult(clipdata.getItemAt(i).getUri());
}
} else {
onDiskResult(data.getData());
}
break;
case RESULT_PHOTO_APN:
onApnPhotoResult(data);
break;
case RESULT_VIDEO_APN:
onApnVideoResult(data);
break;
}
}

private static void onDiskResult(Uri selectedImage) {
InputStream imageStream;
try {
File file = new File(
Environment.getExternalStorageDirectory() + File.separator +
"Android" + File.separator +
"data" + File.separator +
mActivity.getPackageName()
);

if (new File(file.getAbsolutePath()).exists() == false) {
file.mkdirs();
}

imageStream = mActivity.getContentResolver().openInputStream(selectedImage);
Bitmap goodPicture = BitmapFactory.decodeStream(imageStream);
String filePath = file.getAbsoluteFile().toString() + "/" + String.valueOf(Utils.uid()) + Config.PHOTO_TMP_NAME;

try {
//goodPicture = ThumbnailUtils.createVideoThumbnail(filePath, MediaStore.Images.Thumbnails.MINI_KIND);

FileOutputStream out = new FileOutputStream(filePath);
goodPicture = Bitmap.createScaledBitmap(goodPicture, 800, 600, false);
goodPicture.compress(Bitmap.CompressFormat.JPEG, 80, out);
} catch (FileNotFoundException e) {
e.printStackTrace();
return;
}

queueFile(filePath, "image");
} catch (FileNotFoundException e1) {
e1.printStackTrace();
return;
}
}

private static void onApnPhotoResult(Intent data) {
String filePath = data.getExtras().getString(TheFormFragment.INTENT_PHOTO_APN_PATH);

if (filePath.equals(Integer.valueOf(RESULT_VIDEO_APN).toString())) {
RecordVideoActivity.show(mActivity, RESULT_VIDEO_APN);
} else {
queueFile(filePath, "image");
}
}

private static void onApnVideoResult(Intent data) {
String filePath = data.getExtras().getString(TheFormFragment.INTENT_VIDEO_APN_PATH);

if (filePath.equals(Integer.valueOf(RESULT_PHOTO_APN).toString())) {
ApnActivity.show(mActivity, RESULT_PHOTO_APN);
} else {
queueFile(filePath, "video");
}
}

private static void queueFile(String filePath, String fileType) {
mQueue.add(new Upload(filePath, fileType));
}

@Override
public void onResume() {
fetchTags();

while (mQueue.size() > 0) {
uploadFile(mQueue.remove(mQueue.size() - 1));
}

super.onResume();
}

private void uploadFile(Upload file) {
new S3PutObjectTask().execute(file);
listFileToUpload.add(file);
mUploading.updateListFileToUpdate(listFileToUpload);
mUploading.notifyDataSetChanged();
}

private void fetchTags() {
Api.getTags(mActivity, new Api.Callback() {
@Override
public void onSuccess(String json) {
Gson gson = new Gson();
mTags = gson.fromJson(json, Tag[].class);
}
});
}
}


How can I resolve the problem?

Answer

Something like this should be enough:

...
holder.image.setImageBitmap(item.getThumbnail(160, 160));
final ViewHolder finalHolder = holder;
item.setProgressListener(new ProgressListener() {

    @Override
    public void onProgress(int progress) {
        finalHolder.progressUpdate.setProgress(item.getProgress());
    }
});
finalHolder.progressUpdate.setProgress(item.getProgress());