I am trying to get info from a server, including photos. I have created a class called ServerManager, which allows me to download the desired information. However, I cannot download images with Picasso because I get a java.lang.IllegalStateException: Method call should happen from the main thread..
This is what I am doing in ServerManager:
// Check if the photo is already downloaded
if (!checkInternalPhoto(member)) {
final String outputURL = context.getFilesDir().getAbsolutePath() + "/" + member.photoPath;
String photoURL = rootURL + "photos/" + member.photoPath;
Picasso.with(context)
.load(photoURL)
.into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
File file = new File(outputURL);
try {
file.createNewFile();
FileOutputStream outputStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG,100,outputStream);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
Log.e("IOException",e.getLocalizedMessage());
}
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
}
What can I do?
Edit: I tried to use the code in my MainActivity and I am getting the same error message...
public void downloadPhotos(List<Member> memberList){
String rootInURL = serverManager.getRootURL();
String rootOutURL = serverManager.getOutputURL();
for(int i = 0; i < memberList.size(); i++){
if(!serverManager.checkInternalPhoto(memberList.get(i))){
final String outputURL = rootOutURL + memberList.get(i).photoPath;
String photoURL = rootInURL + "photos/" + memberList.get(i).photoPath;
Picasso.with(this)
.load(photoURL)
.into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
File file = new File(outputURL);
try{
file.createNewFile();
FileOutputStream outputStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG,100,outputStream);
outputStream.flush();
outputStream.close();
Toast.makeText(context, "YEpa: " ,Toast.LENGTH_LONG).show();
} catch (IOException e){
Toast.makeText(context, "Error: " + e.toString(),Toast.LENGTH_LONG).show();
}
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
}
}
}
Try this and your error should disappear. This problem always happens when you use it in Unit Android test
kotlin code
Handler(Looper.getMainLooper()).post {
}
java code
new Handler(Looper.getMainLooper()).post(() -> {
});
You can't update an ui element from a different thread than the one which created that ui element. On Android that almost always means the main thread.
What you need to do is send back the photoUrl String to your activity or fragment on the main thread. The traditional way of doing it is by using a Handler. You can read about this more here: https://developer.android.com/training/multiple-threads/communicate-ui.html
Related
The current code works to save the photo but I want to implement the toast code below when the user saves the image already it show image save already. Any ideas how I would do this.
Below is the source code to take the photo:
holder.save.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
checkFolder();
final String path = imagesList.get(position).getPath();
final File file=new File(path);
String destPath = Environment.getExternalStorageDirectory().getAbsolutePath()+Common.APP_DIR;
final File destFile =new File(destPath);
try {
FileUtils.copyFileToDirectory(file, destFile);
} catch (IOException e) {
e.printStackTrace();
}
MediaScannerConnection.scanFile(context, new String[]{destPath + status.getTitle()},
new String[]{"*/*"}, new MediaScannerConnection.MediaScannerConnectionClient() {
#Override
public void onMediaScannerConnected() {
}
#Override
public void onScanCompleted(String path, Uri uri) {
}
});
Toast.makeText(context, "Image Saved Successfully!", Toast.LENGTH_SHORT).show();
}
});
I went through the solution here.
Android FFMpeg No such file or directory error but it doesn't work for me.
The file is present in the location and I am still getting this error.
Here is the code snippet
private void spliceSong(AudioObject audioObject) {
File folder = new File("/sdcard/roboscreen/TempAudio");
if (!folder.exists()) {
folder.mkdir();
}
String fileName = new File(audioObject.path).getName();
File dest = new File(folder, fileName);
Log.d(TAG, "Destination Filename is " + fileName);
if (!dest.exists()){
try {
dest.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
String path = new File(audioObject.path).getPath();
Log.d(TAG, "File created " + dest.getAbsolutePath() + " " + audioObject.endDate + " " + audioObject.startDate);
String[] command = {"-ss", "2", "-i", "root/"+path, dest.toString()};
Log.d(TAG, "spliceSong: " + (this.context==null));
FFmpeg ffmpeg = FFmpeg.getInstance(this.context);
// // to execute "ffmpeg -version" command you just need to pass "-version"
try {
ffmpeg.loadBinary(new LoadBinaryResponseHandler(){
#Override
public void onSuccess() {
super.onSuccess();
Log.d(TAG, "onSuccess: bruhhhhh");
}
});
} catch (FFmpegNotSupportedException e) {
// Log.d(TAG, "Kaam Tamaam");
e.printStackTrace();
}
try {
ffmpeg.execute(command, new ExecuteBinaryResponseHandler() {
#Override
public void onStart() {
Log.d(TAG, "Work Started done");
}
#Override
public void onProgress(String message) {
Log.d(TAG, "Doing some work");
}
#Override
public void onFailure(String message) {
Log.d(TAG, "Conversion failure " + message);
}
#Override
public void onSuccess(String message) {
Log.d(TAG, "Conversion Successful");
}
#Override
public void onFinish() {
Log.d(TAG, "Work Dome");
}
});
} catch (FFmpegCommandAlreadyRunningException e) {
Log.d(TAG, e.toString());
e.printStackTrace();
}
// Log.d(TAG, "spliced");
// return File
}
and the context is coming through a different class
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ScreenRecorder(RoboTutor activity, Context context) throws Exception {
if (isInstantiated){
// raise Error and quit
throw new Exception("One instance already instantiated");
}
this.activity = activity;
this.context = context;
this.isInstantiated = true;
this.videoTimeStamp = new Date();
}
A solution would be really appreciated.
Thanks in advance.
Figured it out. There were no issues with the library. I was referring to the wrong paths.
I need to download mp3 file from server using retrofit.using enqueue() method ,the response callback comes in UI thread. So I decide to use execute() method from a worker thread. But my requirement is , I need to download multiple mp3 files in parallel. below is my code , Can u please let me know if it is a good practice or please suggest me a better approach.
#Override
public void onClick(View v) {
final DownloadAndStoreMusic downloadAndStoreMusic = new DownloadAndStoreMusic(this);
new Thread(new Runnable() {
#Override
public void run() {
downloadAndStoreMusic.downloadLoadMusic(musicUrlForPerseFromServer, musicUrlforLocalStorage, actionString,categoryIndex,itemIndex);
}
}).start();
}
On the Downloading class
public class DownloadAndStoreMusic {
private static final String TAG = "tag";
ApiInterfaceforMusicPersing apiInterfaceforMusicPersing;
Context mContext;
DownloadAndStoreMusic(Context mContext) {
apiInterfaceforMusicPersing = RetrofitApiClientForMusicPersing.getClient().create(ApiInterfaceforMusicPersing.class);
this.mContext = mContext;
}
public void downloadLoadMusic(final String musicUrlForPerseFromServer, final String musicUrlforLocalStorage, final String actionString,final int categoryIndex, final int itemIndex) {
/* String[] split = url.split("/");
final String pathToLocalStorage = url; // We bought music location with category path
String musicLink = split[1];*/
Log.e("server", musicUrlForPerseFromServer);
Log.e("perse", musicUrlforLocalStorage);
Call<ResponseBody> responseBodyCall = apiInterfaceforMusicPersing.downloadMusic(musicUrlForPerseFromServer);
/* responseBodyCall.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, final Response<ResponseBody> response) {
Log.e("music", "completed");
new Thread(new Runnable() {
#Override
public void run() {
writeResponseBodyToDisk(response.body(), musicUrlforLocalStorage, musicUrlForPerseFromServer, actionString,categoryIndex,itemIndex);
}
}).start();
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(mContext, "Problem downloading audio", Toast.LENGTH_SHORT).show();
}
});*/
try
{
Response<ResponseBody> execute = responseBodyCall.execute();
ResponseBody body = execute.body();
writeResponseBodyToDisk(body, musicUrlforLocalStorage, musicUrlForPerseFromServer, actionString,categoryIndex,itemIndex);
}
catch (Exception e)
{
Toast.makeText(mContext, "Problem downloading audio", Toast.LENGTH_SHORT).show();
Log.e("exception"," : "+e+ " , "+musicUrlforLocalStorage);
}
}
private boolean writeResponseBodyToDisk(ResponseBody body, String pathToLocalStorage, String musicUrlForPerseFromServer, String actionString, int categoryIndex, int itemIndex) {
try {
// todo change the file location/name according to your needs
/* File audioParentDirectory;
String[] split = musicUrlForPerseFromServer.split("/");
String parentPath = split[0];
String audioName = split[1];
audioParentDirectory = new File(MyConstants.FILE_AUDIO_DIRECTORY, parentPath);
File parent = new File(audioParentDirectory,parentPath);
Log.e("audioparent",audioParentDirectory.getAbsolutePath());*/
File audioDirectory = new File(pathToLocalStorage);
Log.e("file", audioDirectory.getAbsolutePath());
InputStream inputStream = null;
OutputStream outputStream = null;
try {
byte[] fileReader = new byte[4096];
long fileSize = body.contentLength();
long fileSizeDownloaded = 0;
inputStream = body.byteStream();
outputStream = new FileOutputStream(audioDirectory);
while (true) {
int read = inputStream.read(fileReader);
if (read == -1) {
break;
}
outputStream.write(fileReader, 0, read);
fileSizeDownloaded += read;
Log.e(TAG, "file download: " + fileSizeDownloaded + " of " + fileSize);
}
outputStream.flush();
Log.e("music","music downloaded : "+ audioDirectory.getAbsolutePath());
}
}
return false;
}
Your approach is correct you will download multiply mp3 files as you expected.
i am try to download a image and save it locally. Everything runs trough i didnt get any exceptions, but the file dont appear in my location
i searched for an solution but didnt find any.
Heres my code:
private void saveImages() {
try{
final File thumbsPath = new File(getExternalFilesDir(null), "thumbs");
if (!thumbsPath.exists())
thumbsPath.mkdirs();
Target target = new Target(){
#Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
new Thread(new Runnable() {
#Override
public void run() {
File file = new File(thumbsPath.getAbsolutePath() + "/file.jpeg"); //folder exists
try {
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, ostream);
ostream.flush();
ostream.close();
} catch (Exception e) {
Log.e("ERROR", e.getMessage());
}
}
}).start();
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
Log.e("ERROR", "");
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
Log.e("ERROR", "");
}
};
Picasso.with(getApplicationContext())
.load(myurltodownloadfrom)
.into(target);
}
catch (Exception e){
Log.e("ERROR",e.getMessage());
}
}
Never store Files that way.
It is all covered here: https://developer.android.com/training/basics/data-storage/files.html
How can i load images as they are visible in android? Does anyone know a good tutorial? Moreover, do i need a asyncTask in order to do this? And moreover, if i want to have a picture like the following how should i declare my Android XML file?
There is a really amazing tutorial on the developers website on how to do this. The sample application that comes with it is beautifully done too. You should read it. :)
http://developer.android.com/training/displaying-bitmaps/index.html
It's called lazy loading of images in a listview. Here's a piece of code you can use to do this:
package com.wilson.android.library;
import java.io.IOException;
public class DrawableManager {
private final Map<String, Drawable> drawableMap;
public DrawableManager() {
drawableMap = new HashMap<String, Drawable>();
}
public Drawable fetchDrawable(String urlString) {
if (drawableMap.containsKey(urlString)) {
return drawableMap.get(urlString);
}
Log.d(this.getClass().getSimpleName(), "image url:" + urlString);
try {
InputStream is = fetch(urlString);
Drawable drawable = Drawable.createFromStream(is, "src");
if (drawable != null) {
drawableMap.put(urlString, drawable);
Log.d(this.getClass().getSimpleName(), "got a thumbnail drawable: " + drawable.getBounds() + ", "
+ drawable.getIntrinsicHeight() + "," + drawable.getIntrinsicWidth() + ", "
+ drawable.getMinimumHeight() + "," + drawable.getMinimumWidth());
} else {
Log.w(this.getClass().getSimpleName(), "could not get thumbnail");
}
return drawable;
} catch (MalformedURLException e) {
Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
return null;
} catch (IOException e) {
Log.e(this.getClass().getSimpleName(), "fetchDrawable failed", e);
return null;
}
}
public void fetchDrawableOnThread(final String urlString, final ImageView imageView) {
if (drawableMap.containsKey(urlString)) {
imageView.setImageDrawable(drawableMap.get(urlString));
}
final Handler handler = new Handler() {
#Override
public void handleMessage(Message message) {
imageView.setImageDrawable((Drawable) message.obj);
}
};
Thread thread = new Thread() {
#Override
public void run() {
//TODO : set imageView to a "pending" image
Drawable drawable = fetchDrawable(urlString);
Message message = handler.obtainMessage(1, drawable);
handler.sendMessage(message);
}
};
thread.start();
}
private InputStream fetch(String urlString) throws MalformedURLException, IOException {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet(urlString);
HttpResponse response = httpClient.execute(request);
return response.getEntity().getContent();
}
}
obtained from this thread: Lazy load of images in ListView