hi i have a gridview (It has two textboxes and one imageview)
The items are populated from db. I use a standard photo for items that haven't a photo. App works with 50 items but with 200 items it gives some error.
logcat** java.lang.OutOfMemoryError at
android.graphics.BitmapFactory.nativeDecodeStream(Native Method) at
android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:652)
ı try some methods that get from google suggest for loading large bitmap, but it didnt work. http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
when I set inJustDecodeBounds true, app works but all items come empty..
here is my code get info from db:
private void refreshList(String sql)
{
gridArray = new ArrayList<Stock>();
final Cursor cursor = _SQLite.RawQueryTry(sql, null);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
if (cursor != null)
{
if (cursor.moveToFirst())
{
for (int i = 0; i < cursor.getCount(); i++)
{
byte[] blob = cursor.getBlob(cursor.getColumnIndex("FOTO"));
Bitmap stockImage = null;
ByteArrayInputStream inputStream = null;
if (blob == null)
{
options.inJustDecodeBounds=false;
stockImage = BitmapFactory.decodeResource(getApplicationContext().getResources(), R.drawable.foto_yok, options);
}
else
{
inputStream = new ByteArrayInputStream(blob);
stockImage = BitmapFactory.decodeStream(inputStream, null, options);
}
String stockName = cursor.getString(cursor.getColumnIndex("STOK_ADI"));
String stockNo = cursor.getString(cursor.getColumnIndex("STOK_NO"));
String stockCode = cursor.getString(cursor.getColumnIndex("STOK_KODU"));
String stockEntity = cursor.getString(cursor.getColumnIndex("BIRIM"));
String stockKdvOranı = cursor.getString(cursor.getColumnIndex("KDV_ORANI"));
String stockRatio = TableUtils.getFieldValue("KATSAYI", "BIRIM", stockEntity, "STOKBIRI");
String stockAmount = cursor.getString(cursor.getColumnIndex("MIKTAR"));
gridArray.add(new Stock(stockImage, stockName, stockNo, stockCode, stockKdvOranı, stockEntity, stockAmount, stockRatio, processNo));
cursor.moveToNext();
}
}
}
gridAdapter = new AdapterStockGridView(this, R.layout.stockgriditems, gridArray);
gridView.setAdapter(gridAdapter);
}
and my adapter class :
public class AdapterStockGridView extends ArrayAdapter<Stock>
{
Context context;
int id;
ArrayList<Stock> stock = new ArrayList<Stock>();
public AdapterStockGridView(Context context, int id, ArrayList<Stock> stock)
{
super(context, id, stock);
this.id = id;
this.context = context;
this.stock = stock;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View row = convertView;
RecordHolder holder = null;
if (row == null)
{
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
row = inflater.inflate(id, parent, false);
holder = new RecordHolder();
holder.stockCode = (TextView) row.findViewById(R.id.stockCode);
holder.stockName = (TextView) row.findViewById(R.id.stockName);
holder.stockImage = (ImageView) row.findViewById(R.id.stockImage);
row.setTag(holder);
}
else
{
holder = (RecordHolder) row.getTag();
}
Stock item = stock.get(position);
holder.stockCode.setText(item.getStockCode());
holder.stockName.setText(item.getStockName());
holder.stockImage.setImageBitmap(item.getStockImage());
return row;
}
}
static class RecordHolder
{
TextView stockName;
TextView stockCode;
ImageView stockImage;
}
}
Maybe you're storing the blob as full size? If so, there's no need to do that as you're wasting too much space and you're having these memory issues. The users is not going to see the big image anyway, so redo your image storing in order to store the scaled down images as blobs.
You're getting these OOE because you're loading the full blob byte array - and the way it is now, you can't make use of the article from developer article.
Also, don't load the images in that Stock object as you're going to hold them unnecessarily. Rather than that, use a bitmap loader mechanism that keeps the images in a LRUCache and if not found in there, it loads them from database. In your GridView adapter getView method request to load that image. If found in LRUCache, get it from there, if not start an AsyncTask to get it from DB, add it in LRUCache and display it to the user.
Here is a link with caching bitmaps with LRUCache.
Related
I have been searching SO threads for answers but couldn't figure out my issue from previous discussion. I have a listview which loads about 50 images (it used to be about 100 but this was barely loading any images at all). After grabbing my JSON content (including image URL) from an api endpoint, through an adapter, my code puts it inside the listview.
Currently, with 50 images, picasso will load one image at a time as I scroll down on the feed. I feel as if keeping the scroll fixed on one item in the listview will make that image load faster. As I scroll up, however, it puts the placeholder back in and reloads the image again. Is there a way to solve this issue?
public class MainActivity extends Activity {
private List<Post> myPosts = new ArrayList<Post>();
protected String[] mBlogPostTitles;
public static final String TAG = MainActivity.class.getSimpleName();//prints name of class without package name
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(isNetworkAvailable()) {
GetBlogPostsTask getBlogPostsTask = new GetBlogPostsTask(); // new thread
getBlogPostsTask.execute();// don't call do in background directly
}else{
Toast.makeText(this, "Network is unavailable", Toast.LENGTH_LONG).show();
}
}
public boolean isNetworkAvailable() {
ConnectivityManager manager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
boolean isAvailable = false;
if(networkInfo != null && networkInfo.isConnected()){
isAvailable = true;
}
return isAvailable;
}
private void populateListView() {
ArrayAdapter<Post> adapter = new MyListAdapter();
ListView list = (ListView) findViewById(R.id.postsListView);
list.setAdapter(adapter);
}
private class MyListAdapter extends ArrayAdapter<Post>{
public MyListAdapter() {
super(MainActivity.this, R.layout.item_view, myPosts);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// make sure we have a view to work with
View itemView = convertView;
if (itemView == null) {
itemView = getLayoutInflater().inflate(R.layout.item_view, parent,false);
}
//find the post to work with
Post currentPost = myPosts.get(position);
Context context = itemView.getContext();
String imageURL = currentPost.getImage();
if(imageURL == null || imageURL.isEmpty()){
ImageView imageView = (ImageView) itemView.findViewById(R.id.item_image);
imageView.setVisibility(View.GONE);
}else{
ImageView imageView = (ImageView) itemView.findViewById(R.id.item_image);
Picasso.with(context)
.load(imageURL)
.tag(context)
.placeholder(R.drawable.kanye8080s)
.error(R.drawable.stadiumarcadium)
.into(imageView);
imageView.setVisibility(View.VISIBLE);
}
//Username
TextView userText = (TextView) itemView.findViewById(R.id.item_txtUser);
userText.setText(currentPost.getUser());
//Time of post
TextView timeText = (TextView) itemView.findViewById(R.id.item_txtTime);
timeText.setText("" + currentPost.getTime());
//The actual post
TextView postText = (TextView) itemView.findViewById(R.id.item_txtPost);
postText.setText("" + currentPost.getPost());
//The actual post
TextView likesText = (TextView) itemView.findViewById(R.id.item_txtLikes);
likesText.setText("" + currentPost.getLikes());
return itemView;
}
}
private class GetBlogPostsTask extends AsyncTask<Object, Void, List> {
#Override
protected List doInBackground(Object[] params) {
int responseCode = -1;//need to have this variable outside scope of try/catch block
JSONObject jsonResponse = null;
StringBuilder builder = new StringBuilder();
HttpClient client = new DefaultHttpClient();
HttpGet httpget = new HttpGet(""); /// api endpoint redacted
try {
HttpResponse response = client.execute(httpget);
StatusLine statusLine = response.getStatusLine();
responseCode = statusLine.getStatusCode();
if(responseCode == HttpURLConnection.HTTP_OK){ //could have used just 200 value
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(content));
String line;
while((line = reader.readLine()) != null){
builder.append(line);
}
jsonResponse = new JSONObject(builder.toString());
JSONArray jsonPosts = jsonResponse.getJSONArray("posts");
for(int i=0; i < jsonPosts.length(); i++ ){
JSONObject jsonPost = jsonPosts.getJSONObject(i);
int post_id = Integer.parseInt(jsonPost.getString("id"));
String post_user = jsonPost.getString("user");
String post_account = jsonPost.getString("account");
int post_time = Integer.parseInt(jsonPost.getString("time"));
String post_post = jsonPost.getString("post");
String post_image = jsonPost.getString("image");
int post_likes = Integer.parseInt(jsonPost.getString("likes"));
myPosts.add(new Post(post_id, post_user, post_account, post_time, post_post, post_image, "profile picture here", post_likes));
}
}else{
Log.i(TAG, "Unsuccessful HTTP Response Code: " + responseCode);
}
}
catch (MalformedURLException e){
Log.e(TAG, "Exception caught");
}
catch (IOException e){
Log.e(TAG, "Exception caught");
}
catch (Exception e){//must be in this order, this is the last, general catch
Log.e(TAG, "Exception caught", e);
}
return null;
}
#Override
protected void onPostExecute(List result) {
// call populateListView method here
populateListView();
super.onPostExecute(result);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
EDIT:
I have updated my code into a view holder pattern, created two separate views (one for a post with an image, one for a post with just text) and also included Picasso's new scroll detection capabilities.
I have seen an improvement in some of the images loading quicker, at least when the view is focused while scrolling, the image is more likely to load now. However, on scroll up those same images that were once loaded, disappear. It feels as if Picasso is only loading 4-5 images at a time and replacing the ones already loaded to make room. My updated code is below:
public class MainActivity extends Activity {
private List<Post> myPosts = new ArrayList<Post>();
protected String[] mBlogPostTitles;
public static final String TAG = MainActivity.class.getSimpleName();//prints name of class without package name
...
private void populateListView() {
Activity activity = MainActivity.this;
ArrayAdapter<Post> adapter = new MyListAdapter();
ListView list = (ListView) findViewById(R.id.postsListView);
list.setAdapter(adapter);
list.setOnScrollListener(new SampleScrollListener(activity));
}
private class MyListAdapter extends ArrayAdapter<Post>{
public MyListAdapter() {
super(MainActivity.this, R.layout.item_view, myPosts);
}
#Override
public int getViewTypeCount() {
return 2;
}
#Override
public int getItemViewType(int position) {
String imageURL = myPosts.get(position).getImage();
if(imageURL == null || imageURL.isEmpty()){
return 1; // text based
}else{
return 0; // image based
}
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
PostViewHolder holder;
int type = getItemViewType(position);
View itemView = convertView;
// make sure we have a view to work with
if (itemView == null) {
holder = new PostViewHolder();
if(type == 1) {
itemView = getLayoutInflater().inflate(R.layout.item_view, parent, false);
} else {
itemView = getLayoutInflater().inflate(R.layout.image_post_view, parent, false);
holder.image = (ImageView) itemView.findViewById(R.id.item_image);
}
holder.user = (TextView) itemView.findViewById(R.id.item_txtUser);
holder.time = (TextView) itemView.findViewById(R.id.item_txtTime);
holder.post = (TextView) itemView.findViewById(R.id.item_txtPost);
holder.likes = (TextView) itemView.findViewById(R.id.item_txtLikes);
itemView.setTag(holder);
} else {
holder = (PostViewHolder) itemView.getTag();
}
//find the post to work with
Post currentPost = myPosts.get(position);
if(type != 1) {
Context context = itemView.getContext();
String imageURL = currentPost.getImage();
Picasso.with(context).setIndicatorsEnabled(true);
//Picasso.with(context).setLoggingEnabled(true);
Picasso.with(context)
.load(imageURL)
.tag(context)
.placeholder(R.drawable.kanye8080s)
//.skipMemoryCache()
.error(R.drawable.stadiumarcadium)
.fit()
.into(holder.image);
}
//Username
holder.user.setText(currentPost.getUser());
//Time of post
holder.time.setText("" + currentPost.getTime());
//The actual post
holder.post.setText(currentPost.getPost());
//Likes for the post
holder.likes.setText("" + currentPost.getLikes());
return itemView;
}
}
public class SampleScrollListener implements AbsListView.OnScrollListener {
private final Context context;
public SampleScrollListener(Context context) {
this.context = context;
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
final Picasso picasso = Picasso.with(context);
if (scrollState == SCROLL_STATE_IDLE || scrollState == SCROLL_STATE_TOUCH_SCROLL) {
picasso.resumeTag(context);
} else {
picasso.pauseTag(context);
}
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
// Do nothing.
}
}
...
}
Where is the issue coming from? Should I be preloading these images somehow in the cache? While I have already looked into Picasso's new priority feature, should I be telling Picasso somehow to load images in the order in which they appear in my listview? Any ideas? How can I "keep" images that have already been loaded on scroll up?
use resize with picasso
Picasso.with(context)
.load(imageURL)
.tag(context)
.placeholder(R.drawable.kanye8080s)
.error(R.drawable.stadiumarcadium)
.into(imageView)
.resize(x,y);
//This would definitely help
The size of the memory cache of Picasso is limited so it does not generate out of memory errors when scrolling long lists. Once the images are out of the memory cache, the placeholder will be displayed while the image is reloaded from either the disk cache or the network.
The disk cache is enabled by default so the reload time should be very fast. You can use setIndicatorsEnabled(true) to see where the images are being loaded from.
If you are finding that Picasso is reloading the images from network, this is probably a problem with the HTTP headers being sent from the server. I don't believe Picasso actually caches the images on disk itself, instead relying on the HTTP layer, which will obey a no-cache header, and will reload from network if the expire time elapses.
I'd look at two things.
Number one is the sizes of the images being loaded. I don't know what the default maximum cache size is in Picasso, but it sounds like you may be exceeding it with just a few images, causing the others to be evicted from the cache.
Number two is probably not the core issue, but also contributes to performance.
You are doing a lot findViewById() calls, which are fairly expensive.
Look into the "ViewHolder" pattern for "caching" those lookups.
Edit - see Jake Wharton's answer to a similar question for more detail
Use :
recyclerview.getRecycledViewPool().setMaxRecycledViews(0, 0);
This solved my issue
I would suggest you to use GLIDE for image loading. Since GLIDE is fast and with its cache loading feature you can get super fast image loading, With GLIDE you get lot of features..
Download here
https://github.com/bumptech/glide
I need to parse the json output in my xml. Parsing is done but the image is not seen in the xml. Android log says this -
12-22 14:26:34.472: I/System.out(6037): resolveUri failed on bad bitmap uri: "base_url"/sites/default/files/pictures/picture-6175010166.jpg
Is there anything wrong in my below code can any body suggest me ?
HashMap<String, String> listview = new HashMap<String, String>();
String title = "";
String teaser="";
String createdon = "";
String profile_image = "";
try {
title = jListview.getString("title");
teaser = jListview.getString("teaser");
createdon = jListview.getString("created");
profile_image = jListview.getString("profile_image");
listview.put("title", title);
listview.put("teaser", teaser);
listview.put("created", createdon);
listview.put("profile_image", profile_image);
//listview.put("profile_image", picture);
} catch (JSONException e) {
System.out.println( "Bad Error" + e.toString());
e.printStackTrace();
}
return listview;
This is my main activity code where iam showing the result
try{
/** Getting the parsed data as a List construct */
lists = listJsonParser.parse(obj);
int imageCount = lists.size();
}
}catch(Exception e){
Log.d("Exception Main",e.toString());
}
/** Keys used in Hashmap */
String[] from = { "title","teaser","created","profile_image"};
/** Ids of views in listview_layout */
int[] to = { R.id.title,R.id.teaser,R.id.createdon,R.id.list_image};
/** Instantiating an adapter to store each items
* R.layout.listview_layout defines the layout of each item
*/
SimpleAdapter adapter = new SimpleAdapter(getBaseContext(), countries, R.layout.home_layout, from, to);
return adapter;
LoGcat:12-22 14:26:34.382: I/System.out(6037): resolveUri failed on bad bitmap uri:
your Error says Below:
12-22 14:26:34.472: I/System.out(6037): resolveUri failed on bad bitmap uri: "base_url"/sites/default/files/pictures/picture-6175010166.jpg
you need to download the image and then set it as bitmap. HERE is one of the many examples.
you can not set Direct web url to ImageView for setting ImageView src. you first create an custom Adapter by extending BaseAdapter for ListView and in getView you will need to first download image from Url as Bitmap and then set it to ImageView as:
public class CustomAdapter extends BaseAdapter{
#Override
public View getView(int position, View convertView,
ViewGroup parent) {
if(convertView == null){
LayoutInflater layoutInflater = (LayoutInflater)
getSystemService(LAYOUT_INFLATER_SERVICE);
convertView = layoutInflater.
inflate(R.layout.layout_row, null);
}
Bitmap test = getbitpam(maptemp.get("profile_image"));
imgview=(ImageView) convertView.findViewById(R.id.img_list);
imgview.setImageBitmap(test);
return convertView;
}
}
//get image from server
public Bitmap getbitpam(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;
}
}
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
How do I display a contact's photo from the contact's id?
I've been trying for over a week to populate my ImageViews in my ListView with contact photos from my device, but to no avail.
Is there a COMPLETE solution as to do this for an API Level 10?
My code with LogCat:
Why are my contact photos not displaying in listview?
** CustomAdapter class:**
public class CustomAdapter extends ArrayAdapter<String> {
Cursor c;
String TAG = "CustomAdapter";
private Context context = null;
ArrayList<String> elements = null;
private ArrayList<String> data = null;
public static String contactName;
public static int count = 0;
private ArrayList<Boolean> itemChecked = null;
public static List<String> messages;
public static List<String> contactID;
String body;
String phoneNumber;
public CustomAdapter(Context context, int type, ArrayList<String> elements) {
super(context, type, elements);
data = elements;
this.elements = elements;
this.context = context;
}
// THIS IS SIMPLY A CLASS VIEW WILL HOLD DIFFERENT VIEWS OF YOUR ROW.
static class ViewHolder {
public ImageView photo;
public TextView contact;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View rowView = convertView;
final ViewHolder holder;
if (rowView == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// HERE I AM INFLATING LISTVIEW LAYOUT.
rowView = inflater.inflate(R.layout.contact_entry, null, false);
holder = new ViewHolder();
holder.photo = (ImageView) rowView.findViewById(R.id.iv_contactPic);
holder.contact = (TextView) rowView
.findViewById(R.id.contactEntryText);
rowView.setTag(holder);
// RETRIEVE LATEST CONTACTS WHO SENT SMS (for visual)
contactID = new ArrayList<String>();
contactID = elements;
String folder = "content://sms/inbox/";
Uri mSmsQueryUri = Uri.parse(folder);
contactID = new ArrayList<String>();
try {
c = context.getContentResolver().query(
mSmsQueryUri,
new String[] { "_id", "thread_id", "address", "date",
"body" }, null, null, null);
if (c == null) {
Log.i(TAG, "cursor is null. uri: " + mSmsQueryUri);
}
c.moveToFirst();
while (c.moveToNext()) {
phoneNumber = c.getString(0);
contactID.add(phoneNumber);
}
} catch (Exception e) {
// Log.e(TAG, e.getMessage());
} finally {
c.close();
}
} else {
holder = (ViewHolder) rowView.getTag();
}
if (holder != null) {
// bind the data to the row views
holder.contact.setText(data.get(position));
holder.photo.setImageBitmap(getByteContactPhoto(contactID
.get(position)));
// SHOW CONTACT PHOTO IF IT EXISTS. IF NOT, DEFAULT (***NOT WORKING***)
Long l = Long.parseLong(contactID.get(position));
contactPhoto = loadContactPhoto(context.getContentResolver(), l);
if(contactPhoto == null){
holder.photo.setImageResource(R.drawable.ic_intel);
} else{
holder.photo.setImageBitmap(contactPhoto);
}
return rowView;
} // end if
// GET CONTACT PHOTO
private static Bitmap loadContactPhoto(ContentResolver cr, long id) {
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id);
InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(cr, uri);
if (input == null) {
return null;
}
return BitmapFactory.decodeStream(input);
}
} // end class
Use this code for fetching the photo from contacts...........
public static Bitmap loadContactPhoto(ContentResolver cr, long id) {
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id);
InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(cr, uri);
// InputStream input = ContactsContract.Contacts.Photo
if (input == null) {
return null;
}
return BitmapFactory.decodeStream(input);
Write this in snippet at your desired place
// set the profile picture
ImageView profile = (ImageView) findViewById(R.id.display_contact_image);
Bitmap bitmap = loadContactPhoto(getContentResolver(), _id);
if(bitmap == null) {
//Set default contact image
profile.setImageResource(R.drawable.default_contact_image);
} else {
profile.setImageBitmap(bitmap);
}
Method is
private static Bitmap loadContactPhoto(ContentResolver cr, long id) {
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id);
InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(cr, uri);
if (input == null) {
return null;
}
return BitmapFactory.decodeStream(input);
}
And share your code which you tried yet.... (from last one week :)
I have about 4k rows in sqlite table, table has 7 columns.
I created working ListView with my own CursorAdapter.
Query is like this SELECT * FROM [table] ORDER BY [column] DESC;
Table has first column _id INTEGER PRIMARY KEY but ordering is done by another column.
For opening db using my own subclass of SQLiteOpenHelper
Creating cursor
mySQLiteOpenHelper pm = new mySQLiteOpenHelper();
SQLiteDatabase db = pm.getReadableDatabase();
Cursor c = db.query([tablename], new String[]{"_id", "[column]", "[column]", "[column]", "[column]", "[column]"}, null, null, null, null, "name ASC");
Passing it to ListView
ListView lv = (ListView) findViewById(R.id.list_items);
lv.setOnItemClickListener(this);
pa = new ItemsAdapter(ItemsActivity.this, c);
In ItemsAdapter I have reimplemented
private LayoutInflater inflater;
#Override
public View newView(Context arg0, Cursor arg1, ViewGroup arg2) {
return inflater.inflate(R.layout.items_row, arg2,false);
}
and
#Override
public void bindView(View rtn, Context arg1, Cursor c) {
item_name = (TextView) rtn.findViewById(R.id.item_name);
item_description = (TextView) rtn.findViewById(R.id.item_description);
item_catalog_id = (TextView) rtn.findViewById(R.id.item_catalog_id);
item_true_price = (TextView) rtn.findViewById(R.id.item_true_price);
item_display_price = (TextView) rtn.findViewById(R.id.item_display_price);
item_button = (Button) rtn.findViewById(R.id.item_button);
item = new MyWrapClass(c);
// some work with item to fill up all UI items
}
MyWrapClass
public final class MyWrapClass {
public String name = "";
public String notes = "";
public int id = 0;
public String catalogId = "";
public int price = 0;
public int publicPrice = 0;
public String groupPrice = "";
public int order_count = 0;
public MyWrapClass(Cursor c) {
try {
id = c.getInt(0);
catalogId = c.getString(1);
name = c.getString(2);
price = c.getInt(3);
publicPrice = c.getInt(4);
groupPrice = c.getString(5);
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
The same row init code was used in ListView and there it worked very good.
So if you can say from this code, is there ANY reason, why should load of 6 row items (one screen height) and scroll refresh (mean when you scroll one item down) take up to 1 minute?
Just load of ListView takes up to 2 minutes, and then about half time to scroll one list item down/up. Where can be the performance issue?
I'd create a custom Adapter, that only loads whatever is needed for the active views and that reuses views in the getView() method. It's really quite simple.
Update
I found an excellent example, that you should be able to use:
http://android.amberfog.com/?p=296
I have a listview in which I'm loading all the images (as previews) from the user's SD card. I have a custom SimpleCursorAdapter and when I override the getView() method, I try to start background threads for the image loading.
What I'm trying to do is basically "lazy loading" the image previews into the listview using background threads or something. I'm open for new solutions. The main problem is that scrolling is ungodly slow since loading images is so expensive an operation.
Here's the relevant code I'm trying:
public class listOfImages extends SimpleCursorAdapter {
private Cursor c;
private Context context;
public listOfImages(Context context, int layout, Cursor c,
String[] from, int[] to) {
super(context, layout, c, from, to);
this.c = c;
this.context = context;
}
public View getView(int pos, View inView, ViewGroup parent) {
View v = inView;
if (v == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = inflater.inflate(R.layout.image_item, null);
}
this.c.moveToPosition(pos);
int columnIndex = this.c.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME);
String name = this.c.getString(columnIndex);
columnIndex = this.c.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE);
String size = this.c.getString(columnIndex);
columnIndex = this.c.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
String data = this.c.getString(columnIndex); //gives the filename
TextView sTitle = (TextView) v.findViewById(R.id.image_title);
sTitle.setText(name);
imagePreviewLoader ipl = new imagePreviewLoader(v, data);
ipl.mainProcessing();
v.setTag(data);
v.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "Image: " + v.getTag(), Toast.LENGTH_SHORT).show();
String filename = (String) v.getTag();
Intent intent = new Intent(context, ViewImage.class);
intent.putExtra("filename", filename);
context.startActivity(intent);
}
});
return v;
}
}
And now the background threading that I'm trying:
public class imagePreviewLoader {
private Handler handler = new Handler();
private View v;
private String data;
public imagePreviewLoader(View v, String data) {
this.v = v;
this.data = data;
}
protected void mainProcessing() {
Thread thread = new Thread(null, doBackground, "Background");
thread.start();
}
private Runnable doBackground = new Runnable() {
public void run() {
backgroundThreadProcessing();
}
};
private void backgroundThreadProcessing() {
handler.post(doUpdateGUI);
}
private Runnable doUpdateGUI = new Runnable() {
public void run() {
updateGUI();
}
};
private void updateGUI() {
ImageView img = (ImageView) v.findViewById(R.id.image_view);
BitmapFactory.Options bfo = new BitmapFactory.Options();
bfo.inSampleSize = 30;
bfo.inTargetDensity = 50;
Bitmap bm = BitmapFactory.decodeFile(data, bfo);
img.setImageBitmap(bm);
}
}
The issue is that everything tries to load at once when you scroll, so scrolling is really slow. I thought what would happen is the imageview would just stay blank (or a placeholder) until the thread has loaded the appropriate image. I guess not though.
Thanks for any help.
Have a look at my answer to this question, it has a sample project which shows how to do it but downloading images from the net. You should be able to modify it quite easily to work for you getting images from the SD card.
I have an easy to use library under a basically public domain license that you can check out... It will cancel loading for rows that aren't displaying and uses two threads to do image loading.
You can check it out on my GitHub: https://github.com/tbiehn/Android-Adapter-Image-Loader