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
Related
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 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
I'm a beginner with android programming.
I'm having some problem with downloading a file with android
I used Httpost, Httpget and hhtpurlconnection
the two first aren't working at all
and the the third can't download tow times
I want a way to download different xmls to string or inputstream (or something convertable to them) to parse those XMLs.
besides the method should be able to do something like this :
conn.setRequestProperty("Authorization", "Basic " + encodedStr);
because the xmls are responses from an API
Here I am putting an example how to download an image file from server. I am asuming that on your local server there is a picture folder and you are downloading pic from that..
Use following code it may help you..
public class DownloadType1 extends Activity{
String dwnload_file_path = "http://10.0.2.2/pictures/webicon.PNG";
String dest_file_path = Environment.getRootDirectory()+"/pictures/img1.png";
ProgressDialog dialog = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.download1);
}
public void onClick(View v) {
dialog = ProgressDialog.show(DownloadType1.this, "", "Downloading file...", true);
new Thread(new Runnable() {
public void run() {
downloadFile(dwnload_file_path, dest_file_path);
}
}).start();
}
public void downloadFile(String url, String dest_file_path) {
try {
File dest_file = new File(dest_file_path);
URL u = new URL(url);
URLConnection conn = u.openConnection();
int contentLength = conn.getContentLength();
DataInputStream stream = new DataInputStream(u.openStream());
byte[] buffer = new byte[contentLength];
stream.readFully(buffer);
stream.close();
DataOutputStream fos = new DataOutputStream(new FileOutputStream(dest_file));
fos.write(buffer);
fos.flush();
fos.close();
hideProgressIndicator();
} catch(FileNotFoundException e) {
hideProgressIndicator();
return;
} catch (IOException e) {
hideProgressIndicator();
return;
}
}
void hideProgressIndicator(){
runOnUiThread(new Runnable() {
public void run() {
dialog.dismiss();
}
});
}
}
Below an example that you can use to download a file. Naturally you will have to use a correct URL.
public InputStream downloadXmlFileStreamUsingUrl(final String url) {
log.info(String.format("downloadXmlFileStreamUsingUrl: %s", url));
final HttpGet getRequest = new HttpGet(url);
HttpClient client;
try {
client = new DefaultHttpClient();
final HttpResponse getResponse = client.execute(getRequest);
final int statusCode = getResponse.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
log.warn("Error " + statusCode + " for URL " + url);
return null;
}
final HttpEntity getResponseEntity = getResponse.getEntity();
final InputStream content = getResponseEntity.getContent();
return content;
} catch (final IOException e) {
getRequest.abort();
log.warn("Exception in downloadXmlFileStreamUsingUrl, error for URL " + url + e, e);
}
finally {
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
client.getConnectionManager().shutdown();
}
return null;
}
I want to put a text from a webpage to a textview on Android 3.0. I have this code:
public class Biografie extends Activity {
private TextView outtext;
private String HTML;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_biografie);
outtext= (TextView) findViewById(R.id.textview1);
try {
getHTML();
} catch (Exception e) {
e.printStackTrace();
}
outtext.setText("" + HTML);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.biografie, menu);
return true;
}
private void getHTML() throws ClientProtocolException, IOException
{
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpGet httpGet = new HttpGet("http://artistone.appone.nl/api/biografie.php?dataid=998"); //URL!
HttpResponse response = httpClient.execute(httpGet, localContext);
String result = "";
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = null;
while ((line = reader.readLine()) != null) {
result += line + "\n";
HTML = result;
}
}
}
My TextView returns "null" instead of the text from the page. Please help me to fix this. Thanks in regard.
Change your code to:
while ((line = reader.readLine()) != null) {
result += line + "\n";
}
HTML = result;
and try this:
outtext.setText(Html.fromHtml(HTML));
And instead of performing network action in main thread i will suggest you to do this in separate thread using AsyncTask
The problem is that you are getting NetworkOnMainThreadException
That is because you are downloading network content on the Main Thread (Activity's Thread).
Instead you need to use a background thread to download that content, or use AsynchTask.
A simple code that should fix this issue:
final Handler handler = new Handler();
Thread thread = new Thread() {
public void run() {
try {
getHTML();
handler.post(new Runnable() {
#Override
public void run() {
outtext.setText("" + HTML);
}
});
} catch (Exception e) {
e.printStackTrace();
handler.post(new Runnable() {
#Override
public void run() {
outtext.setText(e.toString());
}
}
}
};
thread.start(); // I forgot to start the thread. sorry !
Instead of :
try {
getHTML();
} catch (Exception e) {
e.printStackTrace();
}
outtext.setText("" + HTML);
Also take a look at this tutorial about android threads : Tutorial
from the beginning i used this method :
public Drawable createPortrait(String url){
try {
InputStream is = (InputStream)new URL(url).getContent();
Drawable d = Drawable.createFromStream(is, "Image");
return d;
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
but honeycomb doesn't allow me to do it anymore, what i see in my log is : android.os.networkonmainthreadexception .
the thing is that my url is already taken from json data :
private class GrabURL extends AsyncTask<String, Void, Void> {
private final HttpClient Client = new DefaultHttpClient();
private String Content;
private String Error = null;
private ProgressDialog Dialog = new ProgressDialog(Main.this);
protected void onPreExecute() {
Dialog.setMessage("Downloading source..");
Dialog.show();
}
protected Void doInBackground(String... urls) {
try {
HttpGet httpget = new HttpGet(urls[0]);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
Content = Client.execute(httpget, responseHandler);
} catch (ClientProtocolException e) {
Error = e.getMessage();
cancel(true);
} catch (IOException e) {
Error = e.getMessage();
cancel(true);
}
return null;
}
protected void onPostExecute(Void unused) {
Dialog.dismiss();
if (Error != null) {
Toast.makeText(Main.this, Error, Toast.LENGTH_LONG).show();
} else {
Toast.makeText(Main.this, "Source: " + Content, Toast.LENGTH_LONG).show();
}
Object o = new Gson().fromJson(Content, Info.class);
Info i = (Info)o;
String d = i.getData().get(0).getLg_portrait();
portrait.setBackgroundDrawable(createPortrait(d));
}
}
and portrait is an ImageView . i don't know what to do .
You need to download the image in Async task as well. Honeycomb simply does not let you run lengthy HTTP operation blocking the UI thread (reading from stream makes HTTP call and waits for the image to be downloaded). You should return some placeholder immediately, trigger AsyncTask and replace the image after it is already downloaded.
Hint "post execute" is run in UI thread....