i have a big doubt about memory leak and screen rotation. I know that activity is destroy when that happens and new one is started. With my code, with is the best way to show the gridview? (this activity is part of a tab activity so in the main one i get the pictures from web services and put them on the object, using AsyncTask)
i would like to show the pictures at the same time they are saved on the object. Like simulating ajax...is that possible? at the moment, they are all show on the start or resume.
Also, im facing memory leak here?
last question, how can i show photos in the grid
my code:
public class LoteFotosActivity extends Activity {
Sistema sis=Sistema.getInstance();
Lote lote;
GridView gridview;
ImageAdapter iA;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lote_foto_view);
Bundle extras = getIntent().getExtras();
lote=sis.getLoteDetalle(extras.getInt("LoteID"));
gridview = (GridView) findViewById(R.id.gridview);
gridview.setAdapter(iA=new ImageAdapter(this));
gridview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
Toast.makeText(LoteFotosActivity.this, "" + position, Toast.LENGTH_SHORT).show();
}
});
}
public class ImageAdapter extends BaseAdapter {
private Context mContext;
public ImageAdapter(Context c) {
mContext = c;
}
public int getCount() {
return lote.FOTOS.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
// create a new ImageView for each item referenced by the Adapter
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) { // if it's not recycled, initialize some attributes
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(200,200));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
}
imageView.setImageBitmap(lote.FOTOS.get(position));
return imageView;
}
}
//test looking
public void onResume() {
super.onResume();
Toast.makeText(this,"ON RESUME",
Toast.LENGTH_SHORT).show();
// gridview.setAdapter(new ImageAdapter(this));
// foto.setImageDrawable(lote.FOTOS.get(0));
}
public void onPause() {
super.onPause();
Toast.makeText(this,"onPause",
Toast.LENGTH_SHORT).show();
iA=null;
gridview.setAdapter(iA=new ImageAdapter(this));
// foto.setImageDrawable(lote.FOTOS.get(0));
}
thx in advance !
I think you should add this to your activity
android:configChanges="orientation"
to avoid the destroying problem when rotating the screen... with this you dont need to save state to restore, there is no need because the activity is not destroyed and recreated everytime the screen rotation changes
For API 13+ the screenSize must also be handled:
android:configChanges="orientation|screenSize"
Related
I have a custom Listview with an ImageView for drawing. In my Mainactivity I start a thread which redraws the ImageView in my Listview every 20ms.
The ImageView is only refreshed when I call adapter.notifyDataSetChanged(); in my Listfragment.
This works fine, but my problem is, that onListItemClick only fires sometimes in this case. When I remove the adapter.notifyDataSetChanged(), onListItemClick fires always but now, my ImageViews are not refreshed.
Here the important parts of my code:
public class FragmentOscilloscope extends ListFragment
{
private ListViewAdapter adapter;
private List<ListViewItem> rowItems;
private Handler sampleUpdateHandler = null;
#Override
public void onActivityCreated(Bundle savedInstanceState)
{
sampleUpdateHandler = new Handler();
}
public void InitFragment()
{
adapter = new ListViewAdapter(getActivity(), rowItems);
setListAdapter(adapter);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id)
{
super.onListItemClick(l, v, position, id);
Log.d("FragmentOscilloscope", "onListItemClick");
}
public void UpdateOscilloscope(final PositionMarker pos)
{
for (int i = 0; i < listItems; i++);
{
Canvas canvas = rowItems.get(i).getCanvas();
// do the drawings
}
sampleUpdateHandler.post(new Runnable()
{
#Override
public void run()
{
adapter.notifyDataSetChanged();
}
});
}
}
This is my getView() in my ListViewAdapter:
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
ListViewItem row_pos = rowItem.get(position);
if (convertView == null)
{
convertView = mInflater.inflate(R.layout.oscilloscope_list_item, parent, false);
}
imageView = (ImageView) convertView.findViewById(R.id.osc_image);
imageView.setImageBitmap(row_pos.getBitmap());
row_pos.setImageView(imageView);
return convertView;
}
Can someone help me with this? I´m really frustrated... Thanks!
You can also find the full code of the described behavior here:
Android ListFragment update/refresh and onItemClick
When I remove the adapter.notifyDataSetChanged(), onListItemClick fires always but now, my ImageViews are not refreshed.
when you call notifyDataSetChanged(), items in your listview will be init and draw again. The main cause the onListItemClick fires sometimes because at that time your UI thread was VERY BUSY, it's processing other tasks and onListItemClick command will be put on the task queue to process.
I guess that in the getView() from adapter you do very heavy tasks, Try to improve it or create Thread/AsynTask for heavy processes. Hope it help.
Any way, if you provide more details in your code (getView() is a good point) I think some guys can help a lot.
Is there any way to remove selected item from gridview.
I want to delete the selected item from my gridview.
I did not find any thing . my code is
public class ImageAdapter extends BaseAdapter{
Context context;
public ImageAdapter(Context context)
{
this.context = context;
}
#Override
public int getCount() {
// TODO Auto-generated method stub
return mThumbIds.length;
}
#Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return 0;
}
#Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ImageView imageView;
if (convertView == null) { // if it's not recycled, initialize some attributes
imageView = new ImageView(context);
imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(0, 5, 0, 0);
} else {
imageView = (ImageView) convertView;
}
imageView.setImageResource(mThumbIds[position]);
return imageView;
}
public Integer[] mThumbIds = {
R.drawable.sample_1,R.drawable.sample_2,R.drawable.sample_3,
R.drawable.sample_3,R.drawable.sample_1,R.drawable.sample_2,
R.drawable.sample_2,R.drawable.sample_3,R.drawable.sample_1
};
}
//////////////////
public class ImageActivity extends Activity {
ImageAdapter iAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image);
iAdapter = new ImageAdapter(this);
final GridView gView = (GridView)findViewById(R.id.grid_view);
gView.setAdapter(iAdapter);
gView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
//gView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
// gView.setItemChecked(position, true);
Toast.makeText(ImageActivity.this, "" + position, Toast.LENGTH_SHORT).show();
}
});
iAdapter.notifyDataSetChanged();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_image, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == R.id.menu_delete)
{
Toast.makeText(this, "Delete",Toast.LENGTH_SHORT ).show();
}
return super.onOptionsItemSelected(item);
}
}
can anyone have idea .
thank
you are using a table :
public Integer[] mThumbIds = {
R.drawable.sample_1,R.drawable.sample_2,R.drawable.sample_3,
R.drawable.sample_3,R.drawable.sample_1,R.drawable.sample_2,
R.drawable.sample_2,R.drawable.sample_3,R.drawable.sample_1}
Tables are not modifiable.
Replace it by a List on which you will be able to make add or remove operations. Simply call notifyDataSetChanged when a change is made to let the adapter know that its list has been modified.
As Teovald and pskink suggested, you cannot have a fixed list of images and then implement the remove functionality that you are looking for. If you want to add remove, change your design and make sure your data set is also removable. What you have tried so far seems to be using some really basic code which is good to show basic GridView feature.
Just try this. Create a image data set class which returns the actual images. Store the images in a List that can be modified. Add setters/getters to this data set and also add a method to delete a particular item. Change your image adapter to use the image from this new data set. Whenever an image is deleted, call the notifyDataSetChanged on the adpater.
Good luck
So I have a Gridview and and ImageAdapter class. The images all get grab from a folder and then populated into the grid view. I then have another class that displays the full image when clicked. However whenever someone clicks an image ImageAdapter has to get called again and all the images need to be repopulated into my variables and then I just pick out the one I need. This is terribly inefficient but I don't know how to do it otherwise.
Here is my code.
Main Classes (favorites in this case) with the grid view
public class Favorites extends Activity {
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.favorites);
GridView gridview = (GridView) findViewById(R.id.favgridview);
gridview.setAdapter(new ImageAdapter(this));
gridview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent,View v, int position, long id){
Intent i = new Intent(getApplicationContext(), FullImageActivity.class);
i.putExtra("id", position);
startActivity(i);
}
});
}
}
My ImageAdapter class, you can see that I load all the images as bitmaps into an array.
public class ImageAdapter extends BaseAdapter{
private Context mContext;
private Bitmap[]mis_fotos;
public ImageAdapter(Context c){
mContext = c;
}
public int getCount(){
get_images();
return mis_fotos.length;
}
public Bitmap getItem(int position){
get_images();
return mis_fotos[position];
}
public long getItemId(int position){
return 0;
}
public View getView(int position, View convertView, ViewGroup parent){
ImageView imageView;
if (convertView == null){
imageView = new ImageView(mContext);
imageView.setLayoutParams(new GridView.LayoutParams(85,85));
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setPadding(8, 8, 8, 8);
} else {
imageView = (ImageView) convertView;
}
imageView.setImageBitmap(mis_fotos[position]);
return imageView;
}
private void get_images(){
String dirPath = mContext.getFilesDir().getAbsolutePath() + File.separator + "favorites";
File directory = new File(dirPath);
File[] archivos = directory.listFiles();
mis_fotos = new Bitmap[archivos.length];
for (int cont=0; cont<archivos.length;cont++){
File imgFile = new File(archivos[cont].toString());
mis_fotos[cont] = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
}
}
}
And Finally my Full Image Class
public class FullImageActivity extends Activity {
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.full_image);
Intent i = getIntent();
int position = i.getExtras().getInt("id");
ImageAdapter imageAdapter = new ImageAdapter(this);
ImageView imageView = (ImageView) findViewById(R.id.full_image_view);
imageView.setImageBitmap(imageAdapter.getItem(position));
}
}
So you can see that when I use the full image all I can pass is the position integer from the gridview class. I then have to call get_images() again in the ImageAdapter class and repopulate an array all over again.
All I need to to pass a single image from the gridview to the fullimage class when an image is clicked. I know there is an easier and far more efficient way to do this. I hope this makes sense.
Work around required, you are calling get_images() multiple times inside an Adapter class which is a bad way. Better solution is remove it from Adapter class and keep inside the MainActivity and just call it before setting the Adapter like,
GridView gridview = (GridView) findViewById(R.id.gridView);
get_images();
gridview.setAdapter(new ImageAdapter(this));
And then your method for Adapter class should be like,
public int getCount() {
return mis_fotos.length;
}
public Object getItem(int position) {
return mis_fotos[position];
}
Now, I come to your issue that is you want to show an Image as fullscreen to Next Activity. So, why don't you fetch the Bitmap from clicked ListView Item and pass it to Next Activity?. So, how can you do that? Here it is,
gridview.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
Bitmap bitmap = (Bitmap) parent.getAdapter().getItem(position);
Intent i = new Intent(getApplicationContext(), FullImageActivity.class);
Bundle bundle = new Bundle();
bundle.putParcelable("bitmap", bitmap);
i.putExtras(bundle);
startActivity(i);
});
So, nothing tricky, just getting the Bitmap using getItem(position); and the sending it to Next Activity using Bundle. Now you can easily get the Bitmap using
Bundle bundle = getIntent().getExtras();
Bitmap bitmap = bundle.getParcelable("bitmap");
// create new Bitmap with any height, width required by you.
Bitmap newBitmap = Bitmap.createScaledBitmap(bitmap, 200, 200, true);
and show to ImageView.
I have a working Gallery that shows one picture at a time and can be "swiped" to rotate through the images. I want to have the option of the user to view 2 or 3 pictures at a time by using the menu and selecting how many to show. So far Ive tried adjusting the Gallery width, and LinearLayout params and all crash the Activity. any advice would be appreciated.
I declare and initialize the Gallery here and have the onOptionsItemSelected method sekeleton.
public class SpeechAppActivity extends Activity implements OnClickListener{
//Menu Items
// Class variables
Gallery myGallery;
ImageView imageView;
MyDBAdapter db;
Item item1;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
db = new MyDBAdapter(this);
db.insertEntry(item1 = new Item("Bathtub", "Bathroom", "Typical", "Clean", "fill, wash", "Round, deep", "Bathroom", "Toilet, Bathroom", R.drawable.ic_launcher));
Log.i("item", "item: " + item1.toString());
// Bind the gallery defined in the main.xml
// Apply a new (customized) ImageAdapter to it.
myGallery = (Gallery) findViewById(R.id.myGallery);
myGallery.setAdapter(new ImageAdapter(this));
//myGallery.setLayoutParams(new Gallery.LayoutParams(250, 250));
myGallery.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View v,
int position, long id) {
}
public void onNothingSelected(AdapterView<?> parent) {
}
});
public boolean onOptionsItemSelected(MenuItem menuItem) {
switch (menuItem.getItemId()) {
case R.id.settings:
startActivity(new Intent(this, Prefs.class));
return true;
case R.id.show1:
//myGallery.findViewById(R.id.myGallery).setLayoutParams(new Gallery.LayoutParams(500, 250));
return true;
case R.id.show2:
//myGallery.findViewById(R.id.myGallery).setLayoutParams(new Gallery.LayoutParams(500, 250));
return true;
case R.id.show3:
//myGallery.findViewById(R.id.myGallery).setLayoutParams(new Gallery.LayoutParams(500, 250));
return true;
}
return false;
}
This is the Image Adapter class for the Gallery
public class ImageAdapter extends BaseAdapter {
/** The parent context */
private Context myContext;
// Put some images to project-folder: /res/drawable/
// format: jpg, gif, png, bmp, ...
private int[] myImageIds = { R.drawable.apple, R.drawable.orange,
R.drawable.ic_launcher };
/** Simple Constructor saving the 'parent' context. */
public ImageAdapter(Context c) {
this.myContext = c;
}
// inherited abstract methods - must be implemented
// Returns count of images, and individual IDs
public int getCount() {
return this.myImageIds.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
// Returns a new ImageView to be displayed,
public View getView(int position, View convertView,
ViewGroup parent) {
// Get a View to display image data
ImageView iv = new ImageView(this.myContext);
iv.setImageResource(this.myImageIds[position]);
// Image should be scaled somehow
//iv.setScaleType(ImageView.ScaleType.CENTER);
iv.setScaleType(ImageView.ScaleType.CENTER_CROP);
//iv.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
//iv.setScaleType(ImageView.ScaleType.FIT_CENTER);
//iv.setScaleType(ImageView.ScaleType.FIT_XY);
//iv.setScaleType(ImageView.ScaleType.FIT_END);
//iv.setScaleType(ImageView.ScaleType.FIT_START);
// Set the Width & Height of the individual images
//get scale for finding dip of a set # of pixels
final float scale = parent.getContext().getResources().getDisplayMetrics().density;
iv.setLayoutParams(new Gallery.LayoutParams((int) (300 * scale + 0.5f), (int) (250 * scale + 0.5f)));
return iv;
}
}// ImageAdapter
In your adapter,
Use View object (witn custom view) and put ImageView inside it.
This was you can put more than one images per view.
Best results can be achieved by few layout files based on number of images and using correct one according to user selection.
Let me know if you need more specific code template.
Note: As of Jellybean the gallery widget is deprecated. A ViewPager should be used instead.
I'd like to programmatically move between images in the Gallery widget, with animation.
I can change the currently displaying image using the setSelection(int position) method, however that does not animate. Then there's setSelection(int position, bool animate) but the extra boolean on the end there doesn't appear to do anything.
In the source of Gallery it appears that it can handle DPAD key-presses, so a work-around I thought of was to fake the key-presses. Eg.
dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT))
However I can't get this working for some reason. Anyone tried this?
I notice three of the widget's methods I'd love to use moveNext(), movePrevious() and scrollToChild() are all private and unusable.
Does anyone know how I might be able to do this?
Just call the key press handler for the gallery directly:
public boolean onKeyDown(int keyCode, KeyEvent event)
i.e
Gallery gallery = ((Gallery) findViewById(R.id.gallery));
gallery.onKeyDown(KeyEvent.KEYCODE_DPAD_LEFT, new KeyEvent(0, 0));
One important thing - this solution works only if child that is on left/right was already created, which means that it has to be 'visible'. If you have your image on fullscreen - consider setting spacing to -1 value.
You can Animate using dispatchKeyEvent or calling onFling directly.
Here is sample code for dispatchKeyEvent:
KeyEvent evtKey = new KeyEvent(0, KeyEvent.KEYCODE_DPAD_RIGHT);
dispatchKeyEvent(evtKey);
Use gallery.setSelected(int); Here is a simple example.
public class Splash extends Activity {
ArrayList objects = new ArrayList();
Gallery g;
int i = 0;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.photos);
g = (Gallery) findViewById(R.id.gallery);
objects.add(getResources().getDrawable(R.drawable.icon));
objects.add(getResources().getDrawable(R.drawable.icon));
objects.add(getResources().getDrawable(R.drawable.icon));
objects.add(getResources().getDrawable(R.drawable.icon));
objects.add(getResources().getDrawable(R.drawable.icon));
objects.add(getResources().getDrawable(R.drawable.icon));
g.setAdapter(new CustomAdapter(this, objects));
g.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView arg0, View arg1,
int arg2, long arg3) {
Log.i("", "selected " + arg2);
}
#Override
public void onNothingSelected(AdapterView arg0) {}
});
}
#Override
public void onBackPressed() {
g.setSelection(i++);
}
private class CustomAdapter extends BaseAdapter {
private Context mCtx;
private List objects;
public int getCount() {
return this.objects.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public CustomAdapter(Context context, ArrayList objects) {
super();
mCtx = context;
this.objects = objects;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView row = (ImageView) convertView;
if (row == null) {
row = new ImageView(mCtx);
row.setBackgroundDrawable(objects.get(position));
}
return row;
}
}
}
In the end I wrote my own version of the Gallery widget with the help of the code at this site.
I then wrote my own method which uses mFlingRunnable.startUsingDistance(distance);
Now I can programmatically animate the gallery between images.
Try this
mGallery.onFling(null,null, velocity,0);
http://groups.google.com/group/android-developers/browse_thread/thread/9140fd6af3061cdf#