I have a simple GridView with custom Adapter in my layouts. My code is as follows:
CircleActivity.java:
public class CircleActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_circle);
List<Integer> listColors = new ArrayList<>();
listColors.add(getResources().getColor(R.color.colorAccent));
listColors.add(getResources().getColor(R.color.colorPrimary));
listColors.add(getResources().getColor(R.color.colorPrimaryDark));
GridView gridView = (GridView) findViewById(R.id.grid_colors);
CircleAdapter adapter = new CircleAdapter(this,listColors);
gridView.setAdapter(adapter);
}
}
activity_circle.xml:
<?xml version="1.0" encoding="utf-8"?>
<GridView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/grid_colors"
android:layout_width="match_parent"
android:layout_height="match_parent" />
CircleAdapter.java:
public class CircleAdapter extends BaseAdapter{
private Context context;
private List<Integer> listColor;
public CircleAdapter(Context context, List<Integer> listColor) {
this.listColor = listColor;
this.context = context;
}
#Override
public int getCount() {
return listColor.size();
}
#Override
public Integer getItem(int position) {
return listColor.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView==null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.row_grid,parent,false);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}
else{
holder = (ViewHolder) convertView.getTag();
}
holder.customCircleView.setFillColor(listColor.get(position));
holder.customCircleView.setCircleRadius(100);
return convertView;
}
static class ViewHolder{
private CustomCircleView customCircleView;
public ViewHolder(View row){
customCircleView = (CustomCircleView) row.findViewById(R.id.custom_circle_view);
}
}
}
row_grid.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:background="#color/colorAccent"
android:layout_width="match_parent"
android:gravity="center"
android:layout_height="match_parent">
<com.droidexperiments.gridexpand.CustomCircleView
android:id="#+id/custom_circle_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
custom:fill_color="#color/colorPrimary"
custom:circle_radius="50"
android:padding="25dp" />
</LinearLayout>
CircleView.java:
public class CustomCircleView extends View {
private int circleRadius = 20;
private int fillColor = Color.BLACK;
public CustomCircleView(Context context) {
super(context);
}
public CustomCircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public CustomCircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public CustomCircleView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray typedArray = context.obtainStyledAttributes(R.styleable.CustomCircle);
circleRadius = typedArray.getInteger(R.styleable.CustomCircle_circle_radius,20);
fillColor = typedArray.getColor(R.styleable.CustomCircle_fill_color, Color.BLACK);
typedArray.recycle();
}
public int getCircleRadius() {
return circleRadius;
}
public void setCircleRadius(int circleRadius) {
this.circleRadius = circleRadius;
}
public int getFillColor() {
return fillColor;
}
public void setFillColor(int fillColor) {
this.fillColor = fillColor;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setColor(fillColor);
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(canvas.getWidth()/2,canvas.getHeight()/2,circleRadius,paint);
}
}
attrts.xml:
<declare-styleable name="CustomCircle">
<attr name="fill_color" format="reference|color"/>
<attr name="circle_radius" format="integer"/>
</declare-styleable>
The issue is that screen remains blank and no row is inflated/showing in GridView.
I have checked everything. There is not any issue in GridView or the layout of grid row or in CustomCircleView. If I change adapter to simple ArrayAdapter, it works fine. So, there must be issue with my adapter:
I double checked getView() in adapter;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if(convertView==null){
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.row_grid,parent,false);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
}
else{
holder = (ViewHolder) convertView.getTag();
}
holder.customCircleView.setFillColor(listColor.get(position));
holder.customCircleView.setCircleRadius(100);
return convertView;
}
but couldn't identify why it shows blank. can anyone help me please?
When you implement a custom view, it is essential that you implement onMeasure. This method will tell the Android framework what size your view should be. Since you didn't specify this for CustomCircleView and used wrap_content in your layout, it had size zero. Therefore, all the elements of the GridView were invisible, making it look like the adapter was not working. I made a simple example implementation of onMeasure that solves your problem (just add this method in CustomCircleView):
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int size = View.MeasureSpec.makeMeasureSpec(2 * this.circleRadius, MeasureSpec.EXACTLY);
setMeasuredDimension(size, size);
}
The documentation advises that size stays within the given parameters (widthMeasureSpec and heightMeasureSpec). I have not included that restriction here, you can determine yourself what you want to do in that case.
You can find more information about this in the guide on creating custom components. Specific information about onMeasure can be found here.
Related
I tried to migrate my Chat Bot from ScrollView to a RecyclerView for performance, but unfortunally every method in my Adapter is called correctly but nothing is showed.
My Custom RecyclerView Adapter:
public class ChatViewAdapter extends RecyclerView.Adapter<ChatViewAdapter.ChatViewHolder> {
private LinkedList<ChatBubbleModel> bubbles;
private ViewGroup group;
public ChatViewAdapter() {
this(new LinkedList<ChatBubbleModel>());
}
public ChatViewAdapter(LinkedList<ChatBubbleModel> bubbles) {
this.bubbles = bubbles;
}
public LinkedList<ChatBubbleModel> getBubbles() {
return bubbles;
}
public void addBubble(ChatBubbleModel bubble) {
this.bubbles.add(bubble);
notifyDataSetChanged();
}
#NonNull
#Override
public ChatViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
this.group = parent;
return new ChatViewHolder(new TextView(parent.getContext()));
}
#Override
public void onBindViewHolder(#NonNull ChatViewHolder holder, int position) {
final ChatBubbleModel instance = this.bubbles.get(position);
if (instance.getUserType() == ChatBubbleModel.UserType.USER) {
holder.setTextView(new RightChatBubble(instance.getOwner(), instance.getMessage(), group.getContext()));
} else {
holder.setTextView(new LeftChatBubble(instance.getOwner(), instance.getMessage(), group.getContext()));
}
}
#Override
public int getItemCount() {
return this.bubbles.size();
}
public static class ChatViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
private TextView textView;
public ChatViewHolder(TextView v) {
super(v);
textView = v;
}
public void setTextView(TextView view) {
this.textView = view;
}
}
}
And in the Fragmnet where I use it:
final View root = inflater.inflate(R.layout.fragment_chatview, container, false);
chatView = root.findViewById(R.id.chatView);
chatView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(getContext());
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
chatView.setLayoutManager(layoutManager);
this.chatAdapter = new ChatViewAdapter(new LinkedList<ChatBubbleModel>());
chatView.setAdapter(chatAdapter);
The Impl of the View I use:
public class LeftChatBubble extends androidx.appcompat.widget.AppCompatTextView {
private final static int leftRightPadding = 50;
private final static int topBottomPadding = 20;
public LeftChatBubble(Context context) {
this(context, null, -1);
}
#SuppressLint("SetTextI18n")
public LeftChatBubble(String owner, String text, Context context) {
super(context);
setText(owner + "\n" + text);
setBackground(ContextCompat.getDrawable(context, R.drawable.inset));
setPadding(pixelToDp(leftRightPadding, context), pixelToDp(topBottomPadding, context), pixelToDp(leftRightPadding, context), pixelToDp(topBottomPadding, context));
setTextAlignment(TEXT_ALIGNMENT_VIEW_START);
setTextColor(Color.WHITE);
}
public LeftChatBubble(Context context, #Nullable AttributeSet attrs) {
this(context, attrs, -1);
}
public LeftChatBubble(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setBackground(ContextCompat.getDrawable(context, R.drawable.ic_chatbubleleft));
setPadding(pixelToDp(leftRightPadding, context), pixelToDp(topBottomPadding, context), pixelToDp(leftRightPadding, context), pixelToDp(topBottomPadding, context));
setTextAlignment(TEXT_ALIGNMENT_VIEW_START);
setTextColor(Color.WHITE);
}
private int pixelToDp(int px, Context context) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (px * scale + 0.5f);
}
}
Does anyone have an Idea why there is nothing showed on the device? The Used Layout is correct bc it worked before.
You did not seem to inflate your item view in the onCreateViewHolder like
#NonNull
#Override
public ChatViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
this.group = parent;
LayoutInflater inflater = LayoutInflater.from(this);
View view = inflater.inflate(R.layout.item_view, parent, false);
return new ChatViewHolder(view);
}
Also, change your ViewHolder args to be a View.
The Problem was that I not created the Correct View Class in onCreate Mathod of Adapter...
But thank you all for your helpful answers.
can a SurfaceView be rendered inside a RecyclerView
what i am trying to do is make a Grid of SurfaceView's
#Keep
public class NativeView {
String TAG = "EglSample";
public static native void nativeOnStart();
public static native void nativeOnResume();
public static native void nativeOnPause();
public static native void nativeOnStop();
// this is part of graphics manager
public native void nativeSetSurface(Surface surface);
View surfaceView = null;
SurfaceHolderCallback surfaceHolderCallback = null;
public NativeView(Context context) {
System.loadLibrary("nativeegl");
surfaceHolderCallback = new SurfaceHolderCallback();
surfaceView = new View(surfaceHolderCallback, context);
}
class View extends SurfaceView {
public View(SurfaceHolder.Callback callback, Context context) {
super(context);
getHolder().addCallback(callback);
}
public View(SurfaceHolder.Callback callback, Context context, AttributeSet attrs) {
super(context, attrs);
getHolder().addCallback(callback);
}
public View(SurfaceHolder.Callback callback, Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
getHolder().addCallback(callback);
}
public View(SurfaceHolder.Callback callback, Context context, AttributeSet attrs, int defStyle, int defStyleRes) {
super(context, attrs, defStyle, defStyleRes);
getHolder().addCallback(callback);
}
}
class SurfaceHolderCallback implements SurfaceHolder.Callback {
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
nativeSetSurface(holder.getSurface());
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
nativeSetSurface(null);
}
}
}
public ViewGroup onViewRequest(Context mContext) {
if (context == null) context = mContext;
if (n == null) n = new NativeView(context);
Log.i(n.TAG, "onViewRequest(Activity, Context)");
// build layout
RelativeLayout rel = new RelativeLayout(context);
rel.addView(n.surfaceView);
n.surfaceView.setOnClickListener(new MyListener());
// set text
TextView text = new TextView(context);
text.setText("Hello World! Try clicking the screen");
text.setTextSize(60f);
text.setTextColor(Color.WHITE);
rel.addView(text);
Log.i(n.TAG, "onCreate()");
// build layout
NativeView.nativeOnStart();
NativeView.nativeOnResume();
return rel;
}
full:
https://github.com/mgood7123/VSTDEMO/blob/0f5e7063d9ebef5ae5a05f128d548eec712b741f/vstdemoopengladdonscube/src/main/java/vst/demo/opengl/addons/cube/main.java
https://github.com/mgood7123/VSTDEMO/blob/0f5e7063d9ebef5ae5a05f128d548eec712b741f/vstdemoopengladdonscube/src/main/java/vst/demo/opengl/addons/cube/NativeView.java
as it renders corrupted in a recycler view (text but no surface view) (you can barely make out the white text but the fact that it is there means the view heirarchy IS being drawn)
(set USE_RECYCLER_VIEW = true)
https://github.com/mgood7123/VSTDEMO/blob/0f5e7063d9ebef5ae5a05f128d548eec712b741f/VstManager/src/main/java/vst/manager/VstGrid.java#L29
Boolean USE_RECYCLER_VIEW = false;
public LinearLayout getView() {
// this assumes the first available "*\.addons\.*" package
if (!USE_RECYCLER_VIEW) {
VST pkg = mVstMan.loadPackage(mActivity, mVstMan.getPackages(mActivity)[0].packageName, false);
VST.CLASS vstClass = mVstMan.loadClass(pkg, "main");
Object vstClassInstance = mVstMan.newInstance(vstClass, "main");
// android.widget.RelativeLayout cannot be cast to android.widget.LinearLayout
LinearLayout x = new LinearLayout(mActivity);
x.addView((ViewGroup) mVstMan.invokeMethod(
vstClass, vstClassInstance,
"onViewRequest", Context.class,
pkg.activityApplicationContext
)
);
return x;
} else {
if (recyclerViewMain == null)
recyclerViewMain = (LinearLayout) LayoutInflater.from(mActivity.getApplicationContext())
.inflate(R.layout.vst_grid, null, false);
if (recyclerView == null) {
recyclerView = recyclerViewMain
.findViewById(R.id.VstGrid);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
recyclerView.setHasFixedSize(true);
}
if (layoutManager == null) {
// use a linear layout manager
layoutManager = new GridLayoutManager(mActivity, 1);
recyclerView.setLayoutManager(layoutManager);
}
if (mAdapter == null) {
// specify an adapter (see also next example)
mAdapter = new VstGridAdapter(mActivity, mVstMan, mVstUI);
recyclerView.setAdapter(mAdapter);
}
mAdapter.update();
return recyclerViewMain;
}
}
https://github.com/mgood7123/VSTDEMO/blob/0f5e7063d9ebef5ae5a05f128d548eec712b741f/VstManager/src/main/java/vst/manager/VstGridAdapter.java#L86
// Create new views (invoked by the layout manager)
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
VST pkg = mVstMan.loadPackage(mActivity, mVstMan.getPackages(mActivity)[0].packageName, false);
VST.CLASS vstClass = mVstMan.loadClass(pkg, "main");
Object vstClassInstance = mVstMan.newInstance(vstClass, "main");
// android.widget.RelativeLayout cannot be cast to android.widget.LinearLayout
LinearLayout x = new LinearLayout(mActivity);
x.addView((ViewGroup) mVstMan.invokeMethod(
vstClass, vstClassInstance,
"onViewRequest", Context.class,
pkg.activityApplicationContext
)
);
return new MyViewHolder(x);
}
https://github.com/mgood7123/VSTDEMO/blob/0f5e7063d9ebef5ae5a05f128d548eec712b741f/vstdemoopengladdonscube/src/main/cpp/RotatingSquares/jniapi.cpp
https://github.com/mgood7123/VSTDEMO/blob/0f5e7063d9ebef5ae5a05f128d548eec712b741f/vstdemoopengladdonscube/src/main/cpp/RotatingSquares/renderer.cpp#L153
meanwhile it renders perfectly fine if NOT in a recycler view (leave USE_RECYCLER_VIEW as false)
why?
apparently in order to get it to display i needed to give the view fixed size layout paramaters: mView.setLayoutParams(new ViewGroup.LayoutParams(500, 500));
I am looking at creating dynamic heights in my RecyclerView to be responsive across all devices. Currently this works fine but for the first two rows at the start I have a double cell and the height of these two rows gets set to the first cell. I want instead this cell on both the first and second row to match the height of the last cell and become a rectangle. I have tried a few ways but none seem to work I am not sure where the problem is but I hope someone can show me. I will attach screenshots and the code below.
SquareLayout.java
public class SquareLayout extends LinearLayout {
public SquareLayout(Context context) {
super(context);
}
public SquareLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SquareLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int width, int height) {
// int width = MeasureSpec.getSize(widthMeasureSpec);
//int height = MeasureSpec.getSize(heightMeasureSpec);
// note we are applying the width value as the height
//if(width>=370){
// super.onMeasure(widthMeasureSpec, widthMeasureSpec/2);
// }
// else{
// super.onMeasure(widthMeasureSpec, widthMeasureSpec);
// }
super.onMeasure(width, width);
// Log.d("int","int is: "+ width);
}
}
DataAdapter.java
public class DataAdapter extends RecyclerView.Adapter<DataAdapter.ViewHolder> {
private ArrayList<AndroidVersion> android;
private Context context;
public DataAdapter(Context context,ArrayList<AndroidVersion> android) {
this.android = android;
this.context = context;
}
#Override
public DataAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.row_layout, viewGroup, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(DataAdapter.ViewHolder viewHolder, int i) {
// int width = viewHolder.tv_android.getMeasuredWidth() / 2; //returns -1
Log.d("MYINT", "value: " + i);
//Picasso.with(context).load(android.get(i).getAndroid_image_url()).resize(240, 120).into(viewHolder.img_android);
}
#Override
public int getItemCount() {
return android.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
private LinearLayout testheight;
private ImageView img_android;
public ViewHolder(View view) {
super(view);
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
private final String android_version_names[] = {
"test1",
"test2",
"test3",
"test4",
"test5",
"test6",
"test7",
"test8",
"test9",
"test10"
};
private final String android_image_urls[] = {
"http://example.com/images/test.png",
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews(){
RecyclerView recyclerView = (RecyclerView)findViewById(R.id.card_recycler_view);
recyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(getApplicationContext(),3);
ArrayList<AndroidVersion> androidVersions = prepareData();
((GridLayoutManager) mLayoutManager).setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
#Override
public int getSpanSize(int position) {
if (position == 0 || position == 2) {
return 2; // ITEMS AT POSITION 1 AND 6 OCCUPY 3 SPACES
}
else {
return 1; // OTHER ITEMS OCCUPY ONLY A SINGLE SPACE
}
}
});
recyclerView.setLayoutManager(mLayoutManager);
DataAdapter adapter = new DataAdapter(getApplicationContext(), androidVersions);
recyclerView.setAdapter(adapter);
}
private ArrayList<AndroidVersion> prepareData(){
ArrayList<AndroidVersion> android_version = new ArrayList<>();
for(int i=0;i<android_version_names.length;i++){
AndroidVersion androidVersion = new AndroidVersion();
androidVersion.setAndroid_version_name(android_version_names[i]);
androidVersion.setAndroid_image_url(android_image_urls[i]);
android_version.add(androidVersion);
}
return android_version;
}
}
row_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<example.SquareLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:background="#android:color/transparent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
android:layout_marginStart="10dp"
android:background="#color/reloadedpurple"
android:elevation="6dp"
android:orientation="vertical">
<ImageView
android:id="#+id/img_android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true" />
<TextView
android:id="#+id/tv_android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:textColor="#FFFFFF"
android:textStyle="bold" />
</LinearLayout>
</example.SquareLayout>
I have a custom TextView which I'm using in a custom GridView adapter. The custom TextView is using a custom font for translation purposes. This works fairly well in devices which have the locale installed by default.
However, in devices, in which the language is not installed, it is displaying a strange behavior. When the app loads the first time, the TextViews don't display with the custom font. However when I press the refresh button to reload the fragment, the TextViews display with the custom font.
I'm not sure why this is happening.
This is happening with all the custom Adapters in my application in which I'm using the custom TextView.
Pretty basic adapter:
public class CalendarWeekAdapter extends BaseAdapter{
private String[] weekdays;
Context mContext;
private LayoutInflater mInflater;
public CalendarWeekAdapter(Context context, int firstDay)
{
mContext=context;
mInflater = LayoutInflater.from(context);
weekdays = context.getResources().getStringArray(R.array.weekdays);
}
public int getCount()
{
return weekdays.length;
}
public Object getItem(int position)
{
return position;
}
public long getItemId(int position)
{
return position;
}
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder=null;
if(convertView==null)
{
convertView = mInflater.inflate(R.layout.calendar_week, parent,false);
holder = new ViewHolder();
holder.txtWeekdays=(CustomTextView)convertView.findViewById(R.id.weekdays);
if(position==0)
{
convertView.setTag(holder);
}
}
else
{
holder = (ViewHolder) convertView.getTag();
}
holder.txtWeekdays.setText(weekdays[position]);
return convertView;
}
}
class ViewHolder
{
CustomTextView txtWeekdays;
}
Basic CustomTextView:
public class CustomTextView extends TextView {
public CustomTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CustomTextView(Context context) {
super(context);
init();
}
private void init() {
if (!isInEditMode()) {
setTypeface(Utils.getFont(getContext()));
}
}
}
This is may not be the answer, but i don't understand this if-statement:
holder.txtWeekdays=(CustomTextView)convertView.findViewById(R.id.weekdays);
if(position==0)
{
convertView.setTag(holder);
}
Why is it there? All your newly inflated convertViews should have holder as their tag.
Just remove the 'if' around the convertView.setTag(holder):
if(convertView==null)
{
convertView = mInflater.inflate(R.layout.calendar_week, null,false);
holder = new ViewHolder();
holder.txtWeekdays=(CustomTextView)convertView.findViewById(R.id.weekdays);
convertView.setTag(holder);
}
...
and see if this will improve or even fix your situation.
I am attempting to fetch all the images from the SD Card and display them in a gridview (contained in a fragment). However, although no exceptions are thrown, nothing is displayed in the gridview, just a plain black screen. I'm not sure where the problem is, with the binding of the view or with the fetching of the data into the cursor. This is the current code for the fragment:
public class PhotoGridFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {
// member variables for
private static final int PHOTO_LIST_LOADER = 0x01;
private ImageCursorAdapter adapter;
private Cursor c;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getLoaderManager().initLoader(PHOTO_LIST_LOADER, null, this);
adapter = new ImageCursorAdapter(getActivity().getApplicationContext(), c);
}
/* R.layout.grid_item,
null, new String[] { MediaStore.Images.Thumbnails.DATA }, new int[] {R.id.grid_item},
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); */
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.photo_item, container, false);
}
// Loader manager methods
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = { MediaStore.Images.Thumbnails._ID, MediaStore.Images.Thumbnails.DATA };
CursorLoader cursorLoader = new CursorLoader(getActivity(),
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection,
null, null, null);
return cursorLoader;
}
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
adapter.swapCursor(cursor);
}
public void onLoaderReset(Loader<Cursor> cursor) {
adapter.swapCursor(null);
}
private class ImageCursorAdapter extends CursorAdapter {
private LayoutInflater mLayoutInflater;
private Context mContext;
public ImageCursorAdapter(Context context, Cursor c) {
super(context, c);
mContext = context;
mLayoutInflater = LayoutInflater.from(context);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
ImageView newView = (ImageView) view.findViewById(R.layout.grid_item);
String imagePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Thumbnails._ID));
if (imagePath != null && imagePath.length() != 0 && newView != null) {
newView.setVisibility(ImageView.VISIBLE);
}
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = mLayoutInflater.inflate(R.layout.grid_item, parent, false);
return v;
}
}
The layout files for the project are as follows:
photo_item.xml:
<?xml version="1.0" encoding="UTF-8"?>
<GridView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/photo_item"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="24dp"
android:padding="6dp" />
grid_item.xml:
<?xml version="1.0" encoding="utf-8"?>
<ImageView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/grid_item"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="24dp"
android:padding="6dp"
/>
in bindView, you're not actually setting the imageView's drawable to anything. You grab an image path, verify it's a real path, and then ignore it :) Use the path to get a drawable! Then set the imageView's drawable to that image.
Try this code
sdcard.java
public class Sdcard extends Activity {
// Cursor used to access the results from querying for images on the SD card.
private Cursor cursor;
// Column index for the Thumbnails Image IDs.
private int columnIndex;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sdcard);
// Set up an array of the Thumbnail Image ID column we want
String[] projection = {MediaStore.Images.Thumbnails._ID};
// Create the cursor pointing to the SDCard
cursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
projection, // Which columns to return
null, // Return all rows
null,
MediaStore.Images.Thumbnails.IMAGE_ID);
// Get the column index of the Thumbnails Image ID
columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Thumbnails._ID);
GridView sdcardImages = (GridView) findViewById(R.id.gridView1);
sdcardImages.setAdapter(new ImageAdapter(this));
}
private class ImageAdapter extends BaseAdapter {
private Context context;
public ImageAdapter(Context localContext) {
context = localContext;
}
public int getCount() {
return cursor.getCount();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView picturesView;
if (convertView == null) {
picturesView = new ImageView(context);
// Move cursor to current position
cursor.moveToPosition(position);
// Get the current value for the requested column
int imageID = cursor.getInt(columnIndex);
// Set the content of the image based on the provided URI
picturesView.setImageURI(Uri.withAppendedPath(
MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, "" + imageID));
picturesView.setScaleType(ImageView.ScaleType.FIT_XY);
picturesView.setPadding(10, 10, 10, 10);
picturesView.setLayoutParams(new GridView.LayoutParams(100, 100));
}
else {
picturesView = (ImageView)convertView;
}
return picturesView;
}
}
}