I have some throuble with getting my GridView working as it should.
When I scrol some of the images are sliding much faster than other images (they will not stay in their row). Sometimes I am also able to scrol above the first line! If I skip to use the convertview I have not seen the problem.
---Some additional background---
The imageBufferLoader object below extends a component I am trying to develop. It works as a cash for objects (this time images) with two parameterised windows. One window for maximum objects cashed (to avoid memory problems) and a window for minimum objects loaded (in order to be prepared for scrolling). I have callables that are sent to an executor, one callable for filling the array and one for cleaning the array.
Maybe my problem is thread related.
Here is my adater:
public class WebImageSearchResultAdapter extends BaseAdapter implements
PropertyChangeListener {
private ImageBufferLoader imageBufferLoader;
private Image image = new Image();
private Context context;
private Bitmap bitmapIC_Delete;
private static Handler handleUIEvents;
private LoggerAndroid logger;
private int lastPosRequest;
private RelativeLayout zeroView;
public WebImageSearchResultAdapter(Context context, Parameters parameters) {
this.context = context;
handleUIEvents = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
notifyDataSetChanged();
logger.LogD("Notify Data set Changed");
super.handleMessage(msg);
}
};
bitmapIC_Delete = BitmapFactory.decodeResource(context.getResources(),
R.drawable.ic_delete);
logger = new LoggerAndroid(
LoggerAndroid.isLoggingactivewebimagesearchresultadapter(),
"WebImageSearchResultAdapter", "");
Logger loggerImageBuffer = new LoggerAndroid(
LoggerAndroid.isLoggingactiveimagebufferloader(),
"ImageBuffer", "ImageBuffer");
Logger loggerImageDataBuffer = new LoggerAndroid(
LoggerAndroid.isLoggingactiveimagebufferloader(),
"ImageDataBuffer", "ImageDataBuffer");
imageBufferLoader = new ImageBufferLoader(loggerImageBuffer,
loggerImageDataBuffer, parameters, false, 50, 50, false, true, 50, 200);
imageBufferLoader.addChangeListener(this);
try {
imageBufferLoader.startService();
} catch (TimeoutException e) {
ExceptionHandler.getInstance(true).handleException(e);
}
}
public void setParameters(Parameters parameters) {
imageBufferLoader.setParameters(parameters);
zeroView = null;
}
public int getCount() {
// TODO Auto-generated method stub
return 1000;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
logger.LogD("ASK: " + position);
lastPosRequest = position;
RelativeLayout view2 = null;
ImageView imageView = null;
if (convertView == null) {
view2 = (RelativeLayout) LayoutInflater.from(context).inflate(R.layout.listimageitem, parent, false);
} else {
view2 = (RelativeLayout) convertView;
}
imageView = (ImageView) view2.findViewById(R.id.imageThumbnail);
if (position == 0 && zeroView != null) {
view2 = zeroView;
} else if (imageBufferLoader.isServiceRunning()
&& imageBufferLoader.isFillCleanRunning()) {
try {
if (imageBufferLoader.isDataAvailable(position)) {
image = imageBufferLoader.getData(position);
imageView.setImageBitmap(image.getThumbnailBitmap());
if(position == 0){
zeroView = view2;
}
logger.LogD("RET IMAGE for: " + position);
} else {
imageView.setImageBitmap(bitmapIC_Delete);
imageBufferLoader.loadData(position);
logger.LogD("RET: IC_DELETE for position " + position +"Request added to Queue");
}
} catch (Exception e) {
ExceptionHandler.getInstance(true).handleException(e);
imageBufferLoader.stopService();
imageView.setImageBitmap(bitmapIC_Delete);
logger.LogD("RET: IC_DELETE for position " + position +" EXCEPTION");
}
} else {
imageView.setImageBitmap(bitmapIC_Delete);
logger.LogD("RET: IC_DELETE for position " + position +" SERVICE NOT RUNNING TRY TO RESTART");
imageBufferLoader.start();
}
return view2;
}
public void propertyChange(PropertyChangeEvent event) {
String proptertyName = event.getPropertyName();
if (proptertyName.equals("Filling Ready")) {
handleUIEvents.sendMessage(new Message());
}
if (proptertyName.equals("BufferCleared")) {
if (imageBufferLoader.isServiceRunning()
&& imageBufferLoader.isFillCleanRunning()) {
imageBufferLoader.loadData(lastPosRequest);
}
}
}
}
Here is my fragment with gridwiev
<?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="horizontal" >
<View
android:layout_width="0dp"
android:layout_height="fill_parent" />
<GridView
android:id="#+id/gridview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:columnWidth="300dp"
android:gravity="center"
android:horizontalSpacing="10dp"
android:numColumns="auto_fit"
android:stretchMode="columnWidth"
android:verticalSpacing="10dp" >
</GridView>
<View
android:layout_width="0dp"
android:layout_height="fill_parent" />
</LinearLayout>
Here is the layout I inflate in the adapter
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="300dp"
android:layout_height="300dp" >
<ImageView
android:id="#+id/imageThumbnail"
android:layout_width="300dp"
android:layout_height="300dp"
/>
</RelativeLayout>
Related
I have a custom BaseAdapter which is loading images into a custom listview of sorts from urls using async tasks but the images are not showing. Here is the adapter:
private class HorizontalAdapter extends BaseAdapter{
public HorizontalAdapter() {
super();
final Checkpoint current = localCheckpoints[checkpointPosition];
urls[0] = current.getGallery()[0].getUrl();
urls[1] = current.getYoutube();
urls[2] = current.getSoundcloud();
}
#Override
public int getCount() {
return 3;
}
#Override
public Object getItem(int position) {
return urls[position];
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
String urlToLoad = urls[position];
if(convertView == null){
convertView = LayoutInflater.from(getActivity()).inflate(R.layout.horizontal_listview_item,parent,false);
}
ImageView imageView = (ImageView)convertView.findViewById(R.id.cp_image);
FrameLayout container = (FrameLayout)convertView.findViewById(R.id.youtubeShower);
Button playButton = (Button)convertView.findViewById(R.id.playStop);
playButton.setVisibility(View.VISIBLE);
if(position == 0){
Log.d("horizontalsv","loading image with url: " + urlToLoad);
new loadImage(imageView).execute(urlToLoad);
//container.setVisibility(View.VISIBLE);
imageView.setVisibility(View.VISIBLE);
}
else if(position == 1){
container.setVisibility(View.VISIBLE);
imageView.setVisibility(View.INVISIBLE);
String videoId = extractYTId(urlToLoad);
PlayYoutubeVideFragment youtubeFrag = PlayYoutubeVideFragment.newInstance(videoId);
myContext.getSupportFragmentManager().beginTransaction().replace(R.id.youtubeShower, youtubeFrag).commit();
}else{
}
return convertView;
}
}
and here is the xml for the listview item:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
>
<FrameLayout
android:id="#+id/youtubeShower"
android:layout_width="match_parent"
android:layout_height="288dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true">
</FrameLayout>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/cp_image"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
<Button
android:layout_width="wrap_content"
android:layout_height="87dp"
android:text="Play"
android:id="#+id/playStop"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
and here is how I am loading the images:
private class loadImage extends AsyncTask<String,Void,Bitmap>{
ImageView target;
public loadImage(ImageView imageViewToLoad){
target = imageViewToLoad;
if(imageViewToLoad == null){
Log.e("in loadImage","imageview is null");
}else{
Log.d("in loadImage","imageView is there");
}
}
#Override
protected Bitmap doInBackground(String... params) {
String urlString = params[0];
try {
URL url = new URL(urlString);
try {
Bitmap bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
return bmp;
}catch(IOException e){
Log.e("IOException",e.getMessage());
return null;
}
}catch (MalformedURLException e){
Log.e("URL ERROR", "url = " + urlString + " and error = " + e.getMessage());
return null;
}
}
#Override
protected void onPostExecute(Bitmap o) {
super.onPostExecute(o);
if(o != null){
Log.d("in loadimage","bitmap is not null");
target.setImageBitmap(o);
//lvTest.setAdapter(new HorizontalAdapter());
}else{
Log.e("in loadimage","bitmap is null");
target.setImageBitmap(null);
target.setBackgroundColor(Color.WHITE);
}
}
}
Is there any reason why the images is not loading? The bitmap is returning as NOT null in the load image asynctask so it should work.
Use the Picasso library, it should take away all the problems you're having with your asynchronous task. http://square.github.io/picasso/
below is my code which works fine for showing listview horizontally. how can I change it to gridvew. What changes should I make to change it to gridview? help me please
public class fifthscreen extends Activity {
int IOConnect = 0;
String _response;
String status;
HorizontalListView listview;
CategoryListAdapter3 cla;
String URL, URL2;
String SelectMenuAPI;
static ArrayList<Long> Category_ID = new ArrayList<Long>();
static ArrayList<String> Category_name = new ArrayList<String>();
static ArrayList<String> Category_image = new ArrayList<String>();
public static String allergen2;
String name;
String url1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fifthscreen);
listview = (HorizontalListView) this.findViewById(R.id.listview2);
cla = new CategoryListAdapter3(fifthscreen.this);
new TheTask().execute();
}
public class TheTask extends AsyncTask<Void, String, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(Void... arg0) {
try {
HttpGet request = new HttpGet(url);
HttpResponse response = client.execute(request);
HttpEntity resEntity = response.getEntity();
_response = EntityUtils.toString(resEntity);
} catch (Exception e) {
e.printStackTrace();
}
return _response;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
try {
JSONObject json2 = new JSONObject(result);
status = json2.getString("status");
if (status.equals("1")) {
JSONArray school4 = json2.getJSONArray("dish_allergen");
//
for (int i = 0; i < school4.length(); i++) {
JSONObject object = school4.getJSONObject(i);
Category_ID.add((long) i);
Category_name.add(object.getString("name"));
Category_image.add(object.getString("image"));
}
}
else {
JSONArray school2 = json2.getJSONArray("data");
for (int i = 0; i < school2.length(); i++) {
JSONObject object = school2.getJSONObject(i);
Category_ID.add((long) i);
Category_name.add(object.getString("name"));
}
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
listview.setAdapter(cla);
}
}
}
public class CategoryListAdapter3 extends BaseAdapter {
private Activity activity;
private AQuery androidAQuery;
public CategoryListAdapter3(Activity act) {
this.activity = act;
// imageLoader = new ImageLoader(act);
}
public int getCount() {
// TODO Auto-generated method stub
return fifthscreen.Category_ID.size();
}
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder;
androidAQuery = new AQuery(getcontext());
if(convertView == null){
LayoutInflater inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.viewitem2, null);
holder = new ViewHolder();
convertView.setTag(holder);
}else{
holder = (ViewHolder) convertView.getTag();
}
holder.txtText = (TextView) convertView.findViewById(R.id.title2);
holder.imgThumb = (ImageView) convertView.findViewById(R.id.image2);
holder.txtText.setText(fifthscreen.Category_name.get(position));
// imageLoader.DisplayImage(fifthscreen.Category_image.get(position),
activity, holder.imgThumb);
androidAQuery.id(holder.imgThumb).image(fifthscreen.Category_image.get(position), false,
false);
return convertView;
}
private Activity getcontext() {
// TODO Auto-generated method stub
return null;
}
static class ViewHolder {
TextView txtText;
ImageView imgThumb;
}
}
<!--- fifithscreen.xml--->
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_below="#+id/test_button_text5"
android:orientation="vertical" >
<com.example.examplecode.HorizontalListView
android:id="#+id/listview2"
android:layout_width="wrap_content"
android:layout_height="120dp"
android:layout_below="#+id/test_button_text5"
android:background="#ffffff"/>
</LinearLayout>
<!--viewitem2.xml--->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<ImageView
android:id="#+id/image2"
android:layout_width="90dp"
android:layout_height="70dp"
android:scaleType="fitXY"
android:padding="5dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:src="#drawable/ic_launcher"
/>
<TextView
android:id="#+id/title2"
android:layout_width="90dp"
android:layout_height="wrap_content"
android:textColor="#000"
android:paddingTop="10dp"
android:gravity="center_horizontal"
/>
</LinearLayout>
No change at all. Just set adapter of GridView as your are setting for ListView.
I'd suggest that you use RecyclerView intead.
You might want to refer to the documentation and learn more about it.
I'm sharing my piece of code in which I'm changing my gridview to listview using RecyclerView
If you're using Android Studio then you might need to add dependencies in gradle build. In my case I added as follows:
dependencies {
.
.
.
compile 'com.android.support:recyclerview-v7:24.0.0'
}
First I'm defining a grid cell which is to be used in grid layout
recycler_cell.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:id="#+id/imageView2"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:background="#FF000000"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Small Text"
android:id="#+id/textView2"
android:layout_below="#+id/imageView2"
android:layout_alig=nParentStart="true"
android:layout_alignEnd="#+id/imageView2"
android:gravity="center"/>
</RelativeLayout>
Now I'm defining a list row which is to be used in list layout
recycler_row.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:id="#+id/imageView"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:background="#FF000000"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/textView"
android:layout_alignParentTop="true"
android:layout_alignBottom="#+id/imageView"
android:layout_alignParentEnd="true"
android:layout_toEndOf="#+id/imageView"
android:gravity="center_vertical"
android:background="#FF333333"
android:textColor="#FFF"
android:padding="10dp"/>
</RelativeLayout>
recycler_view_test.xml
And of course define a layout which would contain RecyclerView
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/recyclerView"
android:layout_alignParentLeft="true"
android:layout_marginLeft="0dp"
android:layout_alignParentTop="true"
android:layout_marginTop="0dp"
android:layout_centerHorizontal="true"
>
</android.support.v7.widget.RecyclerView>
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Change Layout"
android:id="#+id/btnChange"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="62dp"/>
</RelativeLayout>
I'm sharing my piece of code but I'd strongly recommend that you go through the documentation and tutorials to understand RecyclerView to its full extent.
public class RecyclerViewTest extends AppCompatActivity
{
final int GRID = 0;
final int LIST = 1;
int type;
RecyclerView recyclerView;
RecyclerView.LayoutManager gridLayoutManager, linearLayoutManager;
MyAdapter adapter;
Button btnChange;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.recycler_view_test);
// Display contents in views
final List<Person> list = new ArrayList<>();
list.add(new Person("Ariq Row 1"));
list.add(new Person("Ariq Row 2"));
list.add(new Person("Ariq Row 3"));
// Finding views by id
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
btnChange = (Button) findViewById(R.id.btnChange);
// Defining Linear Layout Manager
linearLayoutManager = new LinearLayoutManager(getApplicationContext());
// Defining Linear Layout Manager (here, 3 column span count)
gridLayoutManager = new GridLayoutManager(getApplicationContext(), 3);
//Setting gird view as default view
type = GRID;
adapter = new MyAdapter(list, GRID);
recyclerView.setLayoutManager(gridLayoutManager);
recyclerView.setAdapter(adapter);
//Setting click listener
btnChange.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
if (type == LIST)
{
// Change to grid view
adapter = new MyAdapter(list, GRID);
recyclerView.setLayoutManager(gridLayoutManager);
recyclerView.setAdapter(adapter);
type = GRID;
}
else
{
// Change to list view
adapter = new MyAdapter(list, LIST);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(adapter);
type = LIST;
}
}
});
}
}
//Defining Adapter
class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>
{
List<Person> list;
int type;
final int GRID = 0;
final int LIST = 1;
MyAdapter(List<Person> list, int type)
{
this.list = list;
this.type = type;
}
// Inflating views if the existing layout items are not being recycled
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
View itemView;
if (viewType == GRID)
{
// Inflate the grid cell as a view item
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_cell, parent, false);
}
else
{
// Inflate the list row as a view item
itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_row, parent, false);
}
return new ViewHolder(itemView, viewType);
}
// Add data to your layout items
#Override
public void onBindViewHolder(ViewHolder holder, int position)
{
Person person = list.get(position);
holder.textView.setText(person.name);
}
// Number of items
#Override
public int getItemCount()
{
return list.size();
}
// Using the variable "type" to check which layout is to be displayed
#Override
public int getItemViewType(int position)
{
if (type == GRID)
{
return GRID;
}
else
{
return LIST;
}
}
// Defining ViewHolder inner class
public class ViewHolder extends RecyclerView.ViewHolder
{
TextView textView;
final int GRID = 0;
final int LIST = 1;
public ViewHolder(View itemView, int type)
{
super(itemView);
if (type == GRID)
{
textView = (TextView) itemView.findViewById(R.id.textView2);
}
else
{
textView = (TextView) itemView.findViewById(R.id.textView);
}
}
}
}
// Data Source Class
class Person
{
String name;
Person(String name)
{
this.name = name;
}
}
If you end up with the issue to auto fit the number of columns in case of grid layout then you might want to check #s-marks's answer in which he extended the GridLayoutManager class and added his own patch of code, and also my fix if you start having weird column width.
In my case, using his solution I made a class as follows:
class GridAutofitLayoutManager extends GridLayoutManager
{
private int mColumnWidth;
private boolean mColumnWidthChanged = true;
public GridAutofitLayoutManager(Context context, int columnWidth)
{
/* Initially set spanCount to 1, will be changed automatically later. */
super(context, 1);
setColumnWidth(checkedColumnWidth(context, columnWidth));
}
public GridAutofitLayoutManager(Context context, int columnWidth, int orientation, boolean reverseLayout)
{
/* Initially set spanCount to 1, will be changed automatically later. */
super(context, 1, orientation, reverseLayout);
setColumnWidth(checkedColumnWidth(context, columnWidth));
}
private int checkedColumnWidth(Context context, int columnWidth)
{
if (columnWidth <= 0)
{
/* Set default columnWidth value (48dp here). It is better to move this constant
to static constant on top, but we need context to convert it to dp, so can't really
do so. */
columnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48,
context.getResources().getDisplayMetrics());
}
else
{
columnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, columnWidth,
context.getResources().getDisplayMetrics());
}
return columnWidth;
}
public void setColumnWidth(int newColumnWidth)
{
if (newColumnWidth > 0 && newColumnWidth != mColumnWidth)
{
mColumnWidth = newColumnWidth;
mColumnWidthChanged = true;
}
}
#Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state)
{
int width = getWidth();
int height = getHeight();
if (mColumnWidthChanged && mColumnWidth > 0 && width > 0 && height > 0)
{
int totalSpace;
if (getOrientation() == VERTICAL)
{
totalSpace = width - getPaddingRight() - getPaddingLeft();
}
else
{
totalSpace = height - getPaddingTop() - getPaddingBottom();
}
int spanCount = Math.max(1, totalSpace / mColumnWidth);
setSpanCount(spanCount);
mColumnWidthChanged = false;
}
super.onLayoutChildren(recycler, state);
}
}
Then you simply have to change:
gridLayoutManager = new GridLayoutManager(getApplicationContext(), 3);
and use your custom grid layout object, here 100 is the width of columns in dp
gridLayoutManager = new GridAutofitLayoutManager(getApplicationContext(), 100);
You can do something like this:
For the layout of the grid/list use a merge:
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ViewStub android:id="#+id/list"
android:inflatedId="#+id/showlayout"
android:layout="#layout/list_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"/>
<ViewStub android:id="#+id/grid"
android:inflatedId="#+id/showlayout"
android:layout="#layout/grid_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"/>
</merge>
then define the layout for the list and the grid (and also for their items), and manage the passage between them inflating the layouts, and then use a method like this to change the current view:
private void changeView() {
//if the current view is the listview, passes to gridview
if(list_visibile) {
listview.setVisibility(View.GONE);
gridview.setVisibility(View.VISIBLE);
list_visibile = false;
setAdapters();
}
else {
gridview.setVisibility(View.GONE);
listview.setVisibility(View.VISIBLE);
list_visibile = true;
setAdapters();
}
}
If you need the complete code, it is available in this article:
http://pillsfromtheweb.blogspot.it/2014/12/android-passare-da-listview-gridview.html
Just take a GridView object instead of Listview like :
GridView gridView;
gridView= (GridView) this.findViewById(R.id.gridView1);
And in you getView method of CategoryListAdapter3 do like :
convertView = inflater.inflate(R.layout.your_grid_item_leyout, null);
And at last in onPostExecute of TheTask do like :
gridView.setAdapter(cla);
That's It.
Use GridView instead of below:
Then replace
listview = (HorizontalListView) this.findViewById(R.id.listview2);
to
GridView gridview;
gridview=(GridView) findViewById(R.id.gridview);
Everything else are fine, just set Adapter using GridView object. And you are done.
From what I can gather it appears that this might be because my ListView is not being displayed, I've verified that getCount is returning a value not zero, but I can't see what I'm doing wrong.
Everything loads and acts like it's working but the ListView never appears, I put a background color on the fragment reference in mixed.xml and it is there and taking up the full screen, but when I set a background color on my ListView it does not appear, it's like it's not being rendered at all.
More odd, getView is not being called in my adapter, and this is all working code from regular activities that I ported to fragments.
I've tried calling notifyDataSetChanged which didn't changed anything, debugging shows the adapter is filled with data and getCount is indeed returning an accurate count greater than 0.
Thanks for any help, I'm stuck.
Project is open and can be viewed here http://code.google.com/p/shack-droid/source/browse/#svn%2FTrunk but I'm also including the pertinent code here.
This is the ListFragment:
public class FragmentTopicView extends ListFragment implements ShackGestureEvent {
private ArrayList<ShackPost> posts;
private String storyID = null;
private String errorText = "";
private Integer currentPage = 1;
private Integer storyPages = 1;
private String loadStoryID = null;
private Boolean threadLoaded = true;
private Hashtable<String, String> postCounts = null;
private AdapterLimerifficTopic tva;
public FragmentTopicView() {
}
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.setRetainInstance(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.topics, null);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final ShackGestureListener listener = Helper.setGestureEnabledContentView(R.layout.topics, getActivity());
if (listener != null) {
listener.addListener(this);
}
if (savedInstanceState == null) {
// get the list of topics
GetChattyAsyncTask chatty = new GetChattyAsyncTask(getActivity());
chatty.execute();
}
ListView lv = getListView();
lv.setOnScrollListener(new OnScrollListener() {
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// start loading the next page
if (threadLoaded && firstVisibleItem + visibleItemCount >= totalItemCount && currentPage + 1 <= storyPages) {
// get the list of topics
currentPage++;
GetChattyAsyncTask chatty = new GetChattyAsyncTask(getActivity());
chatty.execute();
}
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
});
}
class GetChattyAsyncTask extends AsyncTask<String, Void, Void> {
protected ProgressDialog dialog;
protected Context c;
public GetChattyAsyncTask(Context context) {
this.c = context;
}
#Override
protected Void doInBackground(String... params) {
threadLoaded = false;
try {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
final String feedURL = prefs.getString("shackFeedURL", getString(R.string.default_api));
final URL url;
if (loadStoryID != null) {
if (currentPage > 1)
url = new URL(feedURL + "/" + loadStoryID + "." + currentPage.toString() + ".xml");
else
url = new URL(feedURL + "/" + loadStoryID + ".xml");
}
else {
if (currentPage > 1)
url = new URL(feedURL + "/" + storyID + "." + currentPage.toString() + ".xml");
else
url = new URL(feedURL + "/index.xml");
}
// Get a SAXParser from the SAXPArserFactory.
final SAXParserFactory spf = SAXParserFactory.newInstance();
final SAXParser sp = spf.newSAXParser();
// Get the XMLReader of the SAXParser we created.
final XMLReader xr = sp.getXMLReader();
// Create a new ContentHandler and apply it to the XML-Reader
SaxHandlerTopicView saxHandler = new SaxHandlerTopicView(c, "topic");
xr.setContentHandler(saxHandler);
// Parse the xml-data from our URL.
xr.parse(new InputSource(HttpHelper.HttpRequestWithGzip(url.toString(), c)));
// Our ExampleHandler now provides the parsed data to us.
if (posts == null) {
posts = saxHandler.GetParsedPosts();
}
else {
ArrayList<ShackPost> newPosts = saxHandler.GetParsedPosts();
newPosts.removeAll(posts);
posts.addAll(posts.size(), newPosts);
}
storyID = saxHandler.getStoryID();
storyPages = saxHandler.getStoryPageCount();
if (storyPages == 0) // XML returns a 0 for stories with only
// one page
storyPages = 1;
}
catch (Exception ex) {
// TODO: implement error handling
}
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
if (currentPage == 1)
dialog = ProgressDialog.show(getActivity(), null, "Loading Chatty", true, true);
else
SetLoaderVisibility(View.VISIBLE);
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
ShowData();
SetLoaderVisibility(View.GONE);
try {
dialog.dismiss();
}
catch (Exception e) {
}
}
}
private void ShowData() {
if (posts != null) {
Hashtable<String, String> tempHash = null;
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
final String login = prefs.getString("shackLogin", "");
final int fontSize = Integer.parseInt(prefs.getString("fontSize", "12"));
try {
postCounts = GetPostCache();
}
catch (Exception ex) {
}
if (postCounts != null)
tempHash = new Hashtable<String, String>(postCounts);
if (tva == null) {
tva = new AdapterLimerifficTopic(getActivity(), R.layout.lime_topic_row, posts, login, fontSize, tempHash);
setListAdapter(tva);
}
else {
tva.SetPosts(posts);
tva.notifyDataSetChanged();
}
final ListView lv = getListView();
lv.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
#Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
menu.setHeaderTitle("Options");
menu.add(0, 1, 0, "Copy Post Url to Clipboard");
menu.add(0, 2, 0, "Watch Thread");
menu.add(0, 3, 0, "Thread Expires In?");
menu.add(0, 4, 0, "Shacker's Chatty Profile");
}
});
// update the reply counts for the listing of topics
try {
UpdatePostCache();
}
catch (Exception e) {
}
}
else {
if (errorText.length() > 0) {
try {
new AlertDialog.Builder(getActivity()).setTitle("Error").setPositiveButton("OK", null).setMessage(errorText).show();
}
catch (Exception ex) {
// could not create a alert for the error for one reason
// or another
Log.e("ShackDroid", "Unable to create error alert ActivityTopicView:468");
}
}
}
threadLoaded = true;
}
}
Here's my FragmentActivity:
public class FragmentActivityTopic extends FragmentActivity {
#Override
protected void onCreate(Bundle arg) {
// TODO Auto-generated method stub
super.onCreate(arg);
setContentView(R.layout.mixed);
}
}
This is the Adapter I'm using, and as mentioned above getView is not being called:
public class AdapterLimerifficTopic extends BaseAdapter {
// private Context context;
private List<ShackPost> topicList;
private final int rowResouceID;
private final String shackLogin;
private final Typeface face;
private final int fontSize;
private final Hashtable<String, String> postCache;
private final String showAuthor;
private final Resources r;
private int totalNewPosts = 0;
LayoutInflater inflate;// = LayoutInflater.from(context);
public AdapterLimerifficTopic(Context context, int rowResouceID, List<ShackPost> topicList, String shackLogin, int fontSize, Hashtable<String, String> postCache) {
this.topicList = topicList;
this.rowResouceID = rowResouceID;
this.shackLogin = shackLogin;
this.fontSize = fontSize;
this.postCache = postCache;
this.r = context.getResources();
face = Typeface.createFromAsset(context.getAssets(), "fonts/arial.ttf");
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
showAuthor = prefs.getString("showAuthor", "count");
inflate = LayoutInflater.from(context);
}
public void SetPosts(List<ShackPost> posts)
{
topicList = posts;
}
#Override
public int getCount() {
return topicList.size();
}
#Override
public Object getItem(int position) {
return topicList.get(position);
}
#Override
public long getItemId(int position) {
// return position;
final ShackPost post = topicList.get(position);
return Long.parseLong(post.getPostID());
}
static class ViewHolder {
TextView posterName;
TextView datePosted;
TextView replyCount;
TextView newPosts;
TextView postText;
TextView viewCat;
RelativeLayout topicRow;
ImageView postTimer;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// TextView tmp;
// final View v;
ViewHolder holder;
final ShackPost post = topicList.get(position);
if (convertView == null) {
convertView = inflate.inflate(rowResouceID, parent, false);
holder = new ViewHolder();
holder.posterName = (TextView) convertView.findViewById(R.id.TextViewLimeAuthor);
holder.datePosted = (TextView) convertView.findViewById(R.id.TextViewLimePostDate);
holder.replyCount = (TextView) convertView.findViewById(R.id.TextViewLimePosts);
holder.newPosts = (TextView) convertView.findViewById(R.id.TextViewLimeNewPosts);
holder.postText = (TextView) convertView.findViewById(R.id.TextViewLimePostText);
holder.viewCat = (TextView) convertView.findViewById(R.id.TextViewLimeModTag);
// holder.topicRow = (RelativeLayout) convertView.findViewById(R.id.TopicRow);
// holder.postTimer = (ImageView) convertView.findViewById(R.id.ImageViewTopicTimer);
// holder.posterName.setTypeface(face);
// holder.datePosted.setTypeface(face);
// holder.replyCount.setTypeface(face);
// holder.newPosts.setTypeface(face);
holder.postText.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
// holder.postText.setTypeface(face);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
// holder.postTimer.setImageResource(Helper.GetTimeLeftDrawable(post.getPostDate()));
//
holder.posterName.setText(post.getPosterName());
//
// if (shackLogin.equalsIgnoreCase(post.getPosterName()))
// holder.posterName.setTextColor(Color.parseColor("#00BFF3"));
// else
// holder.posterName.setTextColor(Color.parseColor("#ffba00"));
//
holder.datePosted.setText(Helper.FormatShackDateToTimePassed(post.getPostDate()));
holder.replyCount.setText(post.getReplyCount());
//
// if (showAuthor.equalsIgnoreCase("count") && post.getIsAuthorInThread())
// holder.replyCount.setTextColor(Color.parseColor("#0099CC"));
// else
// holder.replyCount.setTextColor(Color.parseColor("#FFFFFF"));
// clipped code
holder.postText.setText(preview);
// if (showAuthor.equalsIgnoreCase("topic") && post.getIsAuthorInThread()) {
// final Drawable d = r.getDrawable(R.drawable.background_gradient_blue);
// holder.topicRow.setBackgroundDrawable(d);
// }
// else
// holder.topicRow.setBackgroundDrawable(null);
// TODO: clean this up a little / also replicated in ShackDroidThread ick
final String postCat = post.getPostCategory();
holder.viewCat.setVisibility(View.VISIBLE);
if (postCat.equals("offtopic")) {
holder.viewCat.setText("offtopic");
holder.viewCat.setBackgroundColor(Color.parseColor("#444444"));
}
else if (postCat.equals("nws")) {
holder.viewCat.setText("nws");
holder.viewCat.setBackgroundColor(Color.parseColor("#CC0000"));
}
else if (postCat.equals("political")) {
holder.viewCat.setText("political");
holder.viewCat.setBackgroundColor(Color.parseColor("#FF8800"));
}
else if (postCat.equals("stupid")) {
holder.viewCat.setText("stupid");
holder.viewCat.setBackgroundColor(Color.parseColor("#669900"));
}
else if (postCat.equals("informative")) {
holder.viewCat.setText("interesting");
holder.viewCat.setBackgroundColor(Color.parseColor("#0099CC"));
}
else
holder.viewCat.setVisibility(View.GONE);
return convertView;
}
public int getTotalNewPosts() {
return totalNewPosts;
}
}
And related XML:
mixed.xml (this is the layout for the fragments, only the one for now)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:id="#+id/LinearLayoutMixed">
<fragment
android:id="#+id/MixedThreads"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
class="com.stonedonkey.shackdroid.FragmentTopicView"
>
</fragment>
</LinearLayout>
Topics.xml (this contains the ListView as well as a sliding tray and some other stuff.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ListView
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="#+id/TopicLoader"
android:divider="#333333"
android:dividerHeight="1dip"
android:textColor="#FFFFFF"
/>
<RelativeLayout
android:id="#+id/TopicLoader"
android:layout_width="fill_parent"
android:layout_height="35dip"
android:layout_alignParentBottom="true"
android:gravity="center_horizontal"
android:visibility="gone"
android:layout_marginTop="5dip" >
<TextView
android:id="#+id/TextViewTopicLoaderText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="Loading"
>
</TextView>
<ImageView
android:id="#+id/ImageViewTopicLoader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/TextViewTopicLoaderText"
android:src="#drawable/ic_action_refresh"
android:layout_alignBottom="#+id/TextViewTopicLoaderText"
/>
</RelativeLayout>
<SlidingDrawer
android:id="#+id/SlidingDrawer01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="#+id/TopicLoader"
android:animateOnClick="true"
android:content="#+id/bookMarkParent"
android:handle="#+id/TextViewTrayHandle"
android:orientation="vertical"
android:paddingTop="200dip"
android:visibility="gone" >
<TextView
android:id="#+id/TextViewTrayHandle"
android:layout_width="fill_parent"
android:layout_height="35dip"
android:background="#drawable/darkgrey_gradient"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center_vertical" >
</TextView>
<RelativeLayout
android:id="#id/bookMarkParent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ListView
android:id="#+id/ListViewWatchedThreads"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="#333333"
android:dividerHeight="1dip"
android:textColor="#FFFFFF" >
</ListView>
</RelativeLayout>
</SlidingDrawer>
</RelativeLayout>
and finally lime_topic_row which is my custom row layout for the ListView in the above layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#FF0000" >
<TextView
android:id="#+id/TextViewLimeModTag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#FF0000"
android:layout_alignParentLeft="true"
android:layout_marginLeft="10dip"
android:textColor="#000000"
android:padding="2dip"
android:textSize="10dip"
/>
<TextView
android:id="#+id/TextViewLimePostText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="20dip"
android:padding="10dip"
android:layout_below="#+id/TextViewLimeModTag"
android:textColor="#FFFFFF" />
<TextView
android:id="#+id/TextViewLimeAuthor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/TextViewLimePostText"
android:paddingBottom="10dip"
android:paddingLeft="10dip"
android:textColor="#0099CC" />
<TextView
android:id="#+id/TextViewPosted"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/TextViewLimePostText"
android:layout_toRightOf="#+id/TextViewLimeAuthor"
android:paddingBottom="10dip"
android:text=" posted " />
<TextView
android:id="#+id/TextViewLimePostDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/TextViewLimePostText"
android:layout_toRightOf="#+id/TextViewPosted"
android:paddingBottom="10dip"
android:paddingRight="10dip"
android:textColor="#FF8800" />
<TextView
android:id="#+id/TextViewLimePosts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/TextViewLimePostDate"
android:layout_marginRight="3dip"
android:layout_below="#+id/TextViewLimePostText"
android:layout_marginBottom="15dip"
android:layout_toLeftOf="#+id/TextViewLimeNewPosts"
android:background="#BBBBBB"
android:padding="3dip"
android:minWidth="25dip"
android:gravity="center"
android:textColor="#000000" />
<TextView
android:id="#+id/TextViewLimeNewPosts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/TextViewLimePostDate"
android:layout_below="#+id/TextViewLimePostText"
android:layout_marginBottom="15dip"
android:layout_marginRight="10dip"
android:background="#669900"
android:padding="3dip"
android:minWidth="25dip"
android:gravity="center"
android:layout_alignParentRight="true"
android:textColor="#000000" />
</RelativeLayout>
I think I found the problem. The issue appears because of the ShackGestureListener that you setup at the start of the onActivityCreated method in the FragmentTopicView:
final ShackGestureListener listener = Helper.setGestureEnabledContentView(R.layout.topics, getActivity());
if (listener != null) {
listener.addListener(this);
}
In the setGestureEnabledContentView() method you check to see if the user enabled the gestures in the preferences or if the android version is bigger then 3. Either way, true or false you set the content view for the FragmentActivityTopic again(with the layout of the FragmentTopicView). Setting the content view again will, unfortunately, cover the current layout which holds the ListView with data(ListView that populates with no problems). When you run those AsyncTasks to get the data, at the end you set the data on the correct ListView(returned by getListView) because the getListView will hold a reference to the old correct ListView which was set in the onCreateView method, but you don't see anything because in the setGestureEnabledContentView you cover this ListView.
This behavior is easy to see if you simple comment out(or remove) the lines that set the content view for the activity in the Helper and HelperAPI4 classes. Another way to see that your ListView is covered is, for example to set the adapter for the ListView(tva) using getListView and using the getActivity().findViewById(android.R.id.list)(I've done this on selecting one of your menus items, so I can control when I replace the adapter):
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent intent;
switch (item.getItemId())
{
case R.id.topic_menu_newpost: // Launch post form
//this doesn't work as the getListView will return a reference to the old ListView
ListView lv = getListView();
lv.setAdapter(tva);
// this will work as you get a reference to the new ListView on top
ListView lv = (ListView) getActivity().findViewById(android.R.id.list);
lv.setAdapter(tva);
I don't know what to recommend as a solution as I don't quite understand what you're doing, but I doubt that it requires to set the content view for the activity again(and you should work from this).
I searched for these issues and tried most of the given answers but my issue is not solved yet.
My Grid view has around 10-12 items and and each item has a ImageView and a TextView. image and the texts are dynamically loading from resources.
Issue 1 : When the grid is scrolling the item order changes. first items goes to down and the last items coming to top
Issue 2: When an Admob ad loads in the bottom of the screen entire Grid items are mixing up.Even without any scrolling.
Issue 3: Currently I have put the onClickListeners to the ImageView Only. How do I add the same OnclickListener to the relevant TextView as well
I have used a common gridview generation code found every where in the net.
Here is my code
public class ImageAdapter extends BaseAdapter{
Context myContext;
public ImageAdapter(Context _myContext){
myContext = _myContext;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
View MyView = convertView;
try{
if ( convertView == null ){
LayoutInflater li = ((Activity)myContext).getLayoutInflater();
MyView = li.inflate(R.layout.weather_grid, null);
TextView tv = (TextView)MyView.findViewById(R.id.grid_item_text);
Resources res = getResources();
String[] items = res.getStringArray(R.array.weather_items);
final String[] titles = new String[items.length];
int x = 0;
for(String item:items){
titles[x]=item;
x++;
}
// getStringFromRes(titles[position]);
tv.setText(titles[position]);
// Add The Image!!!
final ImageView iv = (ImageView)MyView.findViewById(R.id.grid_item_image);
Class<drawable> resources = R.drawable.class;
Field[] fields = resources.getFields();
String[] imageName = new String[fields.length];
int index = 0;
for( Field field : fields )
{
if(field.getName().startsWith("weather")){
imageName[index] = field.getName();
index++;
}
}
iv.setImageResource(getDrawable(myContext, imageName[position]));
iv.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
System.out.println("Clicked Item = " + titles[position]);
Bundle b = new Bundle();
if(titles[position].equals("Weather Overview")){
startActivity(new Intent(WeatherGridActivity.this, WeatherActivity.class));
}
if(titles[position].equals("Current Weather")){
b.putString("display", "current");
Intent intent = new Intent(WeatherGridActivity.this,WeatherActivity.class);
intent.putExtras(b);
startActivityForResult(intent, 0);
//startActivity(new Intent(WeatherGridActivity.this, WeatherActivity.class));
}
if(titles[position].equals("Ask a Question")){
startActivity(new Intent(WeatherGridActivity.this, AskQuestionActivity.class));
}
if(titles[position].equals("Average Temperature")){
startActivity(new Intent(WeatherGridActivity.this, AverageTemperatureActivity.class));
}
}
});
}
}catch(Exception e){
System.out.println("Error Occured = " + e.getMessage());
e.printStackTrace();
}
return MyView;
}
#Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
#Override
public int getCount() {
return 10;
}
public int getDrawable(Context context, String name){
Assert.assertNotNull(context);
Assert.assertNotNull(name);
return context.getResources().getIdentifier(name,"drawable", context.getPackageName());
}
public String getStringFromRes(String name){
try{
int resId = (Integer) R.string.class.getField(name).get(null);
// Toast.makeText(MyContext, getResources().getString(resId), Toast.LENGTH_LONG).show();
return getResources().getString(resId);
}catch(Exception e){
// no such string
return "empty";
}
}
}
Here is the xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/bg"
android:orientation="vertical" >
<GridView
android:id="#+id/weather"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/bg"
android:columnWidth="70dp"
android:gravity="center_horizontal"
android:horizontalSpacing="20dp"
android:numColumns="auto_fit"
android:padding="20dp"
android:stretchMode="columnWidth"
android:tileMode="repeat"
android:verticalSpacing="20dp" >
</GridView>
<ImageView
android:id="#+id/back_button"
style="#style/book_button" />
<com.google.ads.AdView
android:id="#+id/adView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
ads:adSize="BANNER"
ads:adUnitId="dummy id"
ads:loadAdOnCreate="true"
ads:testDevices="TEST_EMULATOR, TEST_DEVICE_ID" />
</LinearLayout>
</ScrollView>
I have added the RelativeLayout instead of LinerLayout and ScrollViews but now the entire Grid doesn't display but the ads displaying properly.
Here is the new xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"
android:id="#+id/home_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/bg"
>
<GridView
android:id="#+id/home_grid"
android:layout_width="wrap_content"
android:layout_height="0dip"
android:columnWidth="100dp"
android:rowHeight="30dp"
android:gravity="center_horizontal"
android:horizontalSpacing="5dp"
android:numColumns="auto_fit"
android:stretchMode="none"
android:tileMode="repeat"
android:verticalSpacing="30dp"
>
</GridView>
<com.google.ads.AdView
android:layout_alignParentBottom="true"
android:id="#+id/adView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
ads:adSize="BANNER"
ads:adUnitId="dummy id"
ads:loadAdOnCreate="true"
ads:testDevices="TEST_EMULATOR, TEST_DEVICE_ID"
android:layout_centerHorizontal="true" />
</RelativeLayout>
Your answers are highly appreciated
Thanks
Here is the working code. This fix the scrolling issue,the Admob issue and the onClickListener issue as well.
public class ImageAdapter extends BaseAdapter{
Context myContext;
public ImageAdapter(Context _myContext){
myContext = _myContext;
layoutInflater = LayoutInflater.from(myContext);
Resources res = getResources();
String[] items = res.getStringArray(R.array.weather_items);
titles = new String[items.length];
int x = 0;
for(String item:items){
titles[x]=item;
x++;
}
Class<drawable> resources = R.drawable.class;
Field[] fields = resources.getFields();
imageName = new String[fields.length];
int index = 0;
for( Field field : fields ){
if(field.getName().startsWith("weather")){
imageName[index] = field.getName();
index++;
}
}
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
// View MyView = convertView;
View grid = null;
try{
if ( convertView == null ){
grid = new View(myContext);
// LayoutInflater li = ((Activity)myContext).getLayoutInflater();
grid = layoutInflater.inflate(R.layout.weather_grid, null);
}else{
grid = (View)convertView;
}
TextView tv = (TextView)grid.findViewById(R.id.grid_item_text);
tv.setText(titles[position]);
ImageView iv = (ImageView)grid.findViewById(R.id.grid_item_image);
iv.setImageResource(getDrawable(myContext, imageName[position]));
iv.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
executeListners(position);
}
});
tv.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
executeListners(position);
}
});
}catch(Exception e){
System.out.println("Error Occured = " + e.getMessage());
e.printStackTrace();
}
return grid;
}
#Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
#Override
public int getCount() {
return 10;
}
public int getDrawable(Context context, String name){
Assert.assertNotNull(context);
Assert.assertNotNull(name);
return context.getResources().getIdentifier(name,"drawable", context.getPackageName());
}
public String getStringFromRes(String name){
try{
int resId = (Integer) R.string.class.getField(name).get(null);
// Toast.makeText(MyContext, getResources().getString(resId), Toast.LENGTH_LONG).show();
return getResources().getString(resId);
}catch(Exception e){
return "empty";
}
}
}
The xml files has no changes. This works with either RelativeLayout or with a LinearLayout
I would like to implement that kind of gallery, but with the difference of getting images remotly.
The idea is to update the view only when an image has been downloaded.
=> I need to update the view only when going to onComplete.
Please find below my code :
public class displayAlbums extends Activity {
private static String URL_GRAPH_API = "https://graph.facebook.com/";
private static final String TAG = "displayAlbums";
private ArrayList<Bitmap> thumbnails = new ArrayList<Bitmap>();
private ArrayList<URI> thumbnails_uri = new ArrayList<URI>();
private ImageAdapter imageAdapter;
private int imageCounter = 0;
public boolean[] thumbnailsselection;
public Albums album;
private Context displayAlbums_context;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.galleryitem);
this.displayAlbums_context = this;
Log.d(TAG, "on create");
findViewById(R.id.itemCheckBox).setVisibility(View.GONE);
final GridView imagegrid = (GridView) findViewById(R.id.PhoneImageGrid);
populateThumbnailsList();
processThumbnailsToDownload(thumbnails_uri, new PictureRequestListener() {
#Override
public void onComplete(Bitmap bitmap) {
if(imageAdapter == null) {
Log.d(TAG, "image adapter is null");
imageAdapter = new ImageAdapter(displayAlbums_context);
imagegrid.setAdapter(imageAdapter);
}
imagegrid.setId(imageCounter);
thumbnails.add(bitmap);
imageCounter++;
//imageAdapter.notifyDataSetChanged();
}
});
}
public void processThumbnailsToDownload(ArrayList<URI> thumbnails_uri, final FbRequestListener listener) {
Log.v(TAG,"processThumbnailsToDownload CALLED");
for(URI thumbnail_uri : thumbnails_uri ) {
new HttpConnection(ConnectionManager.getConnectionHandler(listener)).bitmap(thumbnail_uri);
}
}
public void populateThumbnailsList() {
URI uri = null;
for(final Albums album : LoadObjects.albums ) {
Bundle parameters = new Bundle();
parameters.putString("access_token", FbpicturesActivity.mFacebook.getAccessToken());
try {
uri = new URI(URL_GRAPH_API + album.getAid() + "/picture" + "?" +Util.encodeUrl(parameters) );
thumbnails_uri.add(uri);
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
public class ImageAdapter extends BaseAdapter {
private LayoutInflater mInflater;
private Context myContext;
public ImageAdapter(Context displayAlbums_context) {
Log.v(TAG,"IMAGE ADAPTER");
mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
Log.d(TAG,"thumnail_uri size"+thumbnails_uri.size());
return thumbnails_uri.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) {
Log.v(TAG,"GET VIEW CALLED");
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = mInflater.inflate(R.layout.galleryitem, null);
holder.imageview = (ImageView) convertView.findViewById(R.id.thumbImage);
holder.checkbox = (CheckBox) convertView.findViewById(R.id.itemCheckBox);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
//holder.checkbox.setId(position);
//holder.imageview.setId(position);
Log.d(TAG,"thumnail size"+thumbnails.size());
Log.d(TAG,"thumnail position"+thumbnails.get(position));
holder.imageview.setImageBitmap(thumbnails.get(position));
holder.checkbox.setChecked(true);
holder.id = position;
return convertView;
}
}
}
class ViewHolder {
ImageView imageview;
CheckBox checkbox;
int id;
}
galleryItem.xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_height="fill_parent">
<Button android:id="#+id/selectBtn"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="Select" android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:minWidth="200px" />
<GridView android:id="#+id/PhoneImageGrid"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:numColumns="auto_fit" android:verticalSpacing="10dp"
android:horizontalSpacing="10dp" android:columnWidth="90dp"
android:stretchMode="columnWidth" android:gravity="center"
android:layout_above="#id/selectBtn" />
<ImageView android:id="#+id/thumbImage" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_centerInParent="true" />
<CheckBox android:id="#+id/itemCheckBox" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_alignParentRight="true"
android:layout_alignParentTop="true" />
</RelativeLayout>
Please note i have added some Log.v to understand when getView is called :
=> http://pastebin.com/L9PYBYDa
questions :
1) Why getView is called 4 times ?
2) Why holder.imageview.setImageBitmap(thumbnails.get(position)) returns java.lang.IndexOutOfBoundsException: Invalid index 1, size is 1 ?
3) Do you have any advice to implement my gallery with remote image ?
Thank you very much for your help
1) getView will be called at least (numberOfVisibleRows+ 1 or +2) times. I say at least because it can be called as many times as the system wants. There is no guarantee on that.
2)Because thumbnails is lower than size 2 or is null. You have to debug to see that
3) Check this out