I have listview at which I am trying to implement an async task that loads the image into the view inside the getView method of my adapter. I have succeeded in creating this however my problem is that since in the listview and the adapter the view gets recycled, there is a short period of time when the user scrolls the listview that the imageView located in the layout shows the image of the view at a previous position. It then shows the correct image. I have tried setting the imageView bitmap to null inside the getView method before the async task is called but it still behaves the same. How do I load an image into a view using an async task without having the previous image shown before the image is finished loading?
hey follow few step to download image from server and show in your list view
Step 1. make this class in your project
OnImageDownloaded.java
public class OnImageDownloaded {
public OnImageDownloaded() {
try {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
File file = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + File.separator + "your_Dir_name");
if (file.mkdirs()) {
}
} else {
Log.e("testing", "External Directory is not mounted");
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void downloadTheImages(ArrayList<String> imageUrls) {
try {
new downloadingTheImages(imageUrls).execute();
} catch (Exception e) {
e.printStackTrace();
}
}
class downloadingTheImages extends AsyncTask<Void, Void, Void> {
ArrayList<String> imageUrls;
public downloadingTheImages(ArrayList<String> imageUrls) {
this.imageUrls = imageUrls;
}
#Override
protected Void doInBackground(Void... params) {
try {
for (int i = 0; i < imageUrls.size(); i++) {
if (imageUrls.get(i).equals("0")) {
} else
downloadTheImageIfRequired(imageUrls.get(i));
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
public void downloadTheImageIfRequired(String imageName) {
try {
String dirPath = Environment.getExternalStorageDirectory()
.getAbsolutePath()
+ File.separator
+ "your_Dir_name"
+ File.separator;
String CompleteFilePath = dirPath + imageName;
File f = new File(CompleteFilePath);
if (f.exists()) {
} else {
URL url = new URL(
"http image URL ::"
+ imageName);
URLConnection conexion = url.openConnection();
conexion.connect();
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(CompleteFilePath);
byte data[] = new byte[1024];
int count;
while ((count = input.read(data)) != -1) {
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Step 2.
Check out how you get that image
private class getImage extends AsyncTask<Void, Void, String> {
Dialog dialog;
String url;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(Void... params) {
url = getResources().getString(R.string.baseurl) + "getNews";
JSONParser jParser = new JSONParser();
String json = jParser.getJSONFromUrl(url);
try {
JSONObject jobject = new JSONObject(json);
Log.e("testing", "url: " + url + " " + json);
int success = jobject.getInt("success");
Log.e("testing", "json length" + jobject.length());
for (int i = 0; i < jobject.length() - 1; i++) {
JSONObject jobj = jobject
.getJSONObject(Integer.toString(i));
if (success == 1) {
HashMap<String, String> hm = new HashMap<String, String>();
ArrayList<String> tempAl1 = new ArrayList<String>();
tempAl1.add(jobj.getString("image"));
if (tempAl1.size() > 0) {
new OnImageDownloaded().downloadTheImages(tempAl1);
}
Log.e("test", "image" + jobj.getString("image"));
hm.put(image, jobj.getString("image"));
aldata.add(hm);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (dialog != null)
if (dialog.isShowing())
dialog.dismiss();
Custom_Adapter adapter = new Custom_Adapter (
(Activity) context, aldata);
lv.setAdapter(adapter);
}
}
Step 3.
Show that image in your adapter like this
call these methods in your getview in adaper
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
view = null;
if (view == null) {
LayoutInflater inflator = context.getLayoutInflater();
view = inflator.inflate(R.layout.news_view, null);
final ViewHolder viewHolder = new ViewHolder();
initAll(view, viewHolder);
view.setTag(viewHolder);
}
ViewHolder holder = (ViewHolder) view.getTag();
fillAll(holder, position);
return view;
}
public void fillAll(final ViewHolder holder, final int position) {
String dirPath = Environment.getExternalStorageDirectory()
.getAbsolutePath()
+ File.separator
+ "your_Dir_name"
+ File.separator;
String CompleteFilePath = dirPath + allData.get(position).get("image");
File f = new File(CompleteFilePath);
if (f.exists()) {
Log.e("testingTag", "if part");
holder.ivimage.setVisibility(View.VISIBLE);
catchOutOfMemory(holder.ivimage, CompleteFilePath);
} else {
Log.e("testingTag", "else part");
holder.ivimage.setVisibility(View.GONE);
}
Log.e("test", "image" + allData.get(position).get("image"));
}
void catchOutOfMemory(ImageView iv, String path) {
try {
iv.setImageURI(Uri.parse(path));
} catch (OutOfMemoryError e) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
Bitmap preview_bitmap = BitmapFactory.decodeFile(path, options);
iv.setImageBitmap(preview_bitmap);
}
}
thats all thanks
I had the same problem, then I started using Square's Picasso , it's very simple and handles imageview recycling perfectly!
In your adapter, you need to use a ViewHolder (to recycle views effectively) and set a tag (on the view) to bind the view to the correct image. You already know the position in the getView(...) callback.
Related
I need some help, I am developing an app with php and android. I'm using the recycler view, but I'm having problems because my list has 3 items and is showing only one, could you help me? I will add my adapter and my main.
AdapterLocalPersonalizado
public class AdapterLocalPersonalizado extends RecyclerView.Adapter<AdapterLocalPersonalizado.MeuViewHolder> {
Context ctx;
List<Local> listaLocal;
connection con = new connection();
public AdapterLocalPersonalizado(List<Local> locais,Context ctx1) {
this.ctx = ctx1;
this.listaLocal = locais;
}
public class MeuViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
TextView nome,categoria,endereco,valor;
#SuppressLint("WrongViewCast")
public MeuViewHolder(#NonNull View view) {
super(view);
nome = (TextView) view.findViewById(R.id.namec);
categoria = (TextView) view.findViewById(R.id.categoria);
valor = (TextView) view.findViewById(R.id.valor);
endereco = (TextView) view.findViewById(R.id.ende);
view.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int position = getAdapterPosition();
Local objSelecionado = listaLocal.get(position);
if(position != RecyclerView.NO_POSITION){
Intent intent = new Intent(ctx.getApplicationContext(), tela_lista_local.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Bundle bundle = new Bundle();
bundle.putInt("ID",objSelecionado.getId());
ctx.startActivity(intent);
}
}
}
#NonNull
#Override
public MeuViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
Local local = listaLocal.get(i);
Context context = viewGroup.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View linhaView = inflater.inflate(R.layout.activity_tela_lista_local_personalizada, viewGroup, false);
MeuViewHolder viewHolder = new MeuViewHolder(linhaView);
return viewHolder;
}
#Override
public void onBindViewHolder(#NonNull AdapterLocalPersonalizado.MeuViewHolder meuViewHolder, int i) {
Local local = listaLocal.get(i);
TextView nome = meuViewHolder.nome;
nome.setText(local.getNome());
}
#Override
public int getItemCount() {
return listaLocal.size();
}
}
tela_lista_local (main)
public class tela_lista_local extends AppCompatActivity {
AdapterLocalPersonalizado adapterLocalPersonalizado;
List<Local> localList;
Local local;
String endereco,categoria,token;
connection con = new connection();
ListarLocalAsyncTask listarLocaisAsyncTask;
RecyclerView listView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tela_lista_local);
token = "tcc";
Intent it = getIntent();
categoria = it.getStringExtra("categoria");
endereco = it.getStringExtra("endereco");
listView = findViewById(R.id.recyclerViewLocal);
listarLocaisAsyncTask = new ListarLocalAsyncTask();
listarLocaisAsyncTask.execute();
}
public class ListarLocalAsyncTask extends AsyncTask<String, String, String> {
String api_token, query;
HttpURLConnection conn;
URL url = null;
Uri.Builder builder;
final String URL_WEB_SERVICES = "http://192.168.0.110/Controller/APIListarLocal.php";
final int READ_TIMEOUT = 10000; // MILISSEGUNDOS
final int CONNECTION_TIMEOUT = 30000;
int response_code;
public ListarLocalAsyncTask( ){
this.builder = new Uri.Builder();
builder.appendQueryParameter("api_categoria", categoria);
}
#Override
protected void onPreExecute() {
Log.i("APIListar", "onPreExecute()");
}
#Override
protected String doInBackground(String... strings) {
Log.i("APIListar", "doInBackground()");
// Gerar o conteúdo para a URL
try {
url = new URL(URL_WEB_SERVICES);
} catch (MalformedURLException e) {
Log.i("APIListar", "MalformedURLException --> " + e.getMessage());
} catch (Exception e) {
Log.i("APIListar", "doInBackground() --> " + e.getMessage());
}
// Gerar uma requisição HTTP - POST - Result será um ArrayJson
// conn
try {
conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(READ_TIMEOUT);
conn.setConnectTimeout(CONNECTION_TIMEOUT);
conn.setRequestMethod("POST");
conn.setRequestProperty("charset", "utf-8");
conn.setDoInput(true);
conn.setDoOutput(true);
conn.connect();
} catch (Exception e) {
Log.i("APIListar", "HttpURLConnection --> " + e.getMessage());
}
// Adicionar o TOKEN e/ou outros parâmetros como por exemplo
// um objeto a ser incluido, deletado ou alterado.
// CRUD completo
try {
query = builder.build().getEncodedQuery();
OutputStream stream = conn.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(stream, "utf-8"));
writer.write(query);
writer.flush();
writer.close();
stream.close();
conn.connect();
} catch (Exception e) {
Log.i("APIListar", "BufferedWriter --> " + e.getMessage());
}
// receber o response - arrayJson
// http - código do response | 200 | 404 | 503
try {
response_code = conn.getResponseCode();
if (response_code == HttpURLConnection.HTTP_OK) {
InputStream input = conn.getInputStream();
BufferedReader reader = new BufferedReader(
new InputStreamReader(input)
);
StringBuilder result = new StringBuilder();
String linha = null;
while ((linha = reader.readLine()) != null) {
result.append(linha);
}
return result.toString();
} else {
return "HTTP ERRO: " + response_code;
}
} catch (Exception e) {
Log.i("APIListar", "StringBuilder --> " + e.getMessage());
return "Exception Erro: " + e.getMessage();
} finally {
conn.disconnect();
}
}
#Override
protected void onPostExecute(String result) {
Log.i("APIListar", "onPostExecute()--> Result: " + result);
try {
Local local;
JSONArray jsonArray = new JSONArray(result);
localList = new ArrayList<>();
if (jsonArray.length() != 0) {
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
local = new Local(jsonObject.getInt("id"),
jsonObject.getString("nome"),
jsonObject.getString("endereco"),
jsonObject.getString("categoria"),
jsonObject.getString("valor"));
localList.add(local);
Log.i("APIListar", "Estado: -> " + local.getId() + " - " +local.getNome());
}
Toast.makeText(tela_lista_local.this, localList.size() + " local Listados no LogCat", Toast.LENGTH_LONG)
.show();
initial();
}
} catch (Exception e) {
Log.i("APIListar", "onPostExecute()--> " + e.getMessage());
}
}
public void initial(){
adapterLocalPersonalizado = new AdapterLocalPersonalizado(localList, getApplicationContext());
listView.setAdapter(adapterLocalPersonalizado);
listView.setLayoutManager(new LinearLayoutManager(tela_lista_local.this));
}
}
}
It just returns one item but my bank has 3. There are no problems with my API because in debug mode I can see the three items, the problem is when interacting with the list.
Thanks
I guess each item of your recycle view is taking the entire screen and you are only able to see only one item. As #Mike M suggested you can try to scroll and see other item are showing up or not.
If so then make sure your recycle view layout item are not android:layout_width="match_parent" android:layout_height="match_parent".
If you want specific reason, you must post activity_tela_lista_local_personalizada layout.
Happy Coding !
My application gets image names from JSON. and I concatenated that name to another url to download image. I can download all images but all the images that I download are the same. example, my images name (1,2,3,4,5,6,7) but when I download, I can get it all but all are (1,1,1,1,1,1,1).
DownloadImageTask I had log String name and reviewImageLink. The result was fine. It show different name and url. BUT
DownloadFullImageTask on onPostExcecute I had also log String name, but it show the same name(1,1,1,1,1,1,1).
How can I download all my images and do not the same ?
JSON
{"pictures": [
{
"picture_url": "2de19d49ecc640e94b1a306944e161ef.png"
},
{
"picture_url": "bee57cbb42c364592e7472b442c58868.jpg"
},
{
"picture_url": "b718041660189162080ff86b09370ec8.jpg"
},
{
"picture_url": "7022dec80bb604bcbba51d28ce8bc31c.jpg"
},
{
"picture_url": "0be79b2cd531adf02487e8d54f736c0f.jpg"
},
{
"picture_url": "2101134bcfc1356df1ff187a8f9510f8.jpg"
},
{
"picture_url": "2de62e026b3378bbbdfe687cd43d5b0e.jpg"
}]}
AsyncTask Download image and json
public class DownloadImageTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... params) {
placeList = new ArrayList<HashMap<String, String>>();
JSONParser jParser = new JSONParser();
JSONObject jsonO = jParser.getJSONUrl(url);
// for " piture " Object in json
pictures = jsonO.getJSONArray("pictures");
for (int i = 0; i < pictures.length(); i++) {
JSONObject jObj = pictures.getJSONObject(i);
int cafe_id = jObj.getInt(TAG_CAFE_ID);
String picture_url = jObj.getString(TAG_PICTURE_URL);
// Table Picture
Model_Insert model_Insert = new Model_Insert();
model_Insert.setCafe_Id(cafe_id);
model_Insert.setPitureUrl(picture_url);
model_Insert = dataSource.createTablePicture(model_Insert);
Log.i("pic", " Picture " + model_Insert.getPitureurl());
HashMap<String, String> map = new HashMap<String, String>();
map.put(TAG_PICTURE_URL, picture_url);
placeList.add(map);
// Execute DownloadFullImageTask
reviewImageLink = "http://xxx.xxx/xxx/place_pictures/"+picture_url;
URL reviewImageURL;
Log.i("url", reviewImageLink);
String name = reviewImageLink.substring(reviewImageLink.lastIndexOf("/") + 1);
try {
reviewImageURL = new URL(reviewImageLink);
if (!hasExternalStoragePublicPicture(name)) {
isImage = false;
new DownloadFullImageTask().execute(reviewImageURL);
Log.v("log_tag", "if");
isImage = true;
File sdImageMainDirectory = new File(Environment.getExternalStorageDirectory(),getResources()
.getString(R.string.directory));
sdImageMainDirectory.mkdirs();
File file = new File(sdImageMainDirectory, name);
Log.v("log_tag", "Directory created");
}
} catch (MalformedURLException e) {
Log.v(TAG, e.toString());
}
}
} catch (JSONException e) {
// TODO: handle exception
}
return null;
}
protected void onPostExecute(Void unused) {
ShowAllContent(); // When Finish Show Content
}
}
AsyncTask execute url
public class DownloadFullImageTask extends AsyncTask<URL, Integer, Bitmap> {
protected Bitmap doInBackground(URL... paths) {
URL url;
try {
url = paths[0];
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
int length = connection.getContentLength();
InputStream is = (InputStream) url.getContent();
byte[] imageData = new byte[length];
int buffersize = (int) Math.ceil(length / (double) 100);
int downloaded = 0;
int read;
while (downloaded < length) {
if (length < buffersize) {
read = is.read(imageData, downloaded, length);
} else if ((length - downloaded) <= buffersize) {
read = is.read(imageData, downloaded, length - downloaded);
} else {
read = is.read(imageData, downloaded, buffersize);
}
downloaded += read;
publishProgress((downloaded * 100) / length);
}
Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0,
length);
if (bitmap != null) {
Log.i(TAG, "Bitmap created");
} else {
Log.i(TAG, "Bitmap not created");
}
is.close();
return bitmap;
} catch (MalformedURLException e) {
Log.e(TAG, "Malformed exception: " + e.toString());
} catch (IOException e) {
Log.e(TAG, "IOException: " + e.toString());
} catch (Exception e) {
Log.e(TAG, "Exception: " + e.toString());
}
return null;
}
protected void onPostExecute(Bitmap result) {
String name = reviewImageLink.substring(reviewImageLink.lastIndexOf("/") + 1);
if (result != null) {
hasExternalStoragePublicPicture(name);
saveToSDCard(result, name);
isImage = true;
} else {
isImage = false;
}
}
}
In onPostExecute of your DownloadFullImageTask you use the public field: reviewImageLink. But this field is changed by your other task. To fix this I'd recommend you put an inner variable in DownloadFullImageTask where you save paths[0] from doInBackground and use this instead.
For better performance by multithread loading, memory cache or external cache.
I suggest you take a look at this library
https://github.com/nostra13/Android-Universal-Image-Loader
It is powerful!
Refer my question on IllegalStateException in AsyncTask.
I am invoked the following AsyncTask from onPostExecute() of this task(Referred in this link).
public class SaveImageAsync extends AsyncTask<Context, Integer, String> {
private Bitmap bitmap = null;
private ArrayList<String> imageUrls = null;
private ArrayList<ImageView> imageViews = null;
int index = 0;
public SaveImageAsync(ArrayList<ImageView> imageViews,
ArrayList<String> imageUrls) {
this.imageUrls = imageUrls;
this.imageViews = imageViews;
}
#Override
protected String doInBackground(Context... params) {
boolean bRC;
String imageName, imageLocalPath, imageURL;
try {
for (int i = 0; i < imageUrls.size(); i++) {
imageURL = imageUrls.get(i);
String[] strSplittedImagePath = imageURL
.split("/");
if ((strSplittedImagePath != null)
&& (strSplittedImagePath.length >= 1)) {
imageName = strSplittedImagePath[(strSplittedImagePath.length - 1)];
} else {
imageName = imageURL;
}
imageLocalPath = path + imageName;
bRC = doesFileExists(imageLocalPath);
if (bRC == false) {
getImageFromServer(CommonSettings.mSTstrBaseURL
+ imageURL, imageLocalPath);
}
try {
bitmap = BitmapFactory
.decodeFile(imageLocalPath);
} catch (Exception e) {
}
if (bitmap == null) {
try {
new File(imageLocalPath).delete();
} catch (Exception e1) {
}
getImageFromServer(CommonSettings.mSTstrBaseURL
+ imageURL, imageLocalPath);
bitmap = BitmapFactory
.decodeFile(imageLocalPath);
}
Thread.sleep(300);
publishProgress();
}
} catch (InterruptedException e) {
e.printStackTrace();
Log.w(LOG_TAG,
"Got InterruptedException inside AsyncTask SaveImageAsync : "
+ e);
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
ImageView imageView = imageViews.get(index);
while (imageView == null) {
index = index + 1;
imageView = imageViews.get(index);
}
imageView.setScaleType(ScaleType.FIT_XY);
imageView.setImageBitmap(bitmap);
index = index + 1;
//bitmap.recycle();
}
public boolean getImageFromServer(String url, String localPath) {
boolean bReturn = false;
File objNewFile;
try {
objNewFile = new File(localPath);
if (!objNewFile.exists()) {
objNewFile.createNewFile();
}
BufferedInputStream objBufferedInput = new BufferedInputStream(
new java.net.URL(url).openStream());
FileOutputStream objFileOutput = new FileOutputStream(objNewFile);
BufferedOutputStream objBufferOutput = new BufferedOutputStream(
objFileOutput, 1024);
byte[] data = new byte[1024];
int x = 0;
while ((x = objBufferedInput.read(data, 0, 1024)) >= 0) {
objBufferOutput.write(data, 0, x);
}
objFileOutput.flush();
objBufferOutput.flush();
objFileOutput.close();
objBufferOutput.close();
objBufferedInput.close();
bReturn = true;
} catch (IOException e) {
} catch (Exception ex) {
}
return bReturn;
}
}
When pressing back button and loading this task it throws OutOfMemoryException at decodeFile(). Why this happen and how to fix this?
Thanks
i am making an app in which i have to get response from xml and i get image urls .Now i want to put images from urls into gridview but i dnt know how to extract images from urls and put in gridview.Any help will be appreciated.My code is as follows:
public class GalleryNewActivity extends Activity {
private ProgressDialog dialog;
GridView ga;
Element e;
Node elem;
public List<Drawable> pictures;
ImageView imageView;
static final String PREFS_NAME = "MyPrefs";
static final String USER_KEY = "user";
static final String Name = "name";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if(isNetworkconn()){
new GetSPCAsyncTask().execute("");
}else{
showDialogOnNoInternet();
}
ga = (GridView)findViewById(R.id.Gallery01);
ga.setAdapter(new ImageAdapter(this));
imageView = (ImageView)findViewById(R.id.ImageView01);
}
public class ImageAdapter extends BaseAdapter {
private Context mContext;
public ImageAdapter(Context c) {
mContext = c;
}
public int getCount() {
return pictures.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
View v;
if (convertView == null) { // if it's not recycled, initialize some
// attributes
LayoutInflater li = getLayoutInflater();
v = li.inflate(R.layout.galleryitem, null);
imageView = (ImageView)v.findViewById(R.id.thumbImage);
imageView.setLayoutParams(new GridView.LayoutParams(200, 250));
// imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(2, 5, 2, 5);
} else {
imageView = (ImageView) convertView;
}
imageView.setImageDrawable(pictures.get(position));
imageView.setTag(pics[position]);
return imageView;
}
private class GetPicsToNextPage extends AsyncTask<String, String, String>{
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
dialog = ProgressDialog.show(GalleryNewActivity.this, "Please wait", "Loading...");
}
#Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
String str = null;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return str;
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
dialog.dismiss();
Intent intent = new Intent(getApplicationContext(), Flip3d.class);
startActivity(intent);
}
}
private boolean isNetworkconn(){
ConnectivityManager conMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (conMgr.getActiveNetworkInfo() != null && conMgr.getActiveNetworkInfo().isAvailable() && conMgr.getActiveNetworkInfo().isConnected()) {
return true;
}else{
return false;
}
}
private void showDialogOnNoInternet(){
AlertDialog.Builder alt_bld = new AlertDialog.Builder(GalleryNewActivity.this);
alt_bld.setTitle("Error.");
alt_bld.setMessage("Your phone is not connected to internet.");
alt_bld.setCancelable(false);
alt_bld.setNeutralButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
dialog.dismiss();
}
});
alt_bld.show();
}
//loader for dynamic starts
private class GetSPCAsyncTask extends AsyncTask<String, String, String>{
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
dialog = ProgressDialog.show(GalleryNewActivity.this, "Please wait", "Loading...");
}
#Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
ArrayList<HashMap<String, String>> mylist = new ArrayList<HashMap<String, String>>();
String xml = XMLfunctions.getXML();
Document doc = XMLfunctions.XMLfromString(xml);
NodeList nodes = doc.getElementsByTagName("Image");
for (int i = 0; i < nodes.getLength(); i++) {
HashMap<String, String> map = new HashMap<String, String>();
e = (Element)nodes.item(i);
//map.put("Image", XMLfunctions.getValue(e, "Image"));
map.put("ImagePath", "Naam:" + XMLfunctions.getValue(e, "ImagePath"));
map.put("ImageHeadline", "Headline: " + XMLfunctions.getValue(e, "ImageHeadline"));
System.out.println(map.put("ImageHeadline", "Headline: " + XMLfunctions.getValue(e, "ImageHeadline")));
map.put("ImageDesc", "Desc: " + XMLfunctions.getValue(e, "ImageDesc"));
System.out.println(map.put("ImageDesc", "Desc: " + XMLfunctions.getValue(e, "ImageDesc")));
mylist.add(map);
Drawable d=LoadImageFromWebOperations();
pictures.add(d);
}
return xml;}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
dialog.dismiss();
}
private Drawable LoadImageFromWebOperations()
{
String path=XMLfunctions.getValue(e, "ImagePath");
try{
InputStream is = (InputStream) new URL(path).getContent();
Drawable d = Drawable.createFromStream(is, "src name");
Log.w("CREADO","CREADO");
return d;
}catch (Exception e) {
System.out.println("Exc="+e);
return null;
}
}
}
}
I would suggest you to check below solutions for loading images from URL:
Android - Universal Image loader by Nostra
Lazy load of images in ListView
Result you can get if you use Universal image loader:
call this function with url you will get Drawable , and then store this drawables into custom class and then place in grid view.
call function like this
ImageOperations(this, imageurl)
public Object fetch(String address) throws MalformedURLException, IOException {
URL url = new URL(address);
Object content = url.getContent();
return content;
}
private Drawable ImageOperations(Context ctx, String url) {
try {
InputStream is = (InputStream) this.fetch(url);
Drawable d = Drawable.createFromStream(is, "src");
return d;
} catch (MalformedURLException e) {
return null;
} catch (IOException e) {
return null;
}
}
https://github.com/koush/UrlImageViewHelper
UrlImageViewHelper will fill an ImageView with an image that is found at a URL.
The sample will do a Google Image Search and load/show the results asynchronously.
UrlImageViewHelper will automatically download, save, and cache all the image urls the BitmapDrawables. Duplicate urls will not be loaded into memory twice. Bitmap memory is managed by using a weak reference hash table, so as soon as the image is no longer used by you, it will be garbage collected automatically.
else use this,
public static Bitmap loadBitmap(String url) {
Bitmap bitmap = null;
InputStream in = null;
BufferedOutputStream out = null;
try {
in = new BufferedInputStream(new URL(url).openStream(), IO_BUFFER_SIZE);
final ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
out = new BufferedOutputStream(dataStream, IO_BUFFER_SIZE);
copy(in, out);
out.flush();
final byte[] data = dataStream.toByteArray();
BitmapFactory.Options options = new BitmapFactory.Options();
//options.inSampleSize = 1;
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length,options);
} catch (IOException e) {
Log.e(TAG, "Could not load Bitmap from: " + url);
} finally {
closeStream(in);
closeStream(out);
}
return bitmap;
}
I'm working on a small project on Android and have a serious problem with implementing some multi-threading into my solution. Below is a class that is an activity inside the tab of the main interface, which displays a custom list with pictures and data downloaded from YouTube API.
The class works fine, but it completely blocks the UI when, first the data, and then the images are being loaded from the Internet. I know I need to implement some threading and I have tried various things, but I'm not quite sure which parts of the code I have to launch as separate threads. There's also a chance there is something fundamentally wrong with my code structure.
Ideally I'd like to have the UI shown to the user immediately after the application is launched with a progress dialog on top of it, while the textual data is being loaded from YouTube. Then the user should get control of the UI, while images are being loaded in another thread in the background.
public class VodsActivity extends ListActivity {
private LayoutInflater mInflater;
private Vector<RowData> data;
RowData rd;
//private Handler mHandler;
private ProgressDialog dialog;
//Generic names of custom ListView elements
private static String[] title;
private Vector<String> detail;
private Vector<String> status;
private Vector<String> imgurl;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.custom_list);
mInflater = (LayoutInflater) getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
title = getResources().getStringArray(R.array.yt_channels);
detail = new Vector<String>();
status = new Vector<String>();
imgurl = new Vector<String>();
//mHandler = new Handler();
//dialog = ProgressDialog.show(VodsActivity.this, "","Loading. Please wait...", true);
loadData();
displayData();
//dialog.dismiss();
}
private void loadData() {
String[] values = {"error", "error", "http://www.ephotobay.com/thumb/message-error.jpg" };
for (int i = 0; i < title.length; i++) {
values = getData(title[i]);
values[1] = getTodaysUploads(title[i]);
detail.add(i, values[0]);
status.add(i, values[1]);
imgurl.add(i, values[2]);
}
}
/*** This function gets total number of uploads and thumbnail url for the user from a single feed ***/
private String[] getData (String username) {
String[] result = new String[3];
String ytFeedUrl = "http://gdata.youtube.com/feeds/api/users/" + username + "?v=2";
InputStream inStream = null;
try {
inStream = OpenHttpConnection(ytFeedUrl);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document dom = db.parse(inStream);
Element docEle = dom.getDocumentElement();
inStream.close();
NodeList nl = docEle.getElementsByTagName("entry");
if (nl != null && nl.getLength() > 0) {
for (int i = 0; i < nl.getLength(); i++) {
Element entry = (Element) nl.item(i);
Element thumbnail = (Element) entry.getElementsByTagName("media:thumbnail").item(0);
String thumbUrl = thumbnail.getAttribute("url");
Element feedLink = (Element) entry.getElementsByTagName("gd:feedLink").item(5);
String uploads = feedLink.getAttribute("countHint");
result[0] = uploads + " videos";
result[1] = ""; //not used here
result[2] = thumbUrl;
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
finally {
//
}
return result;
}
/*** This function gets a number of today's uploads of the user ***/
private String getTodaysUploads (String username) {
String result = null;
String ytFeedUrl = "http://gdata.youtube.com/feeds/api/videos?author=" + username + "&time=today&v=2";
InputStream inStream = null;
try {
inStream = OpenHttpConnection(ytFeedUrl);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document dom = db.parse(inStream);
Element docEle = dom.getDocumentElement();
inStream.close();
NodeList nl = docEle.getElementsByTagName("feed");
if (nl != null && nl.getLength() > 0) {
for (int i = 0; i < nl.getLength(); i++) {
Element entry = (Element) nl.item(i);
Element title = (Element)entry.getElementsByTagName("openSearch:totalResults").item(0);
result = title.getFirstChild().getNodeValue();
result += " new today";
}
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
finally {
//
}
return result;
}
private void displayData () {
//Use vector instead of ArrayList for safe threading
data = new Vector<RowData>();
for (int i = 0; i < title.length; i++) { //Loop needs to be changed based on results
try {
rd = new RowData(i, title[i], detail.get(i), status.get(i));
} catch (Exception e) {
e.printStackTrace();
}
data.add(rd);
}
CustomAdapter adapter = new CustomAdapter (this, R.layout.custom_list_item, R.id.title, data);
setListAdapter(adapter);
getListView().setTextFilterEnabled(true);
}
private InputStream OpenHttpConnection(String strUrl) throws IOException {
InputStream inStream = null;
URL url = new URL(strUrl);
URLConnection conn = url.openConnection();
try {
HttpURLConnection httpConn = (HttpURLConnection) conn;
httpConn.setRequestMethod("GET");
httpConn.connect();
if (httpConn.getResponseCode() == HttpURLConnection.HTTP_OK) {
inStream = httpConn.getInputStream();
}
} catch (Exception ex) {
ex.printStackTrace();
}
return inStream;
}
//This is temporary
public void onListItemClick(ListView parent, View v, int position, long id) {
CustomAdapter adapter = (CustomAdapter) parent.getAdapter();
RowData row = adapter.getItem(position);
Builder builder = new AlertDialog.Builder(this);
builder.setTitle(row.mTitle);
builder.setMessage(row.mDetail + " -> " + position );
builder.setPositiveButton("ok", null);
builder.show();
}
//Private class RowData - holds details of CustomAdapter item
private class RowData {
protected int mId;
protected String mTitle;
protected String mDetail;
protected String mStatus;
RowData (int id, String title, String detail, String status) {
mId = id;
mTitle = title;
mDetail = detail;
mStatus = status;
}
#Override
public String toString() {
return mId + " " + mTitle + " " + mDetail + " " + mStatus;
}
}
//Custom Adapter for the custom list, overrides onView() method
private class CustomAdapter extends ArrayAdapter<RowData> {
public CustomAdapter(Context context, int resource, int textViewResourceId, List<RowData> objects) {
super (context, resource, textViewResourceId, objects);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
TextView title = null;
TextView detail = null;
TextView status = null;
ImageView image = null;
RowData rowData = getItem(position);
//Reuse existing row views
if(convertView == null) {
convertView = mInflater.inflate(R.layout.custom_list_item, null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}
holder = (ViewHolder) convertView.getTag();
title = holder.getTitle();
title.setText (rowData.mTitle);
detail = holder.getDetail();
detail.setText(rowData.mDetail);
status = holder.getStatus();
status.setText(rowData.mStatus);
//add if statements here for colors
image = holder.getImage();
/**** This loads the pictures ****/
BitmapFactory.Options bmOptions;
bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 1;
String imageUrl = imgurl.get(rowData.mId);
Bitmap bm = LoadImage(imageUrl, bmOptions);
image.setImageBitmap(bm);
return convertView;
}
//Load image from the URL
private Bitmap LoadImage(String url, BitmapFactory.Options options) {
Bitmap bitmap = null;
InputStream inStream = null;
try {
inStream = OpenHttpConnection(url);
bitmap = BitmapFactory.decodeStream(inStream, null, options);
inStream.close();
} catch (IOException ioex) {
ioex.printStackTrace();
}
return bitmap;
}
}
/*** Wrapper for row data ***/
private class ViewHolder {
private View mRow;
private TextView title = null;
private TextView detail = null;
private TextView status = null;
private ImageView image = null;
public ViewHolder (View row) {
mRow = row;
}
public TextView getTitle() {
if (title == null) {
title = (TextView) mRow.findViewById(R.id.title);
}
return title;
}
public TextView getDetail() {
if (detail == null) {
detail = (TextView) mRow.findViewById(R.id.detail);
}
return detail;
}
public TextView getStatus() {
if (status == null) {
status = (TextView) mRow.findViewById(R.id.status);
}
return status;
}
public ImageView getImage() {
if (image == null) {
image = (ImageView) mRow.findViewById(R.id.thumbnail);
}
return image;
}
}
}
Thanks a lot for any pointers.
Check out the AsyncTask. This will let you background your long-running processes while showing the UI.
Also, you can find good/official tutorial on Android threading here.
I ended up using standard java Thread to load the data from API in the background and created a separate class for loading images in separate threads as well. In case you're wondering it now looks like this, and seem to work fine.
Loading the data:
public void onCreate(...) {
//...
mHandler = new Handler();
dialog = ProgressDialog.show(VodsActivity.this, "","Loading. Please wait...", true);
getData.start();
}
private Thread getData = new Thread() {
public void run() {
try {
loadData();
mHandler.post(showData);
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
private Runnable showData = new Runnable() {
public void run() {
try {
displayData();
dialog.dismiss();
} catch (Exception ex) {
ex.printStackTrace();
}
}
};
Loading images (in CustomAdapter):
String imageUrl = imgurl.get(rowData.mId);
final ImageView image = holder.getImage();
//Reuse downloaded images or download new in separate thread
image.setTag(imageUrl);
Drawable cachedImage = imageLoader.loadDrawable(imageUrl, new ImageCallback() {
public void imageLoaded(Drawable imageDrawable, String imageUrl) {
ImageView imageViewByTag = (ImageView) image.findViewWithTag(imageUrl);
if (imageViewByTag != null) {
imageViewByTag.setImageDrawable(imageDrawable);
}
}
});
image.setImageDrawable(cachedImage);
ImageLoader class:
public class ImageLoader {
private HashMap<String, SoftReference<Drawable>> imageCache;
private static final String TAG = "ImageLoader";
public ImageLoader() {
imageCache = new HashMap<String, SoftReference<Drawable>>();
}
//Loads image from the cache if it exists or launches new thread to download it
public Drawable loadDrawable(final String imageUrl, final ImageCallback imageCallback) {
Log.d(TAG, "loadDrawable(" + imageUrl + ")");
if (imageCache.containsKey(imageUrl)) {
SoftReference<Drawable> softReference = imageCache.get(imageUrl);
Drawable drawable = softReference.get();
if (drawable != null) {
return drawable;
}
}
final Handler handler = new Handler() {
#Override
public void handleMessage(Message message) {
imageCallback.imageLoaded((Drawable) message.obj, imageUrl);
}
};
new Thread() {
#Override
public void run() {
Drawable drawable = loadImageFromUrl(imageUrl);
imageCache.put(imageUrl, new SoftReference<Drawable>(drawable));
Message message = handler.obtainMessage(0, drawable);
handler.sendMessage(message);
}
}.start();
return null;
}
//Downloads image from the url
public static Drawable loadImageFromUrl(String url) {
Log.d(TAG, "loadImageFromUrl(" + url + ")");
InputStream inputStream;
try {
inputStream = new URL(url).openStream();
} catch (IOException e) {
throw new RuntimeException(e);
}
return Drawable.createFromStream(inputStream, "src");
}
public interface ImageCallback {
public void imageLoaded(Drawable imageDrawable, String imageUrl);
}
}