I made gridview with Android-Universal-Image-Loader
and, when I select a picture, it's goes on the imageview.
when I select it first, it works fine. but the second one is crashed. (out of memory)
I load over 1M size image (originally took by default camera)
here is code to initialize
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
.memoryCacheExtraOptions(480, 800) // default = device screen dimensions
.discCacheExtraOptions(480, 800, CompressFormat.JPEG, 75)
.taskExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
.taskExecutorForCachedImages(AsyncTask.THREAD_POOL_EXECUTOR)
.threadPoolSize(3) // default
.denyCacheImageMultipleSizesInMemory()
.memoryCacheSize(2 * 1024 * 1024)
.discCacheSize(50 * 1024 * 1024)
.discCacheFileCount(100)
.enableLogging()
.build();
and here is get uri when it's selected
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// when clicked image
//startImagePagerActivity(position);
//URI imageUri = URI.parse("android.resource://com.kmob.camera/" + parent.getItemIdAtPosition(position));
SignUp.profilePath = Uri.parse(imageUrls[position].substring(7)); // return selected uri except prefix, "file://"
Log.v("OWL", "selected file: " + imageUrls[position].substring(7));
finish();
}
});
and here is result for activity
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
//mProfile.notifyAll();
if(profilePath.getPath().toString().length()>0){
mProfile.setImageURI(profilePath);
}
}
Thanks in advance,
According to the author suggestion mention the following two lines in displayoptions
.imageScaleType(ImageScaleType.IN_SAMPLE_INT)
.bitmapConfig(Config.RGB_565) in displayioptions.
And in configuration
.memorycache(new WeakMemoryCache())
Related
I have a problem to understand a chained "RXJava-Retrofit" API call. I got inspired by this and implement this class named ObservationLoader to load the data from the API bucket per bucket. When the end of data is reached the API sends a endOfRecords=true:
public Observable<PageObject<Observation>> getAllObservationDataByRegion(long taxonKey,
String regionId) {
final PublishSubject<PageObject<Observation>> subject = PublishSubject.create();
return subject.doOnSubscribe(disposable -> {
this.getData(taxonKey, regionId, 0).subscribe(subject);
})
.doOnNext(observationPageObject -> {
if (observationPageObject.isEndOfRecords()) {
// -> list is completely loaded
subject.onComplete();
} else {
int nextOffset = observationPageObject.getOffset() + 1;
this.getData(taxonKey, regionId, null, nextOffset).subscribe(subject);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
private Observable<PageObject<Observation>> getData(long id,
String regionId,
int offset) {
// Get your API response value
return this.api.getObservations(id, regionId, ObservationLoader.PAGE_LIMIT, offset);
}
In my Android fragment HomeFragment I subscribe to the ObservationLoader:
ObservationLoader loader = new ObservationLoader(this.getApi());
Observable<PageObject<Observation>> observable = loader
.getAllObservationDataByRegion(this.getSelectedSpecies(), this.getSelectedRegion());
observable.subscribe(new Observer<PageObject<Observation>>() {
#Override
public void onSubscribe(Disposable d) {
Log.i(TAG, "ON_SUBSCRIBE");
}
#Override
public void onNext(PageObject<Observation> observationPageObject) {
Log.i(TAG, "ON_NEXT");
}
#Override
public void onError(Throwable e) {
Log.i(TAG, "ERROR = " + e.getMessage());
}
#Override
public void onComplete() {
Log.i(TAG, "COMPLETED");
}
});
I can see that the onSubscribe() and doOnSubscribe() are called and even the getData() is reached. I assume the API is responding correctly (a previous attempt attempt with recursion worked fine). But I never reached the doOnNext function. The observer goes straight to onComplete() and no data is received. What could be the reason?
When doOnSubscribe runs, the doesn't see any consumers yet so if getData is synchronous, there won't be any first results to trigger further results. Also if getData ends, it will complete the setup so the next getData call in doOnNext will push to an already terminated subject, ingoring all data.
You'll need a differently organized feedback loop:
// we loop back the nextOffset, in a thread-safe manner
Subject<Integer> subject = PublishSubject.<Integer>create()
.toSerialized();
// bootstrap with 0 and keep open for more offsets
subject.mergeWith(Observable.just(0))
// get the data for the current offset
.concatMap(nextOffset -> getData(taxonKey, regionId, nextOffset)
.subscribeOn(Schedulers.io())
)
// if the response is end of records, stop
.takeWhile(observationPageObject -> !observationPageObject.isEndOfRecords())
// otherwise not end of records, feedback the new offset
.doOnNext(observationPageObject ->
subject.onNext(observationPageObject.getOffset() + 1)
)
// get the data on the main thread
.observeOn(AndroidSchedulers.mainThread());
Where should I put this chunk of code in order the listener function works every time I enter the app from the deep link?
Now in my unity mobile app I have this code in the initial load, however it does not work well.
The first case of entering the app from the deep link is not being handled. Only after initial load when I click the deep link my listener function works (as the listener is already set).
Is there any solution to this issue?
void Start()
{
DynamicLinks.DynamicLinkReceived += OnDynamicLink;
}
// Display the dynamic link received by the application.
void OnDynamicLink(object sender, EventArgs args)
{
var dynamicLinkEventArgs = args as ReceivedDynamicLinkEventArgs;
Debug.LogFormat("Received dynamic link {0}", dynamicLinkEventArgs.ReceivedDynamicLink.Url.OriginalString);
}
Test this, feel free to edit.
void Start()
{
StartCoroutine(WaitLoader()); //Loader
}
public void trueAwoken()
{
DynamicLinks.DynamicLinkReceived += OnDynamicLink;
}
public IEnumerator WaitLoader()
{
int i = 0;
while (i < 5) // Potential for true load state 5 (increase this 0-1000+?, it depends on your build?)
{
i++;
//Debug.Log("Waiting: " + i + "/" + Time.deltaTime);
yield return new WaitForFixedUpdate();
}
trueAwoken();
}
I have a treeview of hierarchical data that represents elements retrieved from a database. I would like to be able to move child (leaf) nodes from one parent to another and rearrange the sequence of leaf nodes within a parent via drag-and-drop, finally updating the database with the results of the move operations.
Right now I can drop one of the leaf nodes onto a parent node which allows me to add the child to the parent. However, I don't really see how to drop a leaf node between two other leaf nodes, either in the same parent or in a different parent node.
I would like to be able to do something like the following. Starting with a tree that looks like this:
Root
|
+-+-P1
| |
| +--L1a
| +--L1b
|
+-+-P2
|
+--L2a
+--L2b
For example, I would like to be able to select L2a and drag it up and drop it between L1a and L1b. Or before L1a, or after L1b. Having done that I would like to drag the child nodes of P1 around and rearrange them via DND.
Part of this would be to provide an indication of the drop location. For example, a line between L1a and L1b if you have the cursor positioned 'between' these nodes.
Is this possible? I don't see any examples of this anywhere.
One other thing I am seeing is that the effect of DND doesn't remove the leaf node from its original location even though in the setOnDragDetected method call for my cells I call cell.startDragAndDrop(TransferMode.MOVE). How can I get that to work?
Edit 9/1/17
I figured out the last part of not removing the leaf node.
Here is the code I am using to test this process out. I have an interface IStoryItem that is the (empty) interface implemented by two subclasses, Story and Part (just to create a hierarchy to test with). The Story class has title (String) and parts (Part[]) fields. The Part class has title (String) and partNumber (int) fields. I have a Utils class that creates an array of Story objects to populate my TreeView instance.
Here is my controller class. It's a bit long and in need of cleanup but shows what I have tried so far.
public class Controller {
public TreeView<IStoryItem> tv;
private final DataFormat objectDataFormat = new DataFormat("application/x-java-serialized-object");
class StoryRoot implements IStoryItem { }
TreeItem<IStoryItem> rootItem;
#FXML
public void initialize() {
StoryRoot storyRoot = new StoryRoot();
rootItem = new TreeItem<>(storyRoot);
tv.setRoot(rootItem);
// For Drag and Drop:
// - rootItem can only accept Story nodes.
// - Story nodes can only accept Part nodes.
// - Part nodes can't accept any other nodes.
tv.setCellFactory(new Callback<TreeView<IStoryItem>, TreeCell<IStoryItem>>() {
#Override
public TreeCell<IStoryItem> call(TreeView<IStoryItem> siTreeView) {
TreeCell<IStoryItem> cell = new TreeCell<IStoryItem>() {
#Override
protected void updateItem(IStoryItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null) { setText(item.toString()); }
}
};
// The following calls are as outlined in:
// https://docs.oracle.com/javase/8/javafx/events-tutorial/drag-drop.htm#CHDJFJDH
cell.setOnDragDetected((MouseEvent event) -> {
// Don't drag Story nodes.
if (cell.getItem() instanceof Story) return;
// drag was detected, start a drag-and-drop gesture
// allow Move transfer mode only
Dragboard db = cell.startDragAndDrop(TransferMode.MOVE);
// Put the Part on the dragboard
// From: https://stackoverflow.com/a/30916660/780350
ClipboardContent content = new ClipboardContent();
content.put(objectDataFormat, cell.getItem());
db.setContent(content);
event.consume();
});
cell.setOnDragDropped((DragEvent event) -> {
try {
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasContent(objectDataFormat)) {
Part droppedPart = (Part)db.getContent(objectDataFormat);
IStoryItem targetStoryItem = cell.getItem();
// Question: How to handle drops between leaf items or
// before the initial leaf or after the final leaf.
if (targetStoryItem instanceof Story) {
Story story = (Story) targetStoryItem;
updateStoryWith(droppedPart, story);
addPartTo(cell.getTreeItem(), droppedPart);
success = true;
}
}
event.setDropCompleted(success);
event.consume();
} catch (Exception e) {
System.out.println(e.getMessage());
}
});
cell.setOnDragDone((DragEvent event) -> {
/*
* the drag and drop gesture ended
* if the data was successfully moved, clear it
*/
if (event.getTransferMode() == TransferMode.MOVE) {
// TODO: remove the part that got moved.
IStoryItem item = cell.getItem();
TreeItem<IStoryItem> ti = cell.getTreeItem();
TreeItem<IStoryItem> pti = ti.getParent();
pti.getChildren().remove(ti);
IStoryItem psi = pti.getValue();
boolean removed = removePartFrom(psi, item);
}
event.consume();
});
return cell;
};
});
tv.getSelectionModel()
.selectedItemProperty()
.addListener((observable, oldValue, newValue) -> inspectObject(newValue.getValue()));;
Story[] stories = Utils.createStories();
for (Story s: stories) {
addStoryToTree(s);
}
}
private void updateStoryWith(Part droppedPart, Story story) {
List<Part> partsList = new ArrayList<>(Arrays.asList(story.parts));
partsList.add(droppedPart);
Part [] newParts = (Part[])partsList.toArray(new Part[partsList.size()]);
int idx = 1;
for (Part part : newParts) {
part.partnumber = idx++;
}
story.parts = newParts;
}
private void inspectObject(Object o) {
if (!(o instanceof IStoryItem)) {
System.out.println(o.getClass().toString());
} else if (o instanceof Story) {
Story s = (Story)o;
System.out.println("Story: " + s.toString());
} else if (o instanceof Part) {
Part s = (Part)o;
System.out.println("Part: " + s.toString());
}
}
void addStoryToTree(Story story) {
if (story.parts.length == 0) return;
TreeItem<IStoryItem> item = new TreeItem<>(story);
rootItem.getChildren().add(item);
for (Part part : story.parts) {
addPartTo(item, part);
}
}
void addPartTo(TreeItem<IStoryItem> storyItem, Part part) {
TreeItem<IStoryItem> partItem = new TreeItem<>(part);
storyItem.getChildren().add(partItem);
}
boolean removePartFrom(IStoryItem si, IStoryItem pi) {
if (!(si instanceof Story)) return false;
if (!(pi instanceof Part)) return false;
Story story = (Story) si;
Part part = (Part) pi;
List<Part> plist = new LinkedList<>(Arrays.asList(story.parts));
if (!plist.contains(part)) return false;
boolean removed = plist.remove(part);
story.parts = plist.toArray(new Part[plist.size()]);
return removed;
}
}
In my app, I have a searchbox which allows users to filter as they type. For some reason I can't get an InfinteProgress to properly display while the filtering is being executed.
Here's my code:
Pass 1
public void renderForumList(){
try{
magnify = mStateMachine.findForumSearchIcon(form);
}catch(NullPointerException ex){
System.out.println("User typed additional character in search term before previous term finished executing");
}
InfiniteProgress infi = new InfiniteProgress();
magnify.getParent().replace(magnify, infi, null);
Display.getInstance().invokeAndBlock(new Runnable() {
#Override
public void run() {
for (int i = 0;i < containerStates.length;i++){
if(containerStates[i] != listItems[i].isVisible()){
listItems[i].setHidden(!containerStates[i]);
listItems[i].setVisible(containerStates[i]);
}
}
Display.getInstance().callSerially(new Runnable() {
#Override
public void run() {
mStateMachine.findForumsListComponent(form).animateLayout(200);
mStateMachine.findContainer2(form).replace(infi, magnify, null);
}
});
}
});
}
In this version, the infinite progress shows up in the proper position, but it doesn't spin.
Pass 2
public void renderForumList(){
try{
magnify = mStateMachine.findForumSearchIcon(form);
}catch(NullPointerException ex){
System.out.println("User typed additional character in search term before previous term finished executing");
}
InfiniteProgress infi = new InfiniteProgress();
magnify.getParent().replace(magnify, infi, null);
for (int i = 0;i < containerStates.length;i++){
if(containerStates[i] != listItems[i].isVisible()){
listItems[i].setHidden(!containerStates[i]);
listItems[i].setVisible(containerStates[i]);
}
}
mStateMachine.findForumsListComponent(form).animateLayout(200);
mStateMachine.findContainer2(form).replace(infi, magnify, null);
}
}
}
In this version, the magnifier icon just flashes briefly, but the InfiniteProgress spinner is never visible.
I get the same results on the simulator and on an Android device.
How can I get the InfiniteProgress to spin while the search is taking place?
invokeAndBlock opens a new thread and thus violates the EDT as you access UI components on a separate thread.
Try using callSerially instead to postpone the following code into the next EDT cycle although I'm not sure that will help as everything is still happening on the EDT.
Alternatively I'm guessing the method isVisible takes time, so you can enclose that call alone in invokeAndBlock.
To understand invokeAndBlock check out the developer guide https://www.codenameone.com/manual/edt.html
My users upload some images to the FileStorage at Backendless.
This is the upload sequence:
Backendless.Files.Android.upload(image1_scaled, Bitmap.CompressFormat.PNG,
100, "profileImage", "images", new AsyncCallback<BackendlessFile>() {
#Override
public void handleResponse(BackendlessFile response) {
fileMapping.profile_url = response.getFileURL();
Backendless.Data.of(FileMapping.class).save(fileMapping,
new AsyncCallback<FileMapping>() {
#Override
public void handleResponse(FileMapping response) {
toast_error("Image stored");
}
#Override
public void handleFault(BackendlessFault fault) {
System.out.println("ERROR" + fault.getCode());
}
});
}
#Override
public void handleFault(BackendlessFault fault) {
}
});
And that works flawlessly. Now I need to fetch back the image with the API to display it.
So I need to make a BackendlessCollection<FileMapping> userFiles = Backendless.Data.of(FileMapping.class) call to receive the URL back from that table. And then supposedly do a httpRequest with the url to get back the byte data.
What I can't work out is what sort of .find method to use? Do I .findById() ? And if so, what ID do I use? The "path", "name" ,"table" etc?
Could anyone show an example fitting my case here, with a table storing the url's and such?
Thanks.
You'd this something like this (showing sync call for simplicity, but make sure to change it to Async on Android):
BackendlessCollection<FileMapping> fileMappings;
fileMappings = Backendless.Data.of( FileMapping.class ).find();
Iterator<FileMapping> iterator = fileMappings.getCurrentPage().iterator();
while( iterator.hasNext() )
{
FileMapping fileMapping = iterator.next();
Log.i( "MyApp", "file URL is " + fileMapping.profile_url );
}