Load multiple bitmaps in Android Studio one at time with threads - java

I'm currently working on a project which takes pictures from camera and saves the photoPath in a Database, this is working fine and actually I'm handling the memory correctly generating thumbnails when I load all images.
The thing I want is that I'm trying to dedicate threads to go loading images one per one in the layout, because for example, if I have 50, with normal load it shows the layout until all 50 are loaded, meanwhile it doesn't show anything.
I've already tried to implement this threads to load one, and then another one, but it's the same, until it loads all, it shows all, here my code:
String query = "Select id_reg_mem, information from Memory_REG where type = 'PHOTO' and id_memory =" + id_memory;
final Cursor resultado = memoryDB.rawQuery(query, null);
if(resultado.moveToFirst())
noPhotos = resultado.getCount();
for(int i=0; i<noPhotos; i++)
{
new Thread()
{
public void run()
{
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
updateNewPhoto(resultado.getString(1)); // I send the path from the DB to a method I made to add a tablerow with the image (inside an imageview)
}
});
}
}.start();
if(i + 1 == noPhotos)
break;
resultado.moveToNext();
}
Here this method, where I'm loading a single image to an ImageView inside a TableRow. This method is actually working to load all images from DB.
protected void updateNewPhoto(String path)
{
ImageView iv;
if(rows == null) {
rows = new ArrayList<TableRow>();
rows.add(new TableRow(TL.getContext()));
iv = new ImageView(TL.getContext());
iv.setLayoutParams(new TableRow.LayoutParams(250,250));
iv.setTag(DB_Utils.maxIDRegMem(memoryDB) - 1);
iv.setImageBitmap(getBitmapThumbnail(path));
rows.get(0).addView(iv);
TL.addView(rows.get(0));
count = 2;
}
else
{
iv = new ImageView(TL.getContext());
iv.setLayoutParams(new TableRow.LayoutParams(250,250));
iv.setTag(DB_Utils.maxIDRegMem(memoryDB) - 1);
iv.setImageBitmap(getBitmapThumbnail(path));
if(count == 2)
{
rows.get(rows.size() - 1).addView(iv);
count = 1;
}
else
{
rows.add(new TableRow(TL.getContext()));
rows.get(rows.size() - 1).addView(iv);
TL.addView(rows.get(rows.size() - 1));
count = 2;
}
}
Unfortunately for me, all images aren't shown until all of them are loaded (kind of 3 seconds it takes). I'm thinking in no limit of images, that's why I want a way where images be loaded one per one, not all together.
Any ideas you have? I appreciate your help.
Thanks.

Related

How to retrieve multiple images from Firebase Firestorage and maintaining their order in Android Studio (Java)?

I am trying to retrieve multiple images from Firestorage, each image is associated with a document in Firebase Firestore database (the document ID is equivalent to the image name).
After retrieving all the documents IDs I inserted it into ArrayList<String> POSTS_IDs and I want to fill the ArrayList<File> IMAGE_FILE with the images but the problem is that the images always take a random order and do not maintain the order of the POSTS_IDs.
I mean if the index 3 of POSTS_IDs is equal to "image3", the index 3 of IMAGE_FILE will be image 5 or 6 (it is random some times it comes with the right order).
I want to know if my way is wrong or what is the problem.
Thank you
try {
for (int i = 0; i < POSTS_IDs.size(); i++) {
final File file = File.createTempFile(POSTS_IDs.get(i), ".jpg");
StorageReference reference1 = storageReference.child("images/posts/" + POSTS_IDs.get(i) + ".jpg");
reference1.getFile(file).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
#Override
public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
Toast.makeText(getContext(), ""+taskSnapshot.toString(), Toast.LENGTH_SHORT).show();
IMAGE_FILE.add(file); // adding the images to the IMAGE_FILE ArrayList<File>
}
});
}
}catch(Exception e){
Toast.makeText(getContext(), "Error" + e, Toast.LENGTH_SHORT).show();
}
Just Remove the onSuccessListener. here you have IMAGE_FILE.add(file); for the array list so no need of onSuccessListener

Cached elements do not exist in DOM anymore

Like in similar issue, I use appium + java. Trying to select elements
In mobile application I am go to page, and after that, have many elements android.widget.ImageView(0), I need to select 6 (for example) such elements and go with other steps. Byt can select only one element and then get such exception:
org.openqa.selenium.StaleElementReferenceException: Cached elements 'By.id: com.company:id/selector_view' do not exist in DOM anymore
public GalleryPage choosePhotosFromAlbum(int count) {
List<MobileElement> photos = driver.findElementsById(elements.get("photo from gallery album selector"));
for (int i = 0; i < count; i++) {
photos.get(i).click();
}
return new GalleryPage(device);
}
I had the same issue. I think this happens because every time you click on a photo, the DOM changes. So, when you try to click on the second photo, the cached elements are not on the DOM anymore.
Try putting the photos inside the for cycle, like this:
public GalleryPage choosePhotosFromAlbum(int count) {
for (int i = 0; i < count; i++) {
List<MobileElement> photos = driver.findElementsById(elements.get("photo from gallery album selector"));
photos.get(i).click();
}
return new GalleryPage(device);
}
This way the list of photos is retrieved from the refreshed DOM on every cycle.
And by the way, you're not checking if the count is bigger than the photos list size, which can result in an OutOfBounds exception or similar.
You can use explicit wait to solve this problem.
public GalleryPage choosePhotosFromAlbum(int count)
{
List<MobileElement> photos = driver.findElementsById(elements.get("photo from gallery album selector"));
for (int i = 0; i < count; i++)
{
new WebDriverWait(driver,10).until(ExpectedConditions.presenceOfAllElementsLocatedBy("Your object property"));
photos.get(i).click();
}
return new GalleryPage(device);
}
Try enableMultiWindows appium capability set to true https://github.com/appium/appium/blob/master/docs/en/advanced-concepts/settings.md
Or you can try finding elements via WebDriverWait. In Appium (C#), when the driver tries to find native elements, it can sometimes throw a StaleElementReferenceException. Thus you can ignore this exception and wait until elements exist in DOM:
public ReadOnlyCollection<IWebElement> WaitElements(By selector)
{
var wait = new WebDriverWait(this.Driver, new TimeSpan(0, 0, 10));
ReadOnlyCollection<IWebElement> results = null;
try
{
wait.Until(driver =>
{
try
{
var elements = driver.FindElements(selector);
if (elements.Any())
{
results = elements;
return true;
}
}
catch (StaleElementReferenceException)
{
// ignore
}
return false;
});
}
catch (WebDriverTimeoutException)
{
throw new NoSuchElementException("Elements not found");
}
return results;
}

iTextSharp Footer Gets Progressively Bolder with Each Page

Using OnEndPage, I add a footer to my PDF created with iTextSharp. The footer font gets progressively bolder with each page.
How can I create consistent NORMAL fonts in my footer?
Here is my code:
public override void OnEndPage(PdfWriter writer, Document doc)
{
iTextSharp.text.Image gif = null;
if (FooterImage)
{
if (File.Exists(PathImages))
{
gif = iTextSharp.text.Image.GetInstance(PathImages);
gif.ScaleToFit(75f, 75f);
gif.SetAbsolutePosition(0, 0);
}
}
string sFooter = string.Empty;
if (FooterURL != null && FooterURL.Length > 0)
{
sFooter = FooterURL + " ";
}
if (FooterDate != null && FooterDate.Length > 0)
{
sFooter += FooterDate + " ";
}
if (FooterPage)
{
sFooter += "Page " + doc.PageNumber.ToString();
}
PdfPTable footerTbl = new PdfPTable(1);
footerTbl.TotalWidth = 900;
footerTbl.HorizontalAlignment = Element.ALIGN_CENTER;
Phrase ph = new Phrase(sFooter, FontFactory.GetFont(FontFactory.TIMES, 10, iTextSharp.text.Font.NORMAL));
PdfPCell cell = new PdfPCell(ph);
cell.Border = 0;
cell.PaddingLeft = 10;
footerTbl.AddCell(cell);
if (FooterImage)
{
PdfContentByte cbfoot = writer.DirectContent;
PdfTemplate tpl = cbfoot.CreateTemplate(gif.Width / 5, gif.Height / 5);
tpl.AddImage(gif);
cbfoot.AddTemplate(tpl, doc.PageSize.Width - 100, 10);
}
footerTbl.WriteSelectedRows(0, -1, 10, 30, writer.DirectContent);
}
In the old days, when there wasn't as much choice as today regarding fonts, people used workarounds to create bold fonts. One way to make a font bold, was by adding the same text over and over again at the same position. I think that this is happening to you.
When you use page events correctly, the onEndPage() method is triggered automatically each time a page ends. My guess is that you're doing something very wrong that triggers the onEndPage() many times. Maybe you are called the onEndPage() from your code, maybe you're adding the page event to the writer more than once (and page events are cumulative).
If I have to guess, I would guess that you are doing the latter. My guess is based on the fact that you are using variables such as FooterImage in your onEndPage() method. How are you setting that variable. If you are setting it in the constructor of the page event and you're adding the new page event over and over again to the writer, then you're doing it wrong.

Inflater and loop not working as it should

I am having a problem with a custom view I am currently doing for an app on android, I know there are many questions related with inflaters, but I cannot get around this problem.
the inflater i working just fine, but it should be doing the loop 3 times and is only doing it 1 so I only get one view on my final layout.
the relevant part of the code is this one
void populate(String strcline, String url){
lLfD = (LinearLayout)findViewById(R.id.lLfD);
try{
JSONArray a1 = new JSONArray(strcline);
for(int i = 0; i < a1.length(); i++){
JSONArray a2 = a1.getJSONArray(i);
final String fUserId = a2.getString(0);
String userName = a2.getString(1);
String userPicture = url + a2.getString(2);
View child = getLayoutInflater().inflate(R.layout.cellevery, lLfD);
ImageView avatar = (ImageView)findViewById(R.id.cellAvatar);
downloadFile(userPicture, avatar);
TextView cellName = (TextView)findViewById(R.id.cellName);
cellName.setText(userName);
lLfD.addView(child);
}
}catch(Exception e){
}
pDialog.dismiss();
}
You look like you need to run findViewById only on the inflated view, otherwise it will just find the first one which is only the first one in your loop:
View child = getLayoutInflater().inflate(R.layout.cellevery, lLfD);
ImageView avatar = (ImageView)child.findViewById(R.id.cellAvatar);
downloadFile(userPicture, avatar);
TextView cellName = (TextView)child.findViewById(R.id.cellName);
cellName.setText(userName);
Here's an explanation of findViewById in your loop:
Loop 1:
1LfD->child1->R.id.cellAvatar (findViewById(R.id.cellAvatar) finds this one)
Loop 2:
1Lfd->
child1->R.id.cellAvatar
child2->R.id.cellAvatar (findViewById(R.id.cellAvatar) finds the child1.cellAvatar again)
Loop 3:
1LfD->
child1->R.id.cellAvatar
child2->R.id.cellAvatar
child3->R.id.cellAvatar (findViewById(R.id.cellAvatar) finds the child1.cellAvatar again)
by using child.findViewById(R.id.cellAvatar), it ensures that you find the correct R.id.cellAvatar for each run of the loop.
Does that make sense?
Update 2:
When you call:
getLayoutInflater().inflate(R.layout.cellevery, lLfD);
You are already setting the parent view as the second argument so you don't need to call:
lLfD.addView(child);

Xcode image link ImageView into next View Controller

I have made a Xcode project for a tabbed application that displays images of color swatches in a Scrollview. How do I link One of the images in my scrollview to go to the next View Controller? Below is my code and pictures. So when you click on one of the images or swatch color in the scrollview it links to the New Controller.
I have multiple images that scroll down the page of the iPhone, Do I have to loop the images cause there are 24 images. I was able to make one button and link it to the next scene with the interface builder, But I can fit 5 images on the screen..
DecorsViewController_iPhone.h
#import <UIKit/UIKit.h>
#interface DecorsViewController_iPhone : UIViewController
{
IBOutlet UIScrollView *scrollViewDecors;
}
#property (nonatomic, retain) UIView *scrollViewDecors;
#end
DecorsViewController_iPhone.m
#import "DecorsViewController_iPhone.h"
#interface DecorsViewController_iPhone ()
#end
#implementation DecorsViewController_iPhone
#synthesize scrollViewDecors;
const CGFloat kScrollObjHeight = 81.5;
const CGFloat kScrollObjWidth = 320.0;
const NSUInteger kNumImages = 24;
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollViewDecors subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
CGFloat curYLoc = 0;
CGFloat curYSpace = 1;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, curYLoc);
view.frame = frame;
curYLoc += (curYSpace + kScrollObjHeight);
}
}
// set the content size so it can be scrollable
[scrollViewDecors setContentSize:CGSizeMake(([scrollViewDecors bounds].size.width), (kNumImages * kScrollObjHeight))]; // Vertical Option
}
- (void)viewDidLoad
{
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];
// 1. setup the scrollview for multiple images and add it to the view controller
//
// note: the following can be done in Interface Builder, but we show this in code for clarity
[scrollViewDecors setBackgroundColor:[UIColor blackColor]];
[scrollViewDecors setCanCancelContentTouches:NO];
scrollViewDecors.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollViewDecors.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollViewDecors.scrollEnabled = YES;
// pagingEnabled property default is NO, if set the scroller will stop or snap at each photo
// if you want free-flowing scroll, don't set this property.
// scrollView1.pagingEnabled = YES;
// load all the images from our bundle and add them to the scroll view
NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"Artwork_iPhone_Decors_Scrollview_%d.png", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i; // tag our images for later use when we place them in serial fashion
[scrollViewDecors addSubview:imageView];
//[imageView release];
}
[self layoutScrollImages]; // now place the photos in serial layout within the scrollview
}
//- (void)dealloc
//{
// [scrollViewDecors release];
//
// [super dealloc];
//}
//- (void)viewDidLoad
//{
// [super viewDidLoad];
// // Do any additional setup after loading the view, typically from a nib.
//}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
#end
Firstly, you need to add a gesture recogniser to your view with something like:
UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(flipView:)];
[singleTapGestureRecognizer setNumberOfTapsRequired:1];
[self.view addGestureRecognizer:singleTapGestureRecognizer];
You then need to implement the 'flipView' method:
- (void)flipView:(UIPanGestureRecognizer *)recognizer {
[self performSegueWithIdentifier:#"textView" sender:self];
}
As you can see in my case, when the method is triggered I perform a segue (see below):
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"textView"])
{
//---Pass text to view
CGRect visibleRect;
visibleRect.origin = scrollView.contentOffset;
visibleRect.size = scrollView.bounds.size;
int number;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
number = visibleRect.origin.x / 768;
}
else {
number = visibleRect.origin.x / 320;
}
TextViewController *textViewController = segue.destinationViewController;
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
textViewController.text = [appDelegate.textArray objectAtIndex:number];
}
}
The 'number' variable is used to decide which image has been clicked, I divide the visible rects origin by the width of the screen in pixels to calculate which image has been pressed and therefore what data to send to my new view.
In your case, you would use the Y coordinate to perform a calculation to decide which colour has been pressed, possibly something like:
int number;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
number = visibleRect.origin.y / <height of each image on iPad in pixels>;
}
else {
number = visibleRect.origin.y / <height of each image on iPhone in pixels>;
}
Alternatively, you could use a UITableView and just populate the cells with the appropriate colour and then display the new view based on which cell was pressed.
EDIT
Use a UITableView, and populate each cell with your image using custom tableview cells. This is a much easier approach than what you are suggesting.
See these links:
adding images to UItableView
If using iOS 5 -
http://kurrytran.blogspot.co.uk/2011/10/ios-5-storyboard-uitableview-tutorial.html
if not -
http://www.iosdevnotes.com/2011/10/uitableview-tutorial/
You are overcomplicating this task massively, follow the above tutorials and you'll be done in no time. If this answer helped you, please mark it as correct.
You can customize your UIImageView. For example, MyImageView. Set its delegate to your main ScrollView and add UITapGestureRecognizer and TapDetecting Delegate methods.
You can implement in the MyImageView:
- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer {
// single tap
if ([_delegate respondsToSelector:#selector(myImageViewWasSingleTapped:)])
[_delegate myImageViewWasSingleTapped:self];
}
then in your main ScrollView(delegate of MyImageView):
- (void)myImageViewWasSingleTapped:(MyImageView *)miv {
AnotherViewController *asv = [[AnotherViewController alloc] initWithImage: miv];
[self.navigationController pushViewController: asv animated:YES];
[asv release];
}
You can use a button instead of a UIImageView, and set the button's image to your image. Your loop in viewDidLoad would be like this:
// load all the images from our bundle and add them to the scroll view
NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"Artwork_iPhone_Decors_Scrollview_%d.png", i];
UIImage *image = [UIImage imageNamed:imageName];
UIButton *imageButton = [[UIButton alloc] init];
[imageButton setImage:image forState:UIControlStateNormal];
[imageButton addTarget:self action:#selector(pushNextViewController:) forControlEvents:UIControlEventTouchUpInside];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = CGRectMake(0, 0, kScrollObjWidth, kScrollObjHeight);
imageButton.frame = rect;
imageButton.tag = i; // tag our images for later use when we place them in serial fashion
[scrollViewDecors addSubview:imageButton];
// Release imageButton unless you're using ARC
}
And then you'd need to define an action for imageButton, in this case I called it pushNextViewController:
- (void)pushNextViewController:(id)sender
{
UIViewController *yourNextViewController = // initialise your next view controller here
[self.navigationController pushViewController:yourNextViewController animated:YES];
}

Categories