Set source of ImageView in custom ListView after list bind - android

I have a ListView binded with custom adapter and its working fine :
private class Placeslist extends ArrayAdapter<ArrayList<String>> {
private ArrayList<ArrayList<String>> items;
public Placeslist(Context context, int textViewResourceId,
ArrayList<ArrayList<String>> items) {
super(context, textViewResourceId, items);
this.items = items;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.locationgpsrow, null);
}
ArrayList<String> o = items.get(position);
if (o != null) {
// Binding here
TextView tv1 = (TextView) v.findViewById(R.id.txt1);
tv1.setText(o.get(0));
ImageView imView = (ImageView) v.findViewById(R.id.imageView1);
//o.get(1) // Image url e.g. http://www.some-website/image.jpg
}
return v;
}
}
I have an image source url in one of my array elements and i need to download the image and set it to ImageView in the listview item custom layout. And, I have code for that too !!
ImageView imView = (ImageView) findViewById(R.id.imageView1);
HttpURLConnection conn = (HttpURLConnection) myFileUrl.openConnection();
conn.setDoInput(true);
conn.connect();
is = conn.getInputStream();
bmImg = BitmapFactory.decodeStream(is);
is.close();
imView.setImageBitmap(Bitmap.createScaledBitmap(bmImg, width,
height, true));
I can use it in my above getView() to set imageView source. But what i want is to let the list view bind to adapter without loading images(because it'll be heavy process). And then after listView is loaded then to initiate binding all the ImageViews in rows respectively. Is their a way to achieve this or any thing that can separate the image downloading process from listView binding ?

You have to use below lib to load image on run time :-
Universal loader lib
Picasso
Urlhelper

You can go for 3rd party libraries like universalimageloader and others for it.
Otherwise, if you want to handle it on your own, just create an asyncTask to download an image from url and set it to the imageView onPostExecute callBack. You can pass the parameters(ImageView img, String Url) to this AsyncTask's Constructor, download the image in DoinBackground() and finally set it to the img onPostExecute();
You can trigger this asyncTask from the getView() method from the Adapter, may be doing this on UI thread may be required.

I have used Picasso Image library which takes care of caching and downloading easily. Have a look here:
http://square.github.io/picasso/
Universal Image Loader also does this well, with a bit more options for configuration:
https://github.com/nostra13/Android-Universal-Image-Loader
You might want to look at using a library like this as it will save data, and not do as much network operations.

Use SmartImageView to load the url to images. http://loopj.com/android-smart-image-view/

Your need to read about Lazy Loading of listview where the images are loaded asynchronously. You can use any of the libraries available out there.
A good complete tutorial about listview and lazy loading :
http://www.androidhive.info/2012/02/android-custom-listview-with-image-and-text/

Related

ListView BaseAdapter is hanging

I am getting some odd behavior in my scroll-able listview. It is controlled by a BaseAdapter.
As I scroll up or down it will sometimes hang and then bounce back in the opposite direction. I have no idea why and do not know how to trouble shoot it.
My base adapter is below and it loads about 90 fragments with an image and a bunch of text.
public class PosterListAdapter extends BaseAdapter {
private final ArrayList<Poster> listItems;
private final LayoutInflater inflater;
public PosterListAdapter(ArrayList<Poster> listItems, LayoutInflater inflater) {
this.listItems = listItems;
this.categoryList = categoryItems;
this.inflater = inflater;
}
#Override
public int getCount() {
//Log.d("getCount", String.valueOf(this.listItems.size()));
return this.listItems.size();
}
#Override
public Poster getItem(int i) {
return this.listItems.get(i);
}
#Override
public long getItemId(int i) {
return 0;
}
#Override
public View getView(int i, View convertView, ViewGroup viewGroup) {
MyViewHolder mViewHolder;
SparseArray<String> categoryMap = db.getCategoryMap();
if (convertView == null) {
convertView = inflater.inflate(R.layout.catalog_list_fragment, viewGroup, false);
mViewHolder = new MyViewHolder(convertView);
convertView.setTag(mViewHolder);
} else {
mViewHolder = (MyViewHolder) convertView.getTag();
}
//LayoutParams params = (LayoutParams) imageView.getLayoutParams();
Poster item = this.listItems.get(i);
String filename = item.getPosterFilename();
mViewHolder.posterAuthor.setText("Author: "+item.getPresenterFname()+' '+item.getPresenterLname());
mViewHolder.posterAltAuthors.setText("Supporting Authors: "+item.getPosterAuthors());
mViewHolder.posterTitle.setText(item.getPosterTitle());
mViewHolder.posterSynopsis.setText(item.getPosterSynopsis());
mViewHolder.posterNumber.setText("Poster: "+String.valueOf(item.getPosterNumber()));
mViewHolder.posterPresentation.setText("Live Presentation: "+item.getSessionDate()+" at "+item.getSessionTime()+"\nAt Station: "+item.getPosterStation());
String category = categoryMap.get(item.getCatID());
mViewHolder.posterCategory.setText("Category: "+category);
File imgFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath(), "/"+filename+"/"+filename+".png");
//Here I thought maybe the resizing of the image or even the image itself
// was causing the hang up so I tried the list without it and it is still
// hanging.
//mViewHolder.imageView.setImageURI(Uri.fromFile(new File(imgFile.toString())));
if (imgFile.exists()){
/*Bitmap bmp = BitmapFactory.decodeFile(imgFile.toString());
int newWidth = 500;
Bitmap sizedBMP = getResizedBitmap(bmp, newWidth);
mViewHolder.imageView.setImageBitmap(sizedBMP);*/
}
else{
//set no image available
}
return convertView;
}
private class MyViewHolder {
TextView posterTitle, posterAuthor, posterSynopsis, posterCategory, posterNumber, posterAltAuthors,posterPresentation;
ImageView imageView;
public MyViewHolder(View item) {
posterTitle = (TextView) item.findViewById(R.id.poster_title);
posterAuthor = (TextView) item.findViewById(R.id.poster_author);
posterAltAuthors = (TextView) item.findViewById(R.id.poster_altAuthors);
posterSynopsis = (TextView) item.findViewById(R.id.poster_synopsis);
posterCategory = (TextView) item.findViewById(R.id.poster_category);
posterNumber = (TextView) item.findViewById(R.id.poster_number);
posterPresentation = (TextView) item.findViewById(R.id.poster_presentation);
imageView = (ImageView) item.findViewById(R.id.poster_thumb);
}
}
}
I know that is a big chunk of code and it may be ugly.. If you could point me in the right direction as to how to trouble shoot it that would be helpful as well. I am using eclipse.
I bet if you comment out that line File imgFile = new File(... (and the code that depends on imgFile) that your list scrolling will improve.
That's still an I/O operation and since getView() runs in the UI thread, it may cause hiccups.
What you should do is: once you have the ImageView in getView(), you start an AsyncTask to open the file, decode it, and assign the bitmap to the ImageView.
Then you have to handle things like: the ImageView gets recycled, but the task isn't completed.
Read this article: Multithreading for Performance | Android Developers Blog. It's dealing with images from a remote server, but all the principles are still the same.
Also: does this line SparseArray<String> categoryMap = db.getCategoryMap(); do a database lookup? That could cause a hiccup as well.
TL;DR getView() needs to be fast; put slow operations in a non-UI thread.
Database related operations should done in separate thread. as it might take time to get data if number of records are greater.
and getView() method will be called more then one time. we can say it will be called in loop till size of your array list (getCount()).
Second thing: File operation is also should be done in separate thread.because IO task is also some times time consuming.
Solution:
SparseArray<String> categoryMap = db.getCategoryMap();
put this line out of getView() method as i cant see any list dependent parameter in this line. this should be done in either constructor or separate thread.
Run your database operations and File IO in separate thread like using AsyncTask
I agree with previous answer, looks like creating new File is the only heavy operation which hangs your app.
Try to use some image loading library, for example Glide. It will simplify your code, also you won't have to deal with background job. Library will do it all for you.
1.Import library, e.g. if you use gradle insert this into your build.gradle file:
repositories {
mavenCentral() // jcenter() works as well because it pulls from Maven Central
}
dependencies {
compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.android.support:support-v4:19.1.0'
}
2.In your adapter replace code related to loading picture with this:
Glide
.with(context)
.load(<full path to your local file>)
.into(mViewHolder.imageView);
3.And it is all. Glide will handle recycling and other things internally, also it is optimized for fast loading and smooth scrolling.
Image related processes really consumes so much memory on the UIThread of the app, you should be setting your image using asynchronous(background) approach. Or if its much of a hassle for you, there are tons of libraries available that will do this. I specifically recommend using Picasso for it is very dynamic, easy to use and is regularly updated. Loading an image would require one line of code:
Picasso.with(getApplicationContext()).load(<your image path or url or resource id>).into(YourImageView);
Picasso also have a variety of image options you can choose from.

ListView Lagging when Scrolling Up with Images

My ListView jumps/freezes while scrolling up ( Scrolling down has no problem ) when I add images in, this doesn't happen when my keyboard is up.
I don't own the DownloadImageWithURLTask class, I cannot remember where I got it from.
public class chatAdapter extends ArrayAdapter<chatModel> {
private Context context;
public String userName = null;
public ImageView hold = null;
private static class ViewHolder{
TextView userName;
TextView userMessage;
ImageView userImage;
}
public chatAdapter(Context c, List<chatModel> items){
super(c, 0, items);
this.context = c;
}
class DownloadImageWithURLTask extends AsyncTask<String, Void, Bitmap> {
ImageView bmImage;
public DownloadImageWithURLTask(ImageView bmImage) {
this.bmImage = bmImage;
}
protected Bitmap doInBackground(String... urls) {
String pathToFile = urls[0];
Bitmap bitmap = null;
try {
InputStream in = new java.net.URL(pathToFile).openStream();
bitmap = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return bitmap;
}
protected void onPostExecute(Bitmap result) {
bmImage.setImageBitmap(result);
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent){
final chatModel chatModel = getItem(position);
final ViewHolder viewHolder;
if (convertView == null){
viewHolder = new ViewHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.activity_chat_box, parent, false);
TextView userName = (TextView)convertView.findViewById(R.id.usern);
TextView userMessage = (TextView)convertView.findViewById(R.id.msg);
final ImageView userImage = (ImageView)convertView.findViewById(R.id.imageView8);
userName.setText(chatModel.userName);
userMessage.setText(chatModel.chatMessage);
final String userAvatarURL = "http://downtowndons.eu/Downtown/Avatar/" + chatModel.userName;
DownloadImageWithURLTask downloadTask = new DownloadImageWithURLTask(userImage);
downloadTask.execute(userAvatarURL);
} else {
viewHolder = (ViewHolder)convertView.getTag();
}
convertView.setAnimation(AnimationUtils.loadAnimation(context, R.anim.abc_slide_in_bottom));
return convertView;
}
}
If your using AsyncTask to load Image in imageView.While scrolling rapidly in listview you may had chance to get OutofMemory exception.In order to solve those type of exceptions you need to handle Memory cache mechanism for handling images.By default there are plenty of image loading libraries available in android.One of the easiest library is Universal Image Loader.
Use Universal image loader for downloading images asynchronously.
http://github.com/nostra13/Android-Universal-Image-Loader
The Library itself has a sample code to download image.you may refer it.. After downloading library add library with your project and insert the below code at necessary place
Write this code in adapter constructor
ImageLoader imageloader = ImageLoader.getInstance();
imageloader.init(ImageLoaderConfiguration.createDefault(context));
DisplayImageOptions options; = new DisplayImageOptions.Builder()
.showImageForEmptyUri(R.drawable.ic_empty)
.showImageOnFail(R.drawable.ic_error)
.resetViewBeforeLoading(true).cacheOnDisk(true)
.imageScaleType(ImageScaleType.EXACTLY)
.bitmapConfig(Bitmap.Config.RGB_565).considerExifParams(true)
.cacheInMemory(true)
.displayer(new FadeInBitmapDisplayer(300)).build();
Replace this code in getView instead of yours code.
if(convertView==null){
// ... other stuff
viewHolder.userName=(TextView)convertView.findViewById(R.id.usern);
viewHolder.userMessage=(TextView)convertView.findViewById(R.id.msg);
viewHolder.userImage= (ImageView)convertView.findViewById(R.id.imageView8);
}else{
viewHolder=(ViewHolder)convertView.getTag();
}
viewHolder.userName.setText(chatModel.userName);
viewHolder.userMessage.setText(chatModel.chatMessage);
final String userAvatarURL="http://downtowndons.eu/Downtown/Avatar/"+chatModel.userName;
imageloader.displayImage(userAvatarURL, viewHolder.userImage);
To fetch images from the net, try using one of these two libraries mentioned in this answer: https://stackoverflow.com/a/22862991/1018109
I'd strongly suggest following all answers and comments on this question: Lazy load of images in ListView
The ListView Freezes because it's trying to Re-Download the images again.
One on the best practices in this case is to cache image into memory using Android LruCache or Disk using DiskLruCache for efficiency..
Check this link out, it will help you a lot..
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html#disk-cache
Initially, your problem is fetching and loading images on scroll. Also you don't store earlier downloaded images in cache.
To solve your downloading images problem use any image caching library
Universal Image Loader
Lazy List Loader
Volley Image Loader
Glide
Picasso
Go with any of them and your problem will be solved! I have mentioned example of each library with listview. Check it out!
I'm relatively new to this, but I'm lost with your code. It doesn't look like you're actually doing anything with your viewholder pattern. Your viewholder should be a quick way of getting your two textviews and one imageview every time they get updated, which is what speeds up scrolling for listview. However, you created it but didn't actually do anything with it. So the pattern should be something like:
if(convertView==null){
// ... other stuff
viewHolder.userName=(TextView)convertView.findViewById(R.id.usern);
viewHolder.userMessage=(TextView)convertView.findViewById(R.id.msg);
viewHolder.userImage=(ImageView)convertView.findViewById(R.id.imageView8);
}else{
viewHolder=(ViewHolder)convertView.getTag();
}
viewHolder.userName.setText(chatModel.userName);
viewHolder.userMessage.setText(chatModel.chatMessage);
final String userAvatarURL="http://downtowndons.eu/Downtown/Avatar/"+chatModel.userName;
DownloadImageWithURLTask downloadTask=new DownloadImageWithURLTask(viewHolder.userImage);
downloadTask.execute(userAvatarURL);

ListView shows wrong and duplicates images

I have a ListView and 12 ImageViews in it.
Every ImageView has different image which is loading from url. Images are shuffled and sometimes duplicated either I scroll or not.
I tried 10 other ways to solve this problem but have not succeeded.
This is the code I download and show images:
private static class ViewHolder {
ImageView imageViewPhoto;
Bitmap photo;
boolean isDownloading;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
final ViewHolder viewHolder;
if (convertView == null) {
// ...classical view holder and other operations...
if (!viewHolder.isDownloading) {
viewHolder.isDownloading = true;
IImageDownload downloadInterface = new IImageDownload() {
#Override
public void onError(VolleyError error, String url) {
}
#Override
public void onDownloaded(Bitmap response, String url) {
viewHolder.photo = response;
notifyDataSetChanged();
}
};
imageDownloader.downloadImage(dataList.get(position).getPhotoPath(), true, downloadInterface);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
if (viewHolder.photo != null) {
viewHolder.imageViewPhoto.setImageBitmap(viewHolder.photo);
} else {
viewHolder.imageViewPhoto.setImageResource(R.drawable.gray_background);
}
}
Thanks in advance for any ideas!
Before:
imageDownloader.downloadImage(dataList.get(position).getPhotoPath(), true, downloadInterface);
Put:
viewHolder.photo.setImageBitmap(null);
This will reset the ImageView's bitmap, as it is being recycled and therefore keeping its image.
You should have something like this:
if (!viewHolder.isDownloading) {
// download the image in a worker thread
} else {
// cancel the current downloading and start a new one with the new url
}
Since ListView items are reusable. Your items are starting the image downloads, but when you start scrolling, those same items could still be downloading the images when they are already being reused. So when the worker thread has finished, the bitmaps are set in the wrong place and even worse, you never started the downloads for those reused items because the viewholder.isDownloading said it was already downloading an image.
A) You only initiate the download when the convertView is instantiated. You are recycling the rows so you may have a data set larger than the number of row Views that you actually use. This is not the right place to begin downloading an image. You want to do this per viewed position, not per View instantiated.
B) When you fire off a background task to download the image it may return later (after fetching) and replace a row with the wrong image as the row may now represent the wrong position (given row recycling).
Asynchronous image loading in a recycling ListView is slightly more complicated than it first seems. As the user scrolls through the list, you'll need to fire off downloads when a position is viewed, and cancel calls that are now redundant (as they are for a previously visible position).
You may wish to read more on view recycling in a ListView to get a better understanding of what is happening.
Also consider using an image downloading/caching library that handles these complexities such as Picasso.
Use UniversalImageLoader library to load images..
Try this
ImageLoader.getInstance().displayImage(url, holder.imgView, options);
to load images inside adapter..
Use DisplayImageOptions as follows inside constructor of adapter
options = new DisplayImageOptions.Builder()
.showImageOnLoading(android.R.color.transparent)
.showImageForEmptyUri(android.R.color.transparent)
.showImageOnFail(android.R.color.transparent)
.cacheInMemory(true)
.cacheOnDisk(true)
.considerExifParams(true)
.bitmapConfig(Bitmap.Config.RGB_565)
.build();
and add
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
inside onCreateView/onCreate of fragment/activity contaning the list

Load Bitmaps/images in ListView Adapter

I'm trying to add images in a ListView which has an ArrayAdapter. Fyi, the toList() is a conversion from iterator to a list of the given DBObject.
I override the View getView() and set a textview and an image.
private static class EventAdapter extends ArrayAdapter<DBObject> {
public EventAdapter(Context context, int resource, Iterable<DBObject> events) {
super(context, resource, toList(events));
}
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
LayoutInflater vi = LayoutInflater.from(getContext());
v = vi.inflate(R.layout.adapter_event_list, null);
DBObject event = getItem(position);
if (event != null) {
//Get the logo if any
if( ((DBObject)event.get("events")).containsField("logo") ){
String logoURL = ((DBObject)((DBObject)event.get("events")).get("logo")).get("0").toString();
ImageView eventLogo = (ImageView) v.findViewById(R.id.eventLogoList);
new setLogo().execute(logoURL, eventLogo);
}
TextView title= (TextView) v.findViewById(R.id.eventTitleList);
title.setText( ((DBObject)event.get("events")).get("title").toString() );
}
return v;
}
protected static <T> List<T> toList( Iterable<T> objects ) {
final ArrayList<T> list = new ArrayList<T>();
for( T t : objects ) list.add(t);
return list;
}
//setLogo() method here. See below
}
The text in the textview is fine. However the images are getting messed up. They seem to load in wrong places in the list. The route of the code is: 1)Get from the DB (async) 2)populate the ListView 3) while populating load each image(second async).
Here is the setLogo() AsyncTask which is inside the EventAdapter above:
private class setLogo extends AsyncTask<Object,Void,Bitmap>{
ImageView eventLogo = null;
#Override
protected Bitmap doInBackground(Object...params) {
try{
Bitmap eventImage = downloadBitmap((String) params[0]);
eventLogo = (ImageView) params[1];
return eventImage;
}
catch(Exception e){
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(Bitmap eventImage) {
if(eventImage!=null && eventLogo!=null){
eventLogo.setImageBitmap(eventImage);
}
}
}
I did so (using an Async) which I believe is the correct way to load images from urls. I saw this post on multithreading and from which I borrowed the downloadBitmap() method.
As explained above the images are loaded in wrong places of the ListView. What can be a robust way to load them?
Also the idea to pass the v.findViewById(R.id.eventLogoList) inside the AsyncTask is that the program will distinguish each adapter's ImageView but it seems it doesn't.
Update
After following the problem that is causing this mix I found this SO question.
I altered my code in order to check if the if is causing the problem.
//Get the logo if any
if( ((DBObject)event.get("events")).containsField("logo") ){
String logoURL = ((DBObject)((DBObject)event.get("events")).get("logo")).get("0").toString();
ImageView eventLogo = (ImageView) row.findViewById(R.id.eventLogoList);
//new setLogo().execute(logoURL, eventLogo);
TextView title= (TextView) row.findViewById(R.id.eventTitleList);
title.setText( "Shit happens" );
}
Let's say I have 40 items. The Shit happens is set on the fields that a logo field exists. If I scroll down/up the order changes and the text gets messed up. It is because the stack created inside the loop is small than the maximum of the list..I guess... I am still struggling.
PS: I found this easy library to load images asynchronously instead of DYI stuff.
Update 2
I added an else with a static url. Because of the time it take to the image to load they are still misplaced.
I would really go for a good library like Picasso.
It will handle all the hard part for you and it's very well written.
http://square.github.io/picasso/

Image (from web) in the Android ListView always reloaded when appears

I have a ListView than contains a list of image created from web link (e.g. http://www...image.jpg) with the istruction:
Drawable d = LoadImageFromUrlWeb(TopTen_LinkImg);
imageTopTenView.setImageDrawable(d);
I have created a custom ArrayAdapter (both simple and optimized with "holder" same result).
The problem is that each image when appear in the display is uploaded from web and browse the page list is impossible (too slow).
There is a code that assign to ImageView the permanent image.
The code is:
public View getView(int position, View convertView, ViewGroup parent)
{
LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View rowView = inflater.inflate(R.layout.row_top_ten, null);
ImageView imageTopTenView = (ImageView)rowView.findViewById(R.id.imageTopTen);
String TopTen = (String)ArrayDatiTopTen.get(position);
String[] ArrayTopTen=TopTen.split(",");
String TopTen_LinkImg=(String)ArrayTopTen[0];
Drawable d = LoadImageFromUrlWeb(TopTen_LinkImg);
imageTopTenView.setImageDrawable(d);
return rowView;
}
Perhaps the solution is populate the listView using programmatically code:
ListView listView=(ListView) findViewById(R.id.listView);
...
listView.addView(...)
...
SOLVED
I have solved creating an Drawable array and filling this array with the image before use in ArrayAdapter
// Define:
Drawable imageCache[]=new Drawable[100];
then:
//loop to popolate array
imageCache[ct]=LoadImageFromUrlWeb(Link);
In the ArrayList I use:
...
imageTopTenView.setImageDrawable(imageCache[position]);
return rowView;
...
From url string to drawable:
private Drawable LoadImageFromUrlWeb(String url)
{
try
{
url=url.replaceAll(" ", "%20");
InputStream is = (InputStream) new URL(url).getContent();
Drawable d = Drawable.createFromStream(is, "src name");
return d;
}
catch (Exception e)
{
Log.w("LoadImageFromUrlWeb",e.toString());
return null;
}
}
Brett's answer is only half the solution, yes image downloading should be done asynchronously but you'll end up repeatedly downloading the same image over and over again every time you scroll the listview due to the optimization of the listview.
It reuses views so even if you downloaded an image and set it, if you scroll down several items that view will be reused and the image will have to be downloaded again when you scroll back up.
To prevent this you will need image caching too. See this post on the android developer blog.
Happily enough the code on the blog provides both asynchronous image downloading and image caching. Source code can be gotten from here
(Note: You'll need to make a slight change to the source code)
Change Line 58 from
private Mode mode = Mode.NO_ASYNC_TASK;
to
private Mode mode = Mode.CORRECT;
If I understand your dilemma correctly, you will need to load the drawable in the background, rather than synchronously, and insert a blank/local place holder image in its stead. Once you have the proper image downloaded, you can replace the place holder with it.

Categories

Resources