How to save unique picture per ListItem Android - java

My issue is this (Don't let the paragraph intimidate you, my question is quite simple I believe) :
In the MainActivity(A), I have a listView. When I click on an item in the listView, I go to a second activity(B). In activity B, I have a button that allows the user to take a picture. Now I save this picture under a filename. Since I want each listItem's picture to be unique, I make the filename of the picture that item's position. For example, if I click item#1 in the list, the corresponding picture's name is "1". This all works very well except when I delete an item. Then, when I add another item at the same position, my code loads the existing picture for that item. e.g.- If I have a picture called '2' saved for an item2, it's fine. when I delete this entry and add another item, which is the new item2, my code checks, "does the picture name '2' exist?". If yes, then set this entry's picture to that. Obviously this is a different entry and I don't want this to happen. Possibly, I could delete the picture along with the item, but I have no clue how to do this.
I hope I explained my logic well. The only reason I am using the position is because that is the only unique thing about the item that I can find. By the way(not sure if this is relevant), I am passing the item position as an extra in the intent between Activity A and Activity B.
How can I solve this issue or use a workaround? Thanks!
EDIT 1:
Facepalm. By looking at comments, I realize that deleting it(as I stated earlier)^^, is the way to do this. Could someone tell me how to do this then?
This the code I am using to save the Image:
private void setImage() {
if (loadPicture(getIntent().getStringExtra("position"), bitmap) != null) {
// Toast.makeText(this, "not null", Toast.LENGTH_SHORT).show();
imageView.setImageBitmap(loadPicture(
getIntent().getStringExtra("position"), bitmap));
}
}
private void savePicture(String filename, Bitmap b, Context ctx) {
try {
// ObjectOutputStream bos;
FileOutputStream out;// = new FileOutputStream(filename);
out = ctx.openFileOutput(filename, Context.MODE_WORLD_READABLE);
// bos = new ObjectOutputStream(out);
b.compress(Bitmap.CompressFormat.JPEG, 40, out);
if (b.compress(Bitmap.CompressFormat.JPEG, 40, out) == true)
// Toast.makeText(this, "returned true",
// Toast.LENGTH_LONG).show();
// bos.flush();
// bos.close();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Cheers.

The answer is in the question : delete the file when you delete the item. File.delete() is the method you're probably searching for. You'll also have to rename the other files if the item is not the last one in the list, though.
Another, easier way would be to use a simple counter to name your files, and associate each item in the list with the file name with the help of a Map.

I don't want to step on JB Nizet's answer but I will give another suggestion. Using SimpleCursorAdapter and a SqliteDatabase you could avoid having to manage any kind of numeric key. Just hold the path to the file in the database along with any other related information for the user, setup your ViewBinder and you're off to the races. A binder is a very flexible way to render data and even conditionally render View objects.

The way I solved this issue is by incrementing a counter every time I added the item, then saving this counter in the internal memory. This way, it was not based upon the position and would not get messed up when I deleted an item. I hope this continues to work as I make modifications to my application. Thanks to all for help.

Related

Updating a document in firebase with an auto generated ID

I've learned how to add and delete from Firebase. It's quite straightforward.
My delete code which is activated when clicking the delete button, it's found in my adapter class (it's the only way I could get the delete button click registered correctly)
public void deleteJournal(int position) {
getSnapshots().getSnapshot(position).getReference().delete();
}
And to add (which is in another class)
CollectionReference diaryRef = FirebaseFirestore.getInstance()
.collection("Diary");
diaryRef.add(new Diary(growName, description, priority));
But I don't even know where to begin to update. I will be putting the edit code in the adapter class which will open a dialog window to edit values.
I know how to create the window and edit the values and set new variables for this data. But how do I make sure I'm applying this updated data to the document with the corresponding edit button that clicked? Then update Firebase correctly.
diaryRef.add(new Diary(growName, description, priority)).addOnSuccessListener(documentReference -> {
String id = documentReference.getId();
db.collection("Diary").document(id).update("entryId", id);
});
now you will have a unique id to delete or update the entry
But how do I make sure I'm applying this updated data to the document
In the same way, you are deleting the document. Please see the method below:
public void updateJournal(int position) {
Diary diary = getSnapshots().getSnapshot(position).toObject(Diary.class);
//Make the changes
}
Once you have the Diary object, you can make the desired updates and then write the document back to the database, as shown in your question.

JavaFX ListView adding item into observable list doesn't reflect change and it's not selectable

I have run into pretty messed up behaviour with my ListView, I have listview created in controller with data attached to it.
#FXML
private ListView<Weapon> listViewWeapons;
...
private final ObservableList<Loadout> loadoutList;
public LoadoutViewController() {
...
loadoutList =FXCollections.observableList(CsgoRr.getModel().getLoadoutCache());
...
}
#Override
public void initialize(URL location, ResourceBundle resources) {
...
listViewLoadouts.setItems(loadoutList);
...
}
I call method attached to button, which has function of adding new loadout into list
#FXML
private void newLoadoutOnAction() {
try {
Loadout loadoutToBeStored = new Loadout(new Long[10], "Loadout" + newDuplicateNameLoadoutIncrement);
loadoutToBeStored.setId(DbUtil.storeLoadout(loadoutToBeStored));//store and set id.
CsgoRr.getModel().getLoadoutCache().add(loadoutToBeStored);
System.out.println("Stored new loadout ");
listViewLoadouts.getSelectionModel().select(loadoutToBeStored);
for (Loadout loadout : loadoutList) {
System.out.println("DEBUG LOADOUT CONTAINER OBSERVABLE:" + loadout);
}
} catch (SQLException ex) {//duplicate name
if (ex.getErrorCode() == 23505) {
newDuplicateNameLoadoutIncrement++;
newLoadoutOnAction();
}
Logger.getLogger(LoadoutViewController.class.getName()).log(Level.SEVERE, null, ex);
}
}
All the data is correctly loaded and stored, I have debugged that part of course. But even though I call method newLoadoutOnAction and I put data into list which observable list has reference to, change is not seen up until I resize that listView. That's not the only problem, even after I resize listView and I'm able to see item in a list I can't select it I have to call construstor and initializer again to be able to select this item. I have never encountered this behaviour, how do I fix these problems?
Problem with refreshing item in the list: I have tried to remove items and set them again, and some other solutions common to this problem bud nothing worked even if I put setItems(null) I can't get it to work, items are still there.
Latest item inserted is not selectable (through UI) until I call my controller again and recreate everything. I have this item selected with code.
listViewLoadouts.getSelectionModel().select(loadoutToBeStored);
This actually selected needed item bud I don't see any feedback in the UI and I can't select it with my mouse. Even if I remove this line I still can't select it with a mouse till I call my view again (constructor and initializer).
I know this is a bit more complex problem so I decided to show you what's happening with a gif.
Hope it's clear.
The Javadoc for FXCollections.observableList states:
Note that mutation operations made directly to the underlying list are not reported to observers of any ObservableList that wraps it.
For this reason loadoutList is not connected to the list in CsgoRr.getModel().getLoadoutCache() after creation. This means that when newLoadoutOnAction() calls:
CsgoRr.getModel().getLoadoutCache().add(loadoutToBeStored);
it is not picked up by loadoutList, or the ListView watching it. If you change CsgoRr.getModel().getLoadoutCache() to use an ObservableList, and assign that directly to loadoutList your function should work as desired.
The other option would be to add your loadoutToBeStored to loadoutList instead, but then you would need to also synchronise with the List in CsgoRr.getModel()

Combobox doesn't react to ".setValue()" nor ".select()"

This is my code:
comboBoxInstance.setInputPrompt("Something...");
comboBoxInstance.setNullSelectionAllowed(false);
Cookie comboCookie = getCookieByName("combo");
comboBoxInstance.select((comboCookie != null) ? comboCookie.getValue() : null);
final TextField textFieldInstance = new TextField("Textfield");
textFieldInstance.setInputPrompt("Something...");
Cookie tfCookie = getCookieByName("tf");
textFieldInstance.setValue((tfCookie != null) ? tfCookie.getValue() : null);
The problem is that the textfield works pretty well with the "Cookie setup". Only the combobox is refusing to work like it should.
The output is like this:
I've tried to use .setValue() instead of .select() but this has pretty much the same effect. I've also made sure that both the Cookie itself and the correct value are provided.
It may help to have a look at the part where the cookie is generated:
Cookie comboCookie = new Cookie("combo", comboBoxInstance.getValue().toString());
cookieProcessing(costcentreCookie); //<- sets maxage and vaadin related stuff (like adding the cookie)
Edit:
A few points to the data flow.
I'm generating a ComboBox with a SimpleJDBCConnectionPool's SQLContainer as the data container (coming from a TableQuery). Here's the initialization (executed in the constructor) in the combobox class:
private void init() throws SQLException {
this.setContainerDataSource(generateContainer());
this.setItemCaptionPropertyId("something");
}
The private method generateContainer() returns the SQLContainer of course.
This happens if I click on a particular button which opens up a dialog. This dialog is the fragment shown in the picture above. The combobox - of course - is part of it.
What one is supposed to do now is setting his data (get an item of the ComboBox) and hit save. The save button executes the routine to store the cookies. It's the code already mentioned above (Cookie comboCookie = new Cookie(...).
Okay, now the user is going to open up the dialog again. It's not important whether he reloads the application or just reopens the dialog (or does something else). It's basically the same in the app.
The dialog opens up and initializes the combobox (and the textfield) once again. However, this time it's supposed to gather the data out of the stored cookies. This is were the issue happens. This works well for the textfields (there are two but I've omitted one for shortening reasons) but not for the combobox, even tough it should've the exact same data as before. Hold in mind that it's the exact same class with the exact same initialization as when we stored the cookies in the first place.
I've the vague presumption, that it has to do something how the code is stacked. Maybe it hasn't finished loading the datacontainer while trying to set the appropriated value which then can't be found.
Edit2:
I've finally managed to reveal something. The ComboBox is indeed empty when the ".select()" is executed. However, this means, that the ComboBox is left untouched (it's only kind of "linked" to the datacontainer) until someone drops down the items. As soon as this happens, the items are there and I can possibly select them.
Is it supposed to work like this? O.o Am I able to fully initialize the combobox before I do something else? Something like:
private void init() throws SQLException {
this.setContainerDataSource(generateContainer());
this.setItemCaptionPropertyId("something");
this.gatherTheItems();
}
Edit3 - Test with ".setImmediate(true)"
I've changed the init to:
private void init() throws SQLException {
this.setContainerDataSource(generateContainer());
this.setItemCaptionPropertyId("SOMETHING");
this.setImmediate(true);
}
This didn't change anything. The combobox is still empty:
Finally! At first I've found a workaround which was like this:
for (Iterator it_IDS = combobox.getItemIds().iterator(); it_IDS.hasNext();) {
Object id = (Object) it_IDS.next();
if(id.toString().equals(cookie.getValue().toString())){
combo2.select(id);
break;
}
}
However, I couldn't believe that this was working since it doesn't change anything at the core problem. So I've investigated, that the RowID is built via a BigDecimal and voilĂ :
if(cookie != null) {
combobox.select(new RowId(new BigDecimal(cookie.getValue())));
}
I'm so happy right now :) Thanks for your patience kukis.
In case you came here because you're experiencing the same issue using a BeanItemContainer as datasource, bear in mind that you must implement both equals()and hashCode() methods on the underlying class for ComboBox's select() or setValue() methods to work.
You have plenty examples on Vaadin Forum on how to implement these methods:
ComboBox select value problem
Select or ComboBox does not Show Selected Property
Combobox select/setValue

I don't understand what happens on file.exists() for android on eclipse

i am creating an application for android in eclipse.
i have a chat application in which user's contact's images are downloaded in sdcard and are put in a HashMap (url, localAddress), when i want to load contact list, for any contacts I use a function to find address of contacts' pictures on sdcard, three different state may occur
1- image found on sdcard then return path.
2- image don't download before and HashMap return null, then download it.
3- HashMap return a path but user deleted image from sdcard then remove key from Hashmap and download again.
my code:
public static String findFile(Context ctx, String url, String type)
{
try
{
String value = globalVars.addresses.get(url);
if(value != null)
{
File ff = new File(value);
if(ff.exists())
return value;
globalVars.addresses.remove(url);
}
globalVars.enqueueJob(ctx, new globalVars.downloadJob(url, url, type));
return null;
}
catch(Exception ex)
{
Log.e("Find File", "Start");
Log.e("Find File", ex.toString());
ex.printStackTrace();
return null;
}
}
but when i delete an image it download more and more .
function enqueueJob :
public static void enqueueJob(Context context, downloadJob dj)
{
if(inQueue.get(dj.getAddress())!= null && inQueue.get(dj.getAddress())== true)
return;
downloads.add(dj);
inQueue.put(dj.address, true);
FileUtils.doDownload(context);
}
It work's fine for pictures don't download yet and pictures that download and don't delete yet.
Your title is confusing as it indicates you suspect the File.exists as the problem. Looking at your code, the fact that deleted images are added to download queue means File.exists works fine at least the first time. Otherwise, you would not even add it to the queue. Now the question is what happens when it is added to queue and downloaded. Check your code to make sure that it added back to the map properly. In your code, something should be added to the download queue only under two conditions: one if nothing in the map and the other is whatever in the map is deleted. So either it is not added back properly or may be a race condition where your File.exists is happening before the download is completed fully and you are adding it back to the queue again.
Good luck.

List View - setting View.GONE upon menu selection doesn't hide immediately

TLDR:
I'm setting myListView.setVisibility(View.GONE);, but it's not dissappearing until later... do I need to let it know somehow that I've changed it's visibility? Or do I need to also hide it's inner elements or something?
Description of Problem:
I have a normal news app. You see a list of articles for the "main" section, then you can click the options to select a new section.
When the user clicked, the section title changed, but the articles in the list would just sit there with "old" content until the new content is loaded, then it would flash to the new content.
This isn't ideal obviously. I'd like the list to disappear, show a loading animation, then, after the new data is retrieved (either from DB or online, then DB), it shows the new content.
I found this SO question which seemed like what I want, but...
I'm setting GONE immediately upon selection of the menu, then VISIBLE after it import the articles and loads the new ones... but it's not disappearing at all during that. I know the GONE code works, because if I remove my VISIBLE code, the articles never reappear.
Do I need to say "View.GONE", then tell it to update it's visibility or something?
My Code (MainActivity):
public static void sectionSelected()
{
String selectedText = sectionsSpinner.getSelectedItem().toString();
String[] selectedSection = Section.stringToSection(selectedText);
//check if it was already the current section
if(!Section.isEqual(Section.currentSection, selectedText))
{
//hides list of articles
articleEntryListView.setVisibility(View.GONE);
//sets new currentSection
Section.currentSection = selectedSection; // Section.stringToSection(sectionsSpinner.getSelectedItem().toString());
//imports articles (if it's been more than an hour since last import)
articlesDataSource.importArticles(Section.currentSection, true, false);
//loads article from database to the list
loadArticlesIntoList(Section.currentSection);
}
}
public static void loadArticlesIntoList(String[] section)
{
//clears the list
//articleEntryAdapter.clear(); //don't think I need this now that I'm just going to hide it
//articleEntryAdapter.notifyDataSetChanged();
//POPULATES THE LIST OF ARTICLES, THROUGH THE ADAPTER
for(final Article a1 : articlesDataSource.getArticles(section))
{
articleEntryAdapter.add(a1);
}
articleEntryAdapter.notifyDataSetChanged();
//shows list of articles
articleEntryListView.setVisibility(View.VISIBLE);
}
ADDITION: here is my importAricles() code: http://pastebin.com/8j6JZBej
You have to invalidate the view anytime you make a change to its appearance, so make a call to articleEntryListView.invalidate() after setting the visibility.

Categories

Resources