Android - Drag on LongClick with GridView - Unable to initiate drag - android

I'm developping a thumbnail mosaic of all pictures on SdCard.
If the user longclick on a picture, i want to start drag and drop process.
I clearly manage to get all images files and showing them with my own BaseAdapter in a GridView, but the process is long because I create previews of each image this way :
uri = Uri.fromFile(file);
try {
bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
if (bitmap != null) {
newBitmap = Bitmap.createScaledBitmap(bitmap, 200, 200, true);
bitmap.recycle();
// here code to add the bitmap to the adapter (see after)
}
} catch (IOException e) {
//Error fetching image, try to recover
}
So in order to avoid long wait, I'm loading the images in a AsyncTask.
The process work well and the images appears one by one, but now an error appear on LongClick, in this code :
mGrid.setOnItemLongClickListener(new OnItemLongClickListener()
{
public boolean onItemLongClick(AdapterView<?> adapter, View view, int position, long id)
{
ClipData data = ClipData.newPlainText("AdapterPosition", String.valueOf(position) );
view.startDrag(data, new DragShadowBuilder(view), null, 0);
return true;
}
});
and the error :
12-27 16:54:14.980: E/View(8089): Unable to initiate drag
12-27 16:54:14.980: E/View(8089): java.lang.NullPointerException
12-27 16:54:14.980: E/View(8089): at android.view.View.startDrag(View.java:11470)
12-27 16:54:14.980: E/View(8089): at renault.limandroid.widget.PartageWidgetActivity$9.onItemLongClick(PartageWidgetActivity.java:547)
Is someone have a idea?
Here is a large part of my code :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_partage_widget);
// ... //
mImageAdapter = new ImageAdapter(this);
loadImages();
mGrid.setOnItemLongClickListener(new OnItemLongClickListener()
{
public boolean onItemLongClick(AdapterView<?> adapter, View view, int position, long id)
{
ClipData data = ClipData.newPlainText("AdapterPosition", String.valueOf(position) );
view.startDrag(data, new DragShadowBuilder(view), null, 0);
return true;
}
});
mGrid.setAdapter(mImageAdapter);
}
private void loadImages()
{
// si c'est la première fois qu'on passe ici
if (mLoadImageTask.getStatus() == AsyncTask.Status.PENDING)
{
mLoadImageTask.execute();
}
// si le scan est terminé mais qu'on veut le remettre à jour
// on va recréer la tâche
else if (mLoadImageTask.getStatus() == AsyncTask.Status.FINISHED)
{
mLoadImageTask = new LoadImagesFromSDCard();
mLoadImageTask.execute();
}
}
#Override
protected Object doInBackground(Object... params) {
setProgressBarIndeterminateVisibility(true);
Log.d(TAG,"LoadImages - do in background");
Bitmap bitmap = null;
Bitmap newBitmap = null;
Uri uri = null;
List<File> listFiles = new ArrayList<File>();
listFiles = StorageManager.findImageFiles();
for (File file : listFiles)
{
// mImageListFile contains the files that have already been loaded
if (!mImageListFile.contains(file))
{
uri = Uri.fromFile(file);
try {
bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
if (bitmap != null) {
newBitmap = Bitmap.createScaledBitmap(bitmap, 200, 200, true);
bitmap.recycle();
if (newBitmap != null) {
publishProgress(new LoadedImage(newBitmap));
}
}
} catch (IOException e) {
//Error fetching image, try to recover
}
mImageListFile.add(file);
}
}
return null;
}
/**
* Add a new LoadedImage in the images grid.
*
* #param value The image.
*/
#Override
public void onProgressUpdate(LoadedImage... value)
{
mImageAdapter.addPhoto(value[0]);
mImageAdapter.notifyDataSetChanged();
}
/**
* Set the visibility of the progress bar to false.
*
* #see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
#Override
protected void onPostExecute(Object result)
{
setProgressBarIndeterminateVisibility(false);
mGrid.invalidate();
}
}
class ImageAdapter extends BaseAdapter {
private Context mContext;
private ArrayList<LoadedImage> photos = new ArrayList<LoadedImage>();
public ImageAdapter(Context context) {
mContext = context;
photos.add(new LoadedImage(BitmapFactory.decodeResource(context.getResources(),
R.drawable.click)));
}
public void addPhoto(LoadedImage photo)
{
photos.add(photo);
}
public int getCount() {
return photos.size();
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent)
{
final ImageView imageView;
final int pos = position;
if (convertView == null) {
imageView = new ImageView(mContext);
} else {
imageView = (ImageView) convertView;
}
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
imageView.setPadding(2, 2, 2, 2);
imageView.setLayoutParams(new GridView.LayoutParams(parent.getWidth()/4, parent.getWidth()/4));
imageView.setImageBitmap(photos.get(position).getBitmap());
return imageView;
}
public Object getItem(int position)
{
return photos.get(position);
}
}
/**
* A LoadedImage contains the Bitmap loaded for the image.
*/
private static class LoadedImage {
Bitmap mBitmap;
LoadedImage(Bitmap bitmap) {
mBitmap = bitmap;
}
public Bitmap getBitmap() {
return mBitmap;
}
}

Related

Android App - Selecting Image from Phone Gallery and Adding it to a ListView

I am using a custom adapter in order to add a selected image to the ListView. I get this error:
04-29 18:15:33.582: E/AndroidRuntime(24214): java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setImageBitmap(android.graphics.Bitmap)' on a null object reference
04-29 18:15:33.582: E/AndroidRuntime(24214): at app.photoexpress.ViewAlbumActivity$ImageAdapter.getView(ViewAlbumActivity.java:240)
When a photo is added from the gallery, I create a new Photo object and store the given Bitmap in there. And my getBitmap() method calls that but apparently it is null in this case. Not sure what s wrong here
Here is my Code:
public class ViewAlbumActivity extends AppCompatActivity {
ListView listview;
ImageAdapter adapter;
CharSequence[] images;
int width = 250;
boolean isSearch = false;
// ArrayList<String> listItems = new ArrayList<String>();
TextView title;
Album album;
ArrayList<Album> albumList;
String albumName = "Album";
Album currentlySelectedAlbum;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);
// get bundle
Bundle bundle = getIntent().getExtras();
if (bundle != null) {
albumList = (ArrayList<Album>) bundle.getSerializable("albums");
albumName = bundle.getString("albumName");
album = Album.findAlbum(albumName, getBaseContext());
Log.e(".", album.getName());
setTitle(albumName);
} else {
album = new Album("placeholder");
}
currentlySelectedAlbum = Album.findAlbum(albumName, getBaseContext());
ArrayList<Photo> photoList = currentlySelectedAlbum.getPhotos();
// Displays the icon and album name in the action bar
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setLogo(R.drawable.ic_launcher);
getSupportActionBar().setDisplayUseLogoEnabled(true);
listview = (ListView) findViewById(R.id.listView1);
adapter = new ImageAdapter(this, photoList);
listview.setAdapter(adapter);
// images = readPhotoList();
// Display display = this.getWindowManager().getDefaultDisplay();
// width = display.getWidth();
// width=width/2-15;
/*listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(ViewAlbumActivity.this, ViewPhotoActivity.class);
// intent.putExtra(name, value)
intent.putExtra("index", position);
intent.putExtra("albumname", albumName);
intent.putExtra("album", album);
intent.putExtra("isSearch", isSearch);
startActivity(intent);
}
});*/
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
if (!isSearch) {
getMenuInflater().inflate(R.menu.viewalbum, 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.
if (!isSearch) {
int id = item.getItemId();
if (id == R.id.addPhoto) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 1);
// addPhoto();
return true;
}
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
Uri targetUri = data.getData();
// textTargetUri.setText(targetUri.toString());
Bitmap bitmap;
try {
bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(targetUri));
//image.setImageBitmap(bitmap);
Photo photo = new Photo(bitmap);
currentlySelectedAlbum.addPhoto(photo);
Album.updateAlbumList(currentlySelectedAlbum, getBaseContext());
adapter.notifyDataSetChanged();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/*
* private String[] readPhotoList() { String path =
* Environment.getExternalStorageDirectory().getAbsolutePath() + "/photos/";
*
* File dir = new File(path);
*
* File[] filelist = dir.listFiles();
*
* if (filelist == null) { String[] z = new String[1]; z[0] = "no file in "
* + path; return z; }
*
* if (filelist.length == 0) { String[] s = new String[1]; s[0] =
* "no image file under " + path; return s; } ArrayList<String> result = new
* ArrayList<String>(); for (int i = 0; i < filelist.length; i++) { if
* (BitmapFactory.decodeFile(path + filelist[i].getName()) != null) {
* result.add(filelist[i].getName()); } } String[] convertList = new
* String[result.size()]; for (int i = 0; i < result.size(); i++) {
* convertList[i] = result.get(i); } return convertList;
*
* }
*/
/////////////
class ImageAdapter extends BaseAdapter {
private Context mContext;
public ArrayList<Photo> photoList2;
public ImageAdapter(Context c, ArrayList<Photo> photoList) {
mContext = c;
this.photoList2 = photoList;
}
public int getCount() {
int returnInt = 0;
try {
returnInt = currentlySelectedAlbum.getPhotos().size();
} catch (NullPointerException e) {
Log.e("NullPointerError", ".");
}
return returnInt;
}
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) {
ImageView imageView = new ImageView(mContext);
View vi = convertView;
// String fileName="";
if (convertView == null) {
/*imageView = new ImageView(mContext);
imageView.setLayoutParams(new ListView.LayoutParams(width, width));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(0, 0, 0, 0);*/
LayoutInflater inflator = (LayoutInflater)ViewAlbumActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
vi = inflator.inflate(R.layout.customimageview, parent, false);
} /*else {
imageView = (ImageView) convertView;
}
// if there is any photo
if (album.getPhotos().size() != 0) {
// final String fileName =
// album.getPhotos().get(position).getName();
// showImgFromSD("/photos/" + fileName, imageView);
// showImgFromSD("/photos/002.jpg",imageView);
}*/
Bitmap bitmap = photoList2.get(position).getBitmap();
ImageView thumbnail = (ImageView)vi.findViewById(R.id.imageView1);
thumbnail.setImageBitmap(bitmap);
return imageView;
}
/*
* private void showImgFromSD(String fileName, ImageView iv) { File f =
* new File(Environment.getExternalStorageDirectory(), fileName);
* FileInputStream input = null;
*
* try { input = new FileInputStream(f); } catch (FileNotFoundException
* e) { // toastMsg("File: " + fileName + " not found"); return; }
* Bitmap pic = BitmapFactory.decodeStream(input, null, null);
* iv.setImageBitmap(pic);
*
* }
*/
}
/*
* private void addPhoto() { final CharSequence[] options = images;
* AlertDialog.Builder build = new
* AlertDialog.Builder(ViewAlbumActivity.this);
* build.setTitle("../sdcard/photos/"); build.setItems(options, new
* DialogInterface.OnClickListener() { public void onClick(DialogInterface
* dialog, int item) { Album tempAlbum = findAlbum(albumName, albumList);
* Album allPhotos = findAlbum("All Photos", albumList); List<Photo> Photos
* = tempAlbum.getPhotos();
*
* for (Photo p : Photos) { //if (p.getName().compareToIgnoreCase((String)
* options[item]) == 0) { toastMsg(options[item] + " already in album");
* return; } } //Photo tempPhoto = new Photo((String) options[item], "");
* tempAlbum.addPhoto(tempPhoto); allPhotos.addPhoto(tempPhoto);
*
* // SERIALIZE HERE
*
* // listItems.add((String) options[item]); adapter.notifyDataSetChanged();
* listview.invalidateViews(); toastMsg(options[item] + " added.");
*
* } }); AlertDialog alert = build.create(); alert.show(); }
*/
// handles pop up messages
private void toastMsg(String msg) {
Context context = getApplicationContext();
CharSequence text = msg;
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
}
Album.java:
public class Album implements Serializable {
/**
*
*/
private static final long serialVersionUID = -7593044560206879666L;
String name;
static ArrayList<Photo> photos;
boolean previouslySelected = false;
public Album() {
photos = new ArrayList<Photo>();
}
public Album(String name) {
this.name = name;
photos = new ArrayList<Photo>();
}
public String toString() {
return name;
}
public String getName() {
return name;
}
public static ArrayList<Album> deleteAlbum(int position, Context context) {
ArrayList<Album> albumList = new ArrayList<Album>();
albumList = SerializableManager.readSerializable(context, "albumList.ser");
albumList.remove(albumList.get(position));
return albumList;
}
public static ArrayList<Album> addAlbum(Album a, Context context) {
ArrayList<Album> albumList = new ArrayList<Album>();
albumList = SerializableManager.readSerializable(context, "albumList.ser");
for (Album i : albumList) {
if (i.getName().equalsIgnoreCase(a.getName())) {
Log.e("Not Added", "Album not added because it already exists.");
CreateNewAlbumActivity.toastMsg("Not added. Album already exists.");
return albumList;
}
}
albumList.add(a);
return albumList;
}
public static void updateAlbumList(Album a, Context context){
ArrayList<Album> albumList = SerializableManager.readSerializable(context, "albumList.ser");
for (int i = 0; i < albumList.size(); i++){
if (albumList.get(i).getName().equals(a.getName())){
albumList.remove(i);
albumList.add(a);
}
}
SerializableManager.saveSerializable(context, albumList, "albumList.ser");
}
public static boolean doesAlbumExist(String name, Context context) {
ArrayList<Album> albumList = SerializableManager.readSerializable(context, "albumList.ser");
for (Album i : albumList) {
if (i.getName().equalsIgnoreCase(name)) {
return true;
}
}
return false;
}
public static Album findAlbum(String name, Context context) {
ArrayList<Album> albumList = SerializableManager.readSerializable(context, "albumList.ser");
for (Album i : albumList) {
if (i.getName().equalsIgnoreCase(name)) {
return i;
}
}
return null;
}
public static ArrayList<Album> renameAlbum(String oldName, String newName, Context context) {
ArrayList<Album> albumList = new ArrayList<Album>();
albumList = SerializableManager.readSerializable(context, "albumList.ser");
for (Album i : albumList) {
if (i.getName().equalsIgnoreCase(oldName)) {
Log.e(".", "match found");
if (!doesAlbumExist(newName, context)) {
i.rename(newName);
}
}
}
return albumList;
}
public void rename(String newName) {
this.name = newName;
}
public ArrayList<Photo> getPhotos() {
return photos;
}
public void addPhoto(Photo p) {
photos.add(p);
return;
}
}
Photo.java
public class Photo implements Serializable{
// The Constant storeDir.
public static final String storeDir = "data\\photo";
int id;
String Caption;
Bitmap bitmap;
List<Tag> Tags = new ArrayList <Tag>();
public Photo(Bitmap bitmap) {
id = 1 + (int)(Math.random() * 5000);
this.bitmap = bitmap;
}
public Photo(String caption, Bitmap bitmap) {
Caption = caption;
id = 1 + (int)(Math.random() * 5000);
this.bitmap = bitmap;
}
public void setCaption(String input)
{
Caption = input;
}
public boolean hasTag( String type, String value)
{
for(Tag s: Tags )
{
if(s.Type.compareToIgnoreCase(type) == 0 && s.value.compareToIgnoreCase(value) == 0 )
{
return true;
}
}
return false;
}
public boolean addTag( String type, String value)
{
//if tag already there error
if(!hasTag(type,value))
{
Tags.add(new Tag(value,type));
return true;
}
else
return false;
}
public boolean deleteTag( String type, String value)
{
int count = 0;
for(Tag s: Tags )
{
if(s.Type.compareToIgnoreCase(type) == 0 && s.value.compareToIgnoreCase(value) == 0 )
{
Tags.remove(count);
return true;
}
count++;
}
return false;
}
#Override
public String toString()
{
return "no";
}
public List<Tag> getTags()
{
return Tags;
}
public String getCaption()
{
return Caption;
}
public Bitmap getBitmap(){
return bitmap;
}
#Override
public boolean equals(Object o)
{
if (o==null)
{
return false;
}
if(!(o instanceof Photo)) {return false;}
Photo other = (Photo)o;
return (true);
//FIX THIS
}
}
customimageview.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Based upon your stacktrace you start with it looks like the error happens on this line (A bit hard without knowing that this is actually line 240):
thumbnail.setImageBitmap(bitmap);
As your error is a NullPointer it means that thumbnail is null and that tells us that:
ImageView thumbnail = (ImageView)vi.findViewById(R.id.imageView1);
Fails to find an ImageView. So to get to the root we would need to see the xml of:
R.layout.customimageview
But it seems likely that there is no imageView with the ID of imageView1 in there. If there is none adding one should solve the nullpointer.
If this is not the case and there is an ImageView in there we will keep on investigating. :) (but post your xml then as well and please confirm exactly which line 240 is.)
Edit:
Also looking on your code your adapter is not fully implemented and you will probably get other errors later if this is not fixed. For example the methods getItem and getItemId.
getItem should probably look something like this:
public Object getItem(int position) {
return photolist2.get(position);
}
and getItemId:
public long getItemId(int position) {
return position;
}
Edit2:
Also, while Serializable is handy and easy it does come with some negative aspects, for example speed on Android and it could be good to look up Parceble and to help you with the boilderplate code: https://github.com/johncarl81/parceler. But that's for a later time ;)
Edit 3:
Looking more on the Adapter code it contained a few errors, this should be closer to what you want:
class ImageAdapter extends BaseAdapter {
private Context mContext;
public ArrayList<Photo> photoList2;
public ImageAdapter(Context c, ArrayList<Photo> photoList) {
mContext = c;
this.photoList2 = photoList;
}
public int getCount() {
int returnInt = 0;
try {
returnInt = currentlySelectedAlbum.getPhotos().size();
} catch (NullPointerException e) {
Log.e("NullPointerError", ".");
}
return returnInt;
}
public Object getItem(int position) {
return photoList2.get(position);
}
public long getItemId(int position) {
return position;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
View vi;
// String fileName="";
if (convertView == null) {
/*imageView = new ImageView(mContext);
imageView.setLayoutParams(new ListView.LayoutParams(width, width));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(0, 0, 0, 0);*/
LayoutInflater inflator = (LayoutInflater)ViewAlbumActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
vi = inflator.inflate(R.layout.customimageview, parent, false);
} else {
vi = convertView;
}
Bitmap bitmap = photoList2.get(position).getBitmap();
ImageView thumbnail = (ImageView)vi.findViewById(R.id.imageView1);
thumbnail.setImageBitmap(bitmap);
return vi;
}
So what's the difference? In your adaptor you create and ImageView at the top and return that view at the end. So when Android calls getView again with the convertView, the convertView now holds that ImageView object and not a view of customimageview that you created. So when vi.findViewByid was called it was trying to find an ImageView inside an ImageView, and therefore failed.

Implement expansion files in Wallpaper Chooser

I've an app on Google Play that contains wallpapers (it's a wallpaper chooser) that still uses Gallery (http://developer.android.com/reference/android/widget/Gallery.html, yes, it's an old app). I'm trying to implement apk expansion files to break the 50MB limit.
Right now in-app downloader and .obb download from GP works very well. I can find it in /Android/obb. I still can't ready wallpapers from .obb file. I tried APK Expansion Zip Library but I don't know how to use it with a Gallery...
This is my wallpaper.java file:
public class wallpaper extends Activity implements AdapterView.OnItemSelectedListener,
OnClickListener {
private Gallery mGallery;
private ImageView mImageView;
private TextView mInfoView;
private boolean mIsWallpaperSet;
private Bitmap mBitmap;
private ArrayList<Integer> mThumbs;
private ArrayList<Integer> mImages;
private WallpaperLoader mLoader;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
// Start wallpaper app
requestWindowFeature(Window.FEATURE_NO_TITLE);
findWallpapers();
setContentView(R.layout.wallpaper_chooser);
mGallery = (Gallery) findViewById(R.id.gallery);
mGallery.setAdapter(new ImageAdapter(this));
mGallery.setOnItemSelectedListener(this);
mGallery.setCallbackDuringFling(false);
findViewById(R.id.set).setOnClickListener(this);
mImageView = (ImageView) findViewById(R.id.wallpaper);
mInfoView = (TextView) findViewById(R.id.info);
}
private void findWallpapers() {
mThumbs = new ArrayList<Integer>(24);
mImages = new ArrayList<Integer>(24);
final Resources resources = getResources();
final String packageName = getApplication().getPackageName();
addWallpapers(resources, packageName, R.array.wallpapers);
addWallpapers(resources, packageName, R.array.extra_wallpapers);
}
private void addWallpapers(Resources resources, String packageName, int list) {
final String[] extras = resources.getStringArray(list);
for (String extra : extras) {
int res = resources.getIdentifier(extra, "drawable", packageName);
if (res != 0) {
final int thumbRes = resources.getIdentifier(extra + "_small",
"drawable", packageName);
if (thumbRes != 0) {
mThumbs.add(thumbRes);
mImages.add(res);
}
}
}
}
#Override
protected void onResume() {
super.onResume();
mIsWallpaperSet = false;
}
#Override
protected void onDestroy() {
super.onDestroy();
if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
mLoader.cancel(true);
mLoader = null;
}
}
public void onItemSelected(AdapterView parent, View v, int position, long id) {
if (mLoader != null && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
mLoader.cancel();
}
mLoader = (WallpaperLoader) new WallpaperLoader().execute(position);
}
/*
* When using touch if you tap an image it triggers both the onItemClick and
* the onTouchEvent causing the wallpaper to be set twice. Ensure we only
* set the wallpaper once.
*/
private void selectWallpaper(int position) {
if (mIsWallpaperSet) {
return;
}
mIsWallpaperSet = true;
try {
InputStream stream = getResources().openRawResource(mImages.get(position));
setWallpaper(stream);
setResult(RESULT_OK);
finish();
} catch (IOException e) {
Log.e("Paperless System", "Failed to set wallpaper: " + e);
}
}
public void onNothingSelected(AdapterView parent) {
}
private class ImageAdapter extends BaseAdapter {
private LayoutInflater mLayoutInflater;
ImageAdapter(wallpaper context) {
mLayoutInflater = context.getLayoutInflater();
}
public int getCount() {
return mThumbs.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView image;
if (convertView == null) {
image = (ImageView) mLayoutInflater.inflate(R.layout.wallpaper_item, parent, false);
} else {
image = (ImageView) convertView;
}
int thumbRes = mThumbs.get(position);
image.setImageResource(thumbRes);
Drawable thumbDrawable = image.getDrawable();
if (thumbDrawable != null) {
thumbDrawable.setDither(true);
} else {
Log.e("Paperless System", String.format(
"Error decoding thumbnail resId=%d for wallpaper #%d",
thumbRes, position));
}
return image;
}
}
public void onClick(View v) {
selectWallpaper(mGallery.getSelectedItemPosition());
}
class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
BitmapFactory.Options mOptions;
WallpaperLoader() {
mOptions = new BitmapFactory.Options();
mOptions.inDither = false;
mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
}
protected Bitmap doInBackground(Integer... params) {
if (isCancelled()) return null;
try {
return BitmapFactory.decodeResource(getResources(),
mImages.get(params[0]), mOptions);
} catch (OutOfMemoryError e) {
return null;
}
}
#Override
protected void onPostExecute(Bitmap b) {
if (b == null) return;
if (!isCancelled() && !mOptions.mCancel) {
// Help the GC
if (mBitmap != null) {
mBitmap.recycle();
}
mInfoView.setText(getResources().getStringArray(R.array.info)[mGallery.getSelectedItemPosition()]);
final ImageView view = mImageView;
view.setImageBitmap(b);
mBitmap = b;
final Drawable drawable = view.getDrawable();
drawable.setFilterBitmap(true);
drawable.setDither(true);
view.postInvalidate();
mLoader = null;
} else {
b.recycle();
}
}
void cancel() {
mOptions.requestCancelDecode();
super.cancel(true);
}
}
Wallpapers are defined in res/values/wallpapers.xml:
<resources>
<string-array name="wallpapers" translatable="false">
<item>wallpaper1</item>
<item>wallpaper2</item>
<item>wallpaper3</item>
[...]
</string-array>
<string-array name="info" translatable="false">
<item>wallpaper1 description</item>
<item>wallpaper2 description</item>
<item>wallpaper3 description</item>
[...]
</string-array>
How can I change patch of my wallpapers from /res/drawable to /obb/com.example.app/main.8.com.example.app.obb ?
Thanks in advance for your help!
First read about APK expansion files here: http://developer.android.com/google/play/expansion-files.html
Then, read more about using Gallery widget here: http://developer.android.com/reference/android/widget/Gallery.html
Finally, consider using a ViewPager, referenced from here: http://developer.android.com/training/implementing-navigation/lateral.html
I am not sure if you should ask questions like that, please correct me if I am wrong..

fetching multiple image from urls

I have an application which allow to download 3 images and show them into a gallery
In order to do this , i use a thread in order to download the images and a handler in order to put the images into the gallery
The problem is that the images are not displayed(imageviews are empty) into the gallery (even if i see 3 imageview for my 3 images)
I do not know if this is because the connection is very slow (I develop on a mobile) or if it's because the ui is displayed before images are downloaded
Thank you very much for your help
public class ChoiceLanguage extends Activity {
private TextView nomLangue;
private ArrayList<Language> listeLangues;
private ArrayList<String> listImages;
private Gallery gallery;
private String URL="******************";
private Drawable mNoImage;
Bitmap bitmap;
ImageView imgView = null;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.choice_language);
listeLangues= getIntent().getParcelableArrayListExtra("listeLangues");
listImages=buildListImages();
gallery = (Gallery) findViewById(R.id.galleryImg);
gallery.setAdapter(new AddImgAdp(this));
gallery.setSpacing(10);
gallery.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int position, long id) {
System.out.println("URL "+ listImages.get(position) );
}
});
}
private InputStream openHttpConnection(String urlString) throws IOException {
InputStream in = null;
URL url = new URL(urlString);
URLConnection conn = url.openConnection();
conn.connect();
in=conn.getInputStream();
return in;
}
private Bitmap downloadImage( ImageView iView, String url) {
Bitmap bitmap = null;
InputStream in = null;
BufferedInputStream bis ;
try {
in = openHttpConnection(url);
bis= new BufferedInputStream(in, 8192);
bitmap = BitmapFactory.decodeStream(bis);
bis.close();
in.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return bitmap;
}
private ArrayList<String> buildListImages() {
ArrayList<String> listImg = new ArrayList<String>();
for(Language l : listeLangues) {
listImg.add(URL+l.getImagePath());
}
return listImg;
}
public class AddImgAdp extends BaseAdapter {
int GalItemBg;
private Context cont;
public AddImgAdp(Context c) {
cont = c;
TypedArray typArray = obtainStyledAttributes(R.styleable.GalleryTheme);
GalItemBg = typArray.getResourceId(R.styleable.GalleryTheme_android_galleryItemBackground, 0);
typArray.recycle();
}
public int getCount() {
return listImages.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
imgView = new ImageView(cont);
} else {
imgView = (ImageView)convertView;
}
ThreadDownload progressDl= new ThreadDownload(position);
progressDl.start();
imgView.setLayoutParams(new Gallery.LayoutParams(150, 150));
imgView.setScaleType(ImageView.ScaleType.FIT_XY);
imgView.setBackgroundResource(GalItemBg);
return imgView;
}
}
private class SetImg extends Handler {
public void handleMessage(Message msg) {
imgView.setImageBitmap(bitmap);
}
}
private class ThreadDownload extends Thread {
SetImg img= new SetImg();
int position ;
public ThreadDownload(int position)
{
super();
this.position=position;
}
public void run() {
bitmap = downloadImage(imgView,listImages.get(position));
img.sendEmptyMessage(0);
}
}
}
You can make use of SmartImageView, it is a drop-in replacement for Android’s standard ImageView which additionally allows images to be loaded from URLs or the user’s contact address book. Images are cached to memory and to disk for super fast loading.
https://github.com/loopj/android-smart-image-view

getView is called several times for the first position in GridView

I have an adapter with this getView:
public View getView(int position, View convertView, ViewGroup parent) {
Log.d("getView gv", position+"");
NewsLine holder = null;
if (convertView == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
convertView = inflater.inflate(R.layout.grid_entry, parent, false);
holder = new NewsLine();
holder.iv= (ImageView) convertView.findViewById(R.id.photo);
convertView.setTag(holder);
} else {
holder = (NewsLine) convertView.getTag();
}
NewsItem item=news.ITEMS.get(position);
//---------
if(item.imgurl!=null && item.imgurl.compareToIgnoreCase("null")!=0)
{
holder.iv.setVisibility(View.VISIBLE);
mMemoryCache.loadBitmap(item.imgurl, holder.iv,position);
}
else
holder.iv.setVisibility(View.INVISIBLE);
//-------------
return convertView;
}
I have two problems:
the getView is called several times for position 0 (the bitmap is downloaded with an AsyncTask if its missed in a LruCache). I have an animation (alpha from 0-1) that restarts several times for that position.
because I'm recycling the view sometimes you can see the old imageView content for a fraction of a second.
//----
And here is the cache class (only heap):
public class SetImgAT extends LruCache<String, Bitmap> {
private static SetImgAT instance;
private Animation FadeInAnimation;
private SetImgAT(int size, Context context) {
super(size);
FadeInAnimation = AnimationUtils.loadAnimation(context, R.anim.fadein);
}
public static synchronized SetImgAT getInstance(int size, Context context) {
if (instance == null) {
instance = new SetImgAT(size, context);
}
return instance;
}
#Override
protected int sizeOf(String key, Bitmap value) {
return (value.getRowBytes() * value.getHeight());
}
public void loadBitmap(String url, ImageView imageView,int pos) {
Bitmap bitmap = instance.get(url.hashCode() + "");
if (bitmap != null) {
Log.d("ImageCache", "hit - "+url.hashCode()+"pos:"+pos);
imageView.setImageBitmap(bitmap);
imageView.invalidate();
} else {
Log.d("ImageCache", "miss");
BitmapWorkerTask task = new BitmapWorkerTask(imageView);
task.execute(url);
}
}
class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {
ImageView mImageView;
public BitmapWorkerTask(ImageView imageView) {
mImageView = imageView;
}
#Override
protected Bitmap doInBackground(String... url) {
Bitmap Picture = null;
if (url[0] != null && url[0].compareToIgnoreCase("null") != 0) {
Log.d("GetBMP from", url[0]);
URL img_value = null;
try {
img_value = new URL(url[0]);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Picture = BitmapFactory.decodeStream(img_value
.openConnection().getInputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (Picture == null) {
Log.d("deb", "no bitmap");
} else {
Log.d("got deb", "got bitmap to "+url[0].hashCode());
instance.put(url[0].hashCode()+"", Picture);
}
}
return Picture;
}
#Override
protected void onPostExecute(Bitmap result) {
// super.onPostExecute(result);
if (result != null) {
Log.d("deb", "set bitmap");
mImageView.setImageBitmap(result);
//mImageView.startAnimation(FadeInAnimation);
}
}
}
//----------------
}
Thank you! :)
I've seen similar behavior when scrolling back and forth or haphazardly calling notifyDataSetChanged().
As an enhancement to what you are doing now I would suggest using Picasso instead since it handles this case very well, in addition to the fade in animation.
A one liner in your getView():
Picasso.with(context).load(urlToLoad).into(imageView);
See:
http://square.github.io/picasso/

GridView + CursorAdapter + AsyncTask load image shifting randomly

I use SimpleCursorAdapter and GridActivity (extended Activity written by me based on ListActivity) to load music albums from MediaStore, and use AsyncTask load each album art .
I tried this in bindView or getView, like this:
new AsyncAlbumArtLoader(viewholder.album_art, mShowFadeAnimation).execute(aid, width, height);
class AsyncAlbumArtLoader:
private class AsyncAlbumArtLoader extends AsyncTask<Object, Void, Bitmap> {
boolean enable_animation = false;
private ImageView imageview;
public AsyncAlbumArtLoader(ImageView imageview, Boolean animation) {
enable_animation = animation;
this.imageview = imageview;
}
#Override
protected void onPreExecute() {
if (enable_animation) {
imageview.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(),
android.R.anim.fade_out));
imageview.setVisibility(View.INVISIBLE);
}
}
#Override
protected Bitmap doInBackground(Object... params) {
return MusicUtils.getCachedArtwork(getApplicationContext(), (Long) params[0],
(Integer) params[1], (Integer) params[2]);
}
#Override
protected void onPostExecute(Bitmap result) {
if (result != null) {
imageview.setImageBitmap(result);
} else {
imageview.setImageResource(R.drawable.albumart_mp_unknown_list);
}
if (enable_animation) {
imageview.setVisibility(View.VISIBLE);
imageview.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(),
android.R.anim.fade_in));
}
}
}
But images shifting between gridview items randomly.
You can see screen record video here.
edited prevent this error by setTag() and getTag() is also no effect.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
mAlbumCursor.moveToPosition(position);
ViewHolder viewholder = (ViewHolder) view.getTag();
String album_name = mAlbumCursor.getString(mAlbumIndex);
if (album_name == null || MediaStore.UNKNOWN_STRING.equals(album_name)) {
viewholder.album_name.setText(R.string.unknown_album_name);
} else {
viewholder.album_name.setText(album_name);
}
String artist_name = mAlbumCursor.getString(mArtistIndex);
if (album_name == null || MediaStore.UNKNOWN_STRING.equals(album_name)) {
viewholder.artist_name.setText(R.string.unknown_artist_name);
} else {
viewholder.artist_name.setText(artist_name);
}
// We don't actually need the path to the thumbnail file,
// we just use it to see if there is album art or not
long aid = mAlbumCursor.getLong(mAlbumIdIndex);
int width = getResources().getDimensionPixelSize(R.dimen.gridview_bitmap_width);
int height = getResources().getDimensionPixelSize(R.dimen.gridview_bitmap_height);
viewholder.album_art.setTag(aid);
new AsyncAlbumArtLoader(viewholder.album_art, mShowFadeAnimation, aid, width, height).execute();
long currentalbumid = MusicUtils.getCurrentAlbumId();
if (currentalbumid == aid) {
viewholder.album_name.setCompoundDrawablesWithIntrinsicBounds(0, 0,
R.drawable.ic_indicator_nowplaying_small, 0);
} else {
viewholder.album_name.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
}
return view;
}
// FIXME image loaded some times incorrect
private class AsyncAlbumArtLoader extends AsyncTask<Object, Void, Bitmap> {
boolean enable_animation = false;
private ImageView imageview;
private long album_id;
private int width,height;
public AsyncAlbumArtLoader(ImageView imageview, Boolean animation, long album_id, int width, int height) {
enable_animation = animation;
this.imageview = imageview;
this.album_id = album_id;
this.width = width;
this.height = height;
}
#Override
protected void onPreExecute() {
if (imageview.getTag() == null || (Long)imageview.getTag() != album_id) {
return;
}
if (enable_animation) {
imageview.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(),
android.R.anim.fade_out));
imageview.setVisibility(View.INVISIBLE);
}
}
#Override
protected Bitmap doInBackground(Object... params) {
if (imageview.getTag() == null || (Long)imageview.getTag() != album_id) {
return null;
}
return MusicUtils.getCachedArtwork(getApplicationContext(), album_id,
width, height);
}
#Override
protected void onPostExecute(Bitmap result) {
if (imageview.getTag() == null || (Long)imageview.getTag() != album_id) {
return;
}
if (result != null) {
imageview.setImageBitmap(result);
} else {
imageview.setImageResource(R.drawable.albumart_mp_unknown_list);
}
if (enable_animation) {
imageview.setVisibility(View.VISIBLE);
imageview.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(),
android.R.anim.fade_in));
}
}
}
The Problem is, that the AsyncTask don't know für which ImageView they where started, respectivley they overlap.
To prevent this you need to do the following:
In your getView Method (before calling the AsyncTask-Constructor you need so set a Tag to your ImageView: myImageView.setTag(object). The best choice is, if you use the object from which getView gets its information. In you case i think it is the ArrayList with the Album-Information. Let' say myImageView.setTag(myAlbumArray.get(position)) THE TAG MUST BE UNIQUE
Now add a new String 'tag' to your AsyncTask class and add this.tag = imageview.getTag().toString().
Now finally add the test in your onPostExecute:
if (imageview.getTag().toString().equals(tag)) {
// you got the right imageView, *your PostExecute Code* }
else {// wrong one, do nothing
}

Categories

Resources