I have a method that creates targets for Picasso like this:
private void createTargets() {
Target target;
for (Id id : itemids) {
target = picassoImageTarget(getContext(), "imageDir", id.getId() + ".png");
imgTargets.add(new ImgTarget(id.getId(), target));
}
}
and then I download images to disk this way:
private void download() {
for (ImgTarget imgTarget : imgTargets) {
Picasso.with(getContext()).load("https://www.sestavsisvujsvet.cz/files/magnetky/" + imgTarget.getId() + ".png").into(imgTarget.getTarget());
}
}
it does what I want it to do, however I am unable to get a callback, because the constructor with callback exists only when using ImageView:
Can someone help me find a solution to this? I don't understand callbacks and things like that too much, so it's hard for me to figure it out.
I just need to know when the whole downloading process has finished so I can notify the user.
Thanks :)
A picasso Target is essentially a callback, if you look at the Target object, it has the following structure:
Target target = new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
// Notify the user
}
#Override
public void onBitmapFailed(Exception e, Drawable errorDrawable) {
// Notify the user
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
In your function picassoImageTarget(...) you would be building that target, and inside the onBitmapLoaded and onBitmapFailed you can put your code in to notify the user depending on your implementation.
Also, I noticed you are using Picasso.with(context), this has been updated to Picasso.get() in the latest library, might be worthwhile updating your picasso library to the latest too.
Related
I have a mp4 file(already recorded) and want to change the rotation(including meta data) of the video. There is a way to do this using Hex Editor where in you find the track header(tkhdr) and replace the rotation matrix with the required rotation.
I know this can be done using ffmpeg library but I do not want to use the library instead I want to do this in Android using JAVA. Let me know if anyone has done this before.
Thanks
Ravi
Reference link
This library may help you: https://github.com/MasayukiSuda/Mp4Composer-android
This library generates an Mp4 movie using Android MediaCodec API and can rotate Mp4.
StackOverflow reference: https://stackoverflow.com/a/19392712/8572503
It's API is fluent and easy :
new Mp4Composer(sourceFile, destinationFile)
.rotation(Rotation.ROTATION_90)
.size(1280,720) //720P
.fillMode(FillMode.PRESERVE_ASPECT_FIT)
.listener(new Mp4Composer.Listener() {
#Override
public void onProgress(double progress) {
Log.d(TAG, "onProgress = " + progress);
//or show in notification
}
#Override
public void onCompleted() {
Log.v(TAG, "onCompleted() : Destination → "+ destinationFile);
}
#Override
public void onCanceled() {
Log.d(TAG, "onCanceled");
}
#Override
public void onFailed(Exception exception) {
Log.wtf(TAG, "onFailed()", exception);
}
})
.start();
You can also see this transcoder has written in pure Java: https://github.com/ypresto/android-transcoder
[EDIT: From Comment]:
You can extract code from this: https://github.com/javadev/hexeditor to manually modify the hex.
I have an image called graph.jpg in the drawable folder, and I want to fill it with a certain image every time I download it from a server. For this, I used Retrofit, and I already have the following interface:
#GET("/androidimage/")
Call<ResponseBody> getImage(
#Query("image") String command
);
And the following method in the activity:
private void getImage(WebService webService, String command){
Call<ResponseBody> call = webService.getImage(command);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()){
if (response.body() != null){
Bitmap bm = BitmapFactory.decodeStream(response.body().byteStream());
imageViewTouch.setImageBitmap(bm);
}
else {
imageViewTouch.setImageResource(R.drawable.graph);
}
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
System.out.println("LOG Error: " + t.getMessage());
}
});
}
I want my graph.jpg file to be changed to the most recent bm, converted to JPG. How can this be done?
Thanks to #Alex Klimashevsky's answer, I was able to do this using the Picasso library, and it's much simpler.
Use Picasso library for it.
This library has caching mechanism from the box.
Also you cannot replace images from /drawable folder.
I'm using the example code on this page (http://altbeacon.github.io/android-beacon-library/samples.html) in the Starting an App in the Background section and I've got a working app.
It detects whenever a beacon is in range even on background.
The problem is I need to know which beacon is it (UUID, Major, Minor) to then match it against my local database and throw a notification with the app still on background.
The didEnterRegion(Region region) function only has a matchesBeacon method, and I've tried doing the following to identify which of the beacons is being seen but it's throwing a NullPointerException:
public class SightSeeing extends Activity implements BootstrapNotifier, RangeNotifier {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Region region = new Region("sightRegion", null, null, null);
regionBootstrap = new RegionBootstrap(this, region);
BeaconManager.getInstanceForApplication(this).getBeaconParsers().add(
new BeaconParser(). setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24")
);
BeaconManager.getInstanceForApplication(this).setRangeNotifier(this);
}
#Override
public void didEnterRegion(Region region) {
regionBootstrap.disable();
BeaconManager.getInstanceForApplication(this).setRangeNotifier(this);
try {
BeaconManager.getInstanceForApplication(this).startRangingBeaconsInRegion(region);
}
catch (RemoteException e) {
Log.e(TAG, "Can't start ranging");
}
}
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if (beacons.size() > 0) {
Iterator<Beacon> beaconIterator = beacons.iterator();
while (beaconIterator.hasNext()) {
Beacon beacon = beaconIterator.next();
//check if beacon exists in our DB and throw notification
}
}
}
Am I missing something obvious or isn't this possible with this library?
EDIT:
I've updated the code sample to give you guys a broader idea and I've tried implementing the suggestion by FOliveira without any success.
EDIT2:
Updated code to reflect the davidgyoung's suggestion. Still no luck. I have a Log.d() right on the first line of the didRangeBeaconsInRegion() function and it isn't being called.
I've tried adding BeaconManager.getInstanceForApplication(this).setRangeNotifier(this); before the try/catch block and the result is the same.
Did I implement the suggestion wrong or is there any other way to get this working?
If you want the app to launch itself on beacon detection, then the RegionBootstrap is the easiest way to go. In order to combine this with Ranging needed to detect individual beacons, then add code in your didEnterRegion method like this:
try {
BeaconManager.getInstanceForApplication(this).startRangingBeaconsInRegion(region);
}
catch (RemoteException e) {
Log.e(TAG, "Can't start ranging");
}
Then implement a ranging callback like you have.
You also need to remove the code below, which is probably what is causing your NullPointerException, because the :
for(int i=0; i< beaconsList.size(); i++) {
Beacon b = new Beacon.Builder()
.setId1(beaconsList.get(i).get("uuid"))
.setId2(beaconsList.get(i).get("major"))
.setId3(beaconsList.get(i).get("minor"))
.build();
if(region.matchesBeacon(b)) {
//get info from DB and throw notification
}
}
EDIT: I have updated the library's reference application to show how this can be done successfully. See here: https://github.com/AltBeacon/android-beacon-library-reference/blob/master/src/org/altbeacon/beaconreference/BeaconReferenceApplication.java
you can implement RangeNotifier interface and you can access all the beacon information captured in the public void didRangeBeaconsInRegion(Collection<Beacon> Beacons, Region region) method of that interface. Hope i got the question right
I'm using a bit of code to help me with pulling data from the web called WebRequest (https://github.com/delight-im/Android-WebRequest). It provides a callback for retrieving asynchronous data. However I can't update my ArrayAdapter because I get an error "Non-Static method 'notifyDataSetChanged()' cannot be referenced from a static context"
Now, I've seen a number of similar questions here. Some suggest putting the notifyDataSetChanged command in the Adapter class itself. Some suggest using a Handler and some suggest using a Loader. However I have had no luck actually implementing these solutions. Here's my code:
new WebRequest().get().to(stringSQLUrl).executeAsync(new WebRequest.Callback() {
public void onSuccess(int responseCode, String responseText) {
try {
DataHistory = CsvUtil.fromCsvTable(responseText);
DataHistory.remove(0); //Removes header row
} catch (Exception e) {
Log.e("Main pullWebData","Error converting from CsvTable: " + e.getMessage());
}
DataAdapter.notifyDataSetChanged(); // <-- ERROR HERE
runOnUiThread(new Runnable() {
#Override
public void run() {
DataAdapter.notifyDataSetChanged(); // <-- ALSO ERROR HERE
}
});
}
public void onError() {
Log.e("Main pullWebData","Error pulling data from web");
}
});
I also defined this Handler in my activity thinking I could call it and it would update the ArrayAdapter, but I got the same error here:
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
WeightAdapter.notifyDataSetChanged();
}
};
Lastly I created a method inside the Adapter definition to notify itself, but calling that gave me the same static/non-staic error:
public void updateMe() {
this.notifyDataSetChanged();
}
Long story short - there are a ton of questions seemingly about this same topic and lots of advice, but I have been unsuccessful in implementation. Can anyone show me exactly how I'd implement this?
Thank you!
One other thing: I was considering switching from Web data to an Azure SQL DB, but that would also use a callback and I presume have the same issue?
You can only call static methods using ClassName.methodName(); However, notifyDataSetChanged() is not a static method. i.e. notifyDataSetChanged() works depending on the instance of your adapter.
To make sure that this works, you should use notifyDataSetChanged() on the object of the custom adapter.
If you have something like :
DataAdapter customAdapter = new DataAdapter(//params);
listView.setAdapter(customAdapter);
You should call :
customAdapter.notifyDataSetChanged();
I am writing a custom event and would like some help please. Most of what I am about to talk about is based on the help provided at Custom event listener on Android app
So here is my issue. I am writing an app that needs to download updated images from the web, store the images on the phone, then later display those images. Basically, I download any needed images during a splash screen. Then when the images are downloaded and stored, the splash screen clears and any necessary (newly downloaded) images are displayed on the screen. Here is the problem: the download process is done via an asynctask so the part where the images are loaded on to the screen can't be done inside the asynctask. It has to be done on the main UI thread. I would like to create an event and a custom event listener for the main thread to listen for that basically tells the main UI thread that it is safe to start loading the downloaded images from memory.
According to the discussion from the link above, I came up with this so far... a download listener interace
public interface DataDownloadListener {
void onDownloadStarted();
void onDownloadFinished();
}
an event class...
public class DataDownloadEvent {
ArrayList<DataDownloadListener> listeners = new ArrayList<DataDownloadListener>();
public void setOnDownload(DataDownloadListener listener){
this.listeners.add(listener);
}
}
My problem is that I don't understand where to put the last two steps in those instructions. I thought I would have to put the listener and event inside the class that actually initiates the downloads. But where? Here is my function that initiates the download and saves it to the device:
public String download(String sourceLocation) {
String filename = "";
String path = "";
try {
File externalStorageDirectory = Environment
.getExternalStorageDirectory();
URL urlTmp = new URL(sourceLocation);
filename = urlTmp.getFile()
.substring(filename.lastIndexOf("/") + 1);
path = externalStorageDirectory + PATH;
// check if the path exists
File f = new File(path);
if (!f.exists()) {
f.mkdirs();
}
filename = path + filename;
f = new File(filename);
//only perform the download if the file doesn't already exist
if (!f.exists()) {
Bitmap bitmap = BitmapFactory.decodeStream(urlTmp.openStream());
FileOutputStream fileOutputStream = new FileOutputStream(
filename);
if (bitmap != null) {
bitmap.compress(getFormat(filename), 50, fileOutputStream);
Log.d(TAG, "Saved image " + filename);
return filename;
}
}
else{
Log.d(TAG, "Image already exists: " + filename + " Not re-downloading file.");
}
} catch (MalformedURLException e) {
//bad url
} catch (IOException e) {
//save error
}
return null;
}
And the last step about registering the listener, where do I put that? The instructions say to put that somewhere during initialization. Does that mean in the onCreate method of my main activity? outside the class in the import section of the main activity? Never done a custom event before, so any help would be appreciated.
According to the discussion from the link above, I came up with this so far... a download listener interace
public interface DataDownloadListener {
void onDownloadStarted();
void onDownloadFinished();
}
an event class...
public class DataDownloadEvent {
ArrayList<DataDownloadListener> listeners = new ArrayList<DataDownloadListener>();
public void setOnDownload(DataDownloadListener listener){
this.listeners.add(listener);
}
}
Ok...
Now in your download procedure, at the start of the download, cycle all the elements on the listeners ArrayList and invoke the onDownloadStarted event to inform all your listeners that the download is just started (in this event i presume you'll need to open the splashscreen).
Always in your download procedure, at the and of the download, cycle all the elements on the listeners ArrayList and invoke the onDownloadFinished event to inform all your listeners that the download is finished (now close the splashscreen).
How to cycle listeners on download completed
foreach(DataDownloadListener downloadListener: listeners){
downloadListener.onDownloadFinished();
}
How to cycle listeners on download started
foreach(DataDownloadListener downloadListener: listeners){
downloadListener.onDownloadStarted();
}
Don't make it static if possible... In the class that you'll use to download your files, simply add what you put in your DataDownloadEvent class (listeners arrayList and facility methods for adding and removing). You have no immediate need to use a class in that way (static members I mean).
Example
public class DownloadFileClassExample{
private ArrayList<DataDownloadListener> listeners = new ArrayList<DataDownloadListener>();
public DownloadFileClassExample(){
}
public void addDownloadListener(DataDownloadListener listener){
listeners.add(listener);
}
public void removeDownloadListener(DataDownloadListener listener){
listeners.remove(listener);
}
//this is your download procedure
public void downloadFile(){...}
}
Then access you class in this way
DownloadFileClassExample example = new DownloadFileClassExample();
example.addDownloadListener(this); // if your class is implementing the **DataDownloadListener**
or use
example.addDownloadListener( new DataDownloadListener{...})