I'm downloading an image from the web and trying to set it as the background to the inflated list element in my ListView adapter. This is my method (from the class extending BaseAdapter:
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
//working with an object called "hl"
if (view == null){
view = myInflater.inflate(R.layout.list_element, null);
}
Bitmap background = hl.getBgImage();
Drawable dr = new BitmapDrawable(background);
RelativeLayout rl = (RelativeLayout) view.findViewById(R.layout.headline_list);
rl.setBackgroundDrawable(dr);
return view;
}
However, I am getting a NullPointerException on the rl.setBackgroundDrawable(dr); line. Is there a problem with the way I'm adding the image? My method to get the bitmap is as follows, the stack trace is never called so I assume that it is downloading properly?
private static Bitmap getBitmapFromURL(String imageUrl) {
try {
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
Thanks for any advice.
Edit: I am calling getBitmapFromUrl(String imageURL) with:
String image = "http://www.google.com/trends/resources/2327917647-google-icon.png";
Bitmap bg = getBitmapFromURL(image);
Object hl = new Object(title, bg);
objectList.add(hl);
Found the issue. Should have ignored the relativelayout completely.
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
//working with an object called "hl"
if (view == null){
view = myInflater.inflate(R.layout.headline_list, null);
}
Bitmap background = hl.getBgImage();
Drawable dr = new BitmapDrawable(background);
view.setBackgroundDrawable(dr);
return view;
}
As I know, the code line "rl.setBackgroundDrawable(dr);" will never throw NullPointerException unless rl is null, even if dr is null. So Please update your xml file R.layout.list_element and let's find the problem together.
Good Luck!
I have a Adobe Air application that intend to take a screenshot with Native Extension on Android device, but the java code returns a black image.
public FREObject call(FREContext context, FREObject[] params) {
View view = context.getActivity().getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap image = view.getDrawingCache();
}
I don't know much about Adobe Air. My java code runs exactly on Android Java Application, but returns black image on Adobe Air Android Application with Native Extension.
Is there any solution or any way to take a screenshot using Java in NativeExtension?
Thanks much!
Could be that you are not getting the correct view. Try this to get the topmost root view.
public FREObject call(FREContext context, FREObject[] params)
{
View view = findViewById(android.R.id.content).getRootView();
view.setDrawingCacheEnabled(true);
Bitmap image = view.getDrawingCache();
if(image == null)
{
System.out.println("Image returned was null!");
}
}
I also removed the buildDrawingCache() line; that can sometimes cause issues, and from what I've read it's not completely necessary.
Finally you'll want to check if the bitmap being returned is null. If so that could be why it's all black.
You can take a screenshot like this and save it to the SD card:
View content = findViewById(R.id.layoutroot);
content.setDrawingCacheEnabled(true);
Function to get the rendered view:
private void getScreen()
{
View content = findViewById(R.id.layoutroot);
Bitmap bitmap = content.getDrawingCache();
File file = new File( Environment.getExternalStorageDirectory() + "/asdf.png");
try
{
file.createNewFile();
FileOutputStream ostream = new FileOutputStream(file);
bitmap.compress(CompressFormat.PNG, 100, ostream);
ostream.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
You have to add this permission to your AndroidManifest (if you want to save it):
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I want to store images in my database. Also I want to check that if the image and title is already in the database. If so, it will not add them to the database. This is my class.
Attractions
public class Attractions extends ListActivity {
DataBaseHandler db = new DataBaseHandler(this);
ArrayList<Contact> imageArry = new ArrayList<Contact>();
List<Contact> contacts;
ContactImageAdapter adapter;
int ctr, loaded;
int [] landmarkImages={R.drawable.oblation,R.drawable.eastwood,R.drawable.ecopark,R.drawable.circle};
String []landmarkDetails = { "Oblation", "Eastwood", "Ecopark", "QC Circle"};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_attractions);
ctr = db.checkContact(landmarkDetails[loaded]);
// get image from drawable
/**
* CRUD Operations
* */
// Inserting Contacts
Log.d("Insert: ", "Inserting ..");
for(loaded=0; loaded <landmarkDetails.length;loaded++){
Bitmap image = BitmapFactory.decodeResource(getResources(),
landmarkImages[loaded]);
// convert bitmap to byte
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte imageInByte[] = stream.toByteArray();
Log.d("Going to load images", "Image "+ loaded);
Log.d("Goind to load objects", "loading");
if(ctr == 0){
Log.d("Nothing Loaded", "Loading Now");
db.addContact(new Contact(landmarkDetails[loaded], imageInByte));}
Log.d(landmarkDetails[loaded], "Loaded!");
image.recycle();
}
loadFromDb();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.attractions, menu);
return true;
}
public void loadFromDb(){
// Reading all contacts from database
contacts = db.getAllContacts();
for (Contact cn : contacts) {
String log = "ID:" + cn.getID() + " Name: " + cn.getName()
+ " ,Image: " + cn.getImage();
// Writing Contacts to log
Log.d("Result: ", log);
//add contacts data in arrayList
imageArry.add(cn);
}
adapter = new ContactImageAdapter(this, R.layout.screen_list,
imageArry);
ListView dataList = (ListView) findViewById(android.R.id.list);
dataList.setAdapter(adapter);
}
public void onPause(){
super.onPause();
}
public void onResume(){
super.onResume();
}
}
It works fine on the emulator, but I tried testing on my S4 and then after 3 tries of going to this class, it forced stop. I tried it with usb debugging and the logcat showed java.lang.outofmemoryerror . The logcat pointed the error in my contactimageadapter.
ContactImageAdapter
public class ContactImageAdapter extends ArrayAdapter<Contact>{
Context context;
int layoutResourceId;
// BcardImage data[] = null;
ArrayList<Contact> data=new ArrayList<Contact>();
public ContactImageAdapter(Context context, int layoutResourceId, ArrayList<Contact> data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
ImageHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new ImageHolder();
holder.txtTitle = (TextView)row.findViewById(R.id.txtTitle);
holder.imgIcon = (ImageView)row.findViewById(R.id.imgIcon);
row.setTag(holder);
}
else
{
holder = (ImageHolder)row.getTag();
}
Contact picture = data.get(position);
holder.txtTitle.setText(picture._name);
//convert byte to bitmap take from contact class
byte[] outImage=picture._image;
ByteArrayInputStream imageStream = new ByteArrayInputStream(outImage);
Bitmap theImage = BitmapFactory.decodeStream(imageStream);
holder.imgIcon.setImageBitmap(theImage);
return row;
}
static class ImageHolder
{
ImageView imgIcon;
TextView txtTitle;
}
}
And pointed to this line Bitmap theImage = BitmapFactory.decodeStream(imageStream);
I have little (almost none) knowledge on managing images and storing them. I also enable android:largeHeap but still force closes on multiple tries. I hope someone can help me solving this issue, or at least show me a different way of storing text and images to sqlite db. Many thanks!
You have multiple places where whole image (assuming it is big) keeps in memory:
Contact object has it. All loaded images are in imageArry which is instance level variable.
public class Attractions extends ListActivity {
DataBaseHandler db = new DataBaseHandler(this);
ArrayList<Contact> imageArry = new ArrayList<Contact>();
in ContactImageAdapter.getView method you create another copy of image as BMP in holder object and pass it out of method.
So, at some point you do not have enough memory to keep all of them. Also I sure that decodeStream needs some more memory to perform.
After all it is not predictable when each new holder created in getView will be cleaned by GC.
Usually for such situation when object created as new in some method, then passed back to the calling method, that object will be collected only by Full GC.
So, as "Software Sainath" said, do not store images in database…
and do not keep them in memory either.
P.S. Then provide to the view a link to the external image file. That also will save time to load a view. Image will be in cache and if user at least once got it, it will not pass through the network again.
I guess images there are not frequently change them self. another image of Contact will be another file…
I wrote an answer to the somewhat similar problem some while ago, here is the link that you can check. The problem is in the approach of saving the images into the database, you should not be doing this. Instead, write the images as files on the phone memory and use it further.
Don't store Image to Sqlite Database eventually, you will ran into out of memory error after three or five image saved to database. It's not the best practice, maximum memory allocated for field in a row in sqlite is less than 3mb, be aware of this.
Instead of saving Images to database, Keep the images inside your app folder, save the path to the Database.
Your are loading your image as it is to your Image adapter. Let's say your image is 1280x720 resolution and 2mb in size, it will take the same space in your memory Heap.
You can either scaledown your image and load it as bitmap to your Adapter ImageView like this.
Before loading your image as Bitmap get it height and width.
//Code read the image and give you image height and width.it won't load your bitmap.
BitmapFactory.Options option = new BitmapFactory.Options();
option.inJustDecodeBounds = true;
BitmapFactory.decodeFile(your_image_url,option);
int image_original_width = option.outHeight;
int image_original_height = option.outWidth;
Now to scale down your Image you have to know the ImageView width and height. This is because we are going to scale down the image matching the imageview with pixel perfection.
int image_view_width = image_view.getWidht();
int image_view_height = image_view.getHeight();
int new_width;
int new_height;
float scaled_width;
if(image_original_width>image_view_width)
{ //if the image_view width is lesser than original_image_width ,you have to scaled down the image.
scale_value =(float)image_original_width/(float)image_view_width;
new_width = image_original_width/scaled_value;
new_height = image_orignal_height/scale_value
}
else
{
// use the image_view width and height as sacling value widht and height;
new_width = image_view_width;
new_height = image_view_height;
}
Now Scale Down your bitmap and load it like this.
// this will load a bitmap with 1/4 the size of the original one.
// this to lower your bitmap memory occupation in heap.
BitmapFactory.Options option = new BitmapFactory.Options();
option.inSampleSize = 4;
Bitmap current_bitmap = BitmapFactory.decodeFile(image_url,option);
Bitmap scaled_bitmap = Bitmap.createScaledBitmap(current_bitmap,new_width,new_height,true);
holder.imgIcon.setImageBitmap(scaled_bitmap);
//release memory occupied by current_bitmap in heap, as we are no longer using it.
current_bitmap.recycle();
If you want to understand a little more about Bitmap and memory view this link.
If you don't want to handle rescaling bitmap by yourself. you can use Glide or Picasso library which does the same.
I have written an article about using Picasso to load image in listview, which will help you to start, if you are looking to use picasso.
http://codex2android.blogspot.in/2015/11/picasso-android-example.html
Please make sure to use the quick garbage collection eligible reference type while loading the images from the network
import java.lang.ref.SoftReference;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import android.graphics.Bitmap;
public class MemoryCache {
private Map<String, SoftReference<Bitmap>> cache=Collections.synchronizedMap(new HashMap<String, SoftReference<Bitmap>>());
public Bitmap get(String id){
if(!cache.containsKey(id))
return null;
SoftReference<Bitmap> ref=cache.get(id);
return ref.get();
}
public void put(String id, Bitmap bitmap){
cache.put(id, new SoftReference<Bitmap>(bitmap));
}
public void clear() {
cache.clear();
}
}
Don't store Image to Sqlite Database. It's not the best practice.
Instead of saving Images to database, Keep the images in a storage, but if you want to keep them private then keep them inside your app folder and save the path to the Database.
Use one of the well known libraries like http://square.github.io/picasso/ or https://github.com/bumptech/glide, they offer great help with memory issues and also some cool transition effects.
I recommend using Glide because it works very well on device with low memory restrictions
Hi guys i have problem i need show image in EditText use : ImageGetter.
this work
String html = "<img src=\"ic_launcher\">";
CharSequence text = Html.fromHtml(html, new Html.ImageGetter(){
public Drawable getDrawable(String source){
int id = getResources().getIdentifier(source, "drawable", getPackageName());
Drawable d = getResources().getDrawable(id);
int w = d.getIntrinsicWidth();
int h = d.getIntrinsicHeight();
d.setBounds(0, 0, w, h);
return d;
}
}, null);
mContentEditText.setText(text);
but i need my image in SDcard ,not "R.drawable.IMAGE_NAME" ,Thanks
You have to apply the appropriate permissions in the manifest so that you can read from external storage. Then create a piece of code that will search your SD Card for the image you want.
Bitmap bitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath());
Where imageFile is your ImageFile, for example: File imageFile = new File("/sdcard/gallery_photo_4.jpg");
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mPath ="Your image Path here";
l1=(LinearLayout) findViewById(R.id.layout1);
l1.setBackgroundColor(Color.WHITE);
System.out.println(mPath);
Bitmap b=Bitmap.createScaledBitmap(BitmapFactory.decodeFile(mPath),l1.getWidth(),l1.getHeight(),false);
if(b!=null){
ImageView iv=new ImageView(this);
iv.setImageBitmap(b);
l2.addView(iv);
}
}
Here is the code which works for me.hope it will help you.
String html2 = "<img src=\"a.jpg\">";
CharSequence text2 = Html.fromHtml(html2, new Html.ImageGetter(){
public Drawable getDrawable(String source){
String path = "/sdcard/a/" + source;
File f = new File(path);
Drawable bmp = Drawable.createFromPath(f.getAbsolutePath());
bmp.setBounds(0, 0, bmp.getIntrinsicWidth(), bmp.getIntrinsicHeight());
return bmp;
}
}, null);
display.setText(text2);
is Work for me! 100% thx all :)
I am trying to read an image from /mnt/sdcard/img.jpg into ImageView.
Bitmap bm = BitmapFactory.decodeFile("/mnt/sdcard/img.jpg");
imageView1.setImageBitmap(bm);
I have write external storage permission.
But ImageView is empty, LogCat don't get any errors,
How can I fix it?
Try
File file = new File("/mnt/sdcard/img.jpg");
Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
imageview1.setImageBitmap(bitmap);