Kev_oh Kev_oh - 5 months ago 19
Android Question

Dynamically generating edittext in listview

In my fragment i want to display images selected from gallery and display them in a list view. Each list view item will consist of an ImageView for the image and an EditText for the caption. I am getting a nullpointerexception at caption.setText(mAllCaptions.get(position)) where I want to give a default caption such as Photo 1 from an ArrayList of captions named mAllCaptions. Any ideas

list_item_selected_image.xml

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/selected_imageImageView"/>

<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/selected_imageCaptionEditText"
android:background="@color/white"
android:hint="@string/add_caption"
android:textColorHint="@color/input_hint"
android:textColor="@color/dark_grey"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:padding="10dp"/>

</LinearLayout>


Inner class SelectedImagesAdapter

private class SelectedImagesAdapter extends ArrayAdapter<String>{


public SelectedImagesAdapter(ArrayList<String> imagesArray){

super(getActivity(),0,imagesArray);

for (int i = 0; i < imagesArray.size(); i++) {

int j = ++i;
String defaultCaption = "Photo " + j;
mAllCaptions.add(defaultCaption);
}
notifyDataSetChanged();

}//end constructor

@Override
public int getCount(){

return mAllCaptions.size();
}


@Override
public View getView(int position, View convertView, ViewGroup parent){

//if we arent given a view inflate one
//if there's no recycled view passed in inflate one

if(convertView == null)
convertView = getActivity()
.getLayoutInflater()
.inflate(R.layout.list_item_selected_image, null);

//configure the view for this image
String imagePath = getItem(position);
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);
//get the screen width at run time
int screenWidth = DeviceDimensionsHelper.getDisplayWidth(getActivity());
//load resized bitmap into an ImageView

ImageView imageView = (ImageView)convertView.findViewById(R.id.selected_imageImageView);

imageView.setImageBitmap(BitmapScaler.scaleToFitWidth(bitmap, screenWidth));

EditText caption = (EditText)convertView.findViewById(R.id.selected_imageCaptionEditText);

caption.setText(mAllCaptions.get(position));
caption.setId(position);

//update adapter once we finish editing
caption.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {

if (!hasFocus){
final int position = v.getId();
final EditText Caption = (EditText) v;
mAllCaptions.set(position, Caption.getText().toString());

}


}
});

return convertView;//return view object to the list view

}
}//end private class ImagesAdapter


Error Log

java.lang.NullPointerException
at com.photos.android.photos.PhotosFragment$SelectedImagesAdapter.getView(PhotosFragment.java: 278)
at android.widget.AbsListView.obtainView(AbsListView.java: 2259)
at android.widget.ListView.makeAndAddView(ListView.java: 1813)
at android.widget.ListView.fillDown(ListView.java: 688)
at android.widget.ListView.fillDown(ListView.java: 667)
at android.widget.ListView.fillFromTop(ListView.java: 759)
at android.widget.ListView.layoutChildren(ListView.java: 1666)
at android.widget.AbsListView.onLayout(AbsListView.java: 2110)
at android.view.View.layout(View.java: 13947)
at android.view.ViewGroup.layout(ViewGroup.java: 4472)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java: 1687)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java: 1545)
at android.widget.LinearLayout.onLayout(LinearLayout.java: 1450)
at android.view.View.layout(View.java: 13947)
at android.view.ViewGroup.layout(ViewGroup.java: 4472)
at android.support.v4.view.ViewPager.onLayout(ViewPager.java: 1627)
at android.view.View.layout(View.java: 13947)
at android.view.ViewGroup.layout(ViewGroup.java: 4472)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java: 1687)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java: 1545)
at android.widget.LinearLayout.onLayout(LinearLayout.java: 1450)
at android.view.View.layout(View.java: 13947)
at android.view.ViewGroup.layout(ViewGroup.java: 4472)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java: 1687)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java: 1545)
at android.widget.LinearLayout.onLayout(LinearLayout.java: 1450)
at android.view.View.layout(View.java: 13947)
at android.view.ViewGroup.layout(ViewGroup.java: 4472)
at android.widget.FrameLayout.onLayout(FrameLayout.java: 460)
at android.view.View.layout(View.java: 13947)
at android.view.ViewGroup.layout(ViewGroup.java: 4472)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java: 1687)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java: 1545)
at android.widget.LinearLayout.onLayout(LinearLayout.java: 1450)
at android.view.View.layout(View.java: 13947)
at android.view.ViewGroup.layout(ViewGroup.java: 4472)
at android.widget.FrameLayout.onLayout(FrameLayout.java: 460)
at android.view.View.layout(View.java: 13947)
at android.view.ViewGroup.layout(ViewGroup.java: 4472)
at android.widget.LinearLayout.setChildFrame(LinearLayout.java: 1687)
at android.widget.LinearLayout.layoutVertical(LinearLayout.java: 1545)
at android.widget.LinearLayout.onLayout(LinearLayout.java: 1450)
at android.view.View.layout(View.java: 13947)
at android.view.ViewGroup.layout(ViewGroup.java: 4472)
at android.widget.FrameLayout.onLayout(FrameLayout.java: 460)
at android.view.View.layout(View.java: 13947)
at android.view.ViewGroup.layout(ViewGroup.java: 4472)
at android.view.ViewRootImpl.performLayout(ViewRootImpl.java: 1883)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java: 1704)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java: 1011)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java: 4244)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java: 725)
at android.view.Choreographer.doCallbacks(Choreographer.java: 555)
at android.view.Choreographer.doFrame(Choreographer.java: 525)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java: 711)
at android.os.Handler.handleCallback(Handler.java: 615)
at android.os.Handler.dispatchMessage(Handler.java: 92)
at android.os.Looper.loop(Looper.java: 213)
at android.app.ActivityThread.main(ActivityThread.java: 4793)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java: 511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java: 789)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java: 556)
at dalvik.system.NativeStart.main(Native Method)

Answer

The solution i had given earlier brought me some problems because edittext values were being interchanged on scrolling, i.e when the ListView redrwas itself, so here is the final solution with no bugs thanks to this link

 //custom adapter as inner class
private class SelectedImagesAdapter extends BaseAdapter{

    private LayoutInflater mInflater;
    int size = 0;

    public SelectedImagesAdapter() {
        mInflater = (LayoutInflater)getActivity()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        this.size = mPhotosPathList.size();

        int j = 1;
        for (int i = 0; i < size; i++) {

            String defaultCaption = "Photo " + j;
            etStrings.add(defaultCaption);
            j++;
        }


    }//end constructor

    @Override
    public int getCount() {


        return size;
    }

    @Override
    public Object getItem(int position) {
        return position;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }


    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {

        //if we arent given a view inflate one
        //if there's no recycled view passed in inflate one
        final ViewHolder holder;
        if (convertView == null) {

            holder = new ViewHolder();
            convertView = mInflater.inflate(R.layout.list_item_selected_image, null);
            holder.caption = (EditText)
                    convertView.findViewById(R.id.selected_imageCaptionEditText);

            holder.photo = (ImageView)
                    convertView.findViewById(R.id.selected_imageImageView);
            convertView.setTag(holder);

            holder.mWatcher = new EditTextWatcher();
            holder.caption.addTextChangedListener(holder.mWatcher);

        }else {

            holder = (ViewHolder)convertView.getTag();

        }

        holder.mWatcher.setActive(false);
        holder.caption.setText(etStrings.get(position));
        holder.mWatcher.setPosition(position);
        holder.mWatcher.setActive(true);

        Bitmap bitmap = BitmapFactory.decodeFile(mPhotosPathList.get(position));
        //get the screen width  at run time
        int screenWidth = DeviceDimensionsHelper.getDisplayWidth(getActivity());
        //load resized bitmap into an ImageView
        holder.photo.setImageBitmap(BitmapScaler.scaleToFitWidth(bitmap, screenWidth));


        return convertView;//return view object to the list view

    }
}//end private class ImagesAdapter

class ViewHolder {
    EditText caption;
    ImageView photo;
    public EditTextWatcher mWatcher;

}

class EditTextWatcher implements TextWatcher{


    private int mPosition;
    private boolean mActive;

    void setPosition(int position){
        mPosition = position;
    }
    void setActive(boolean active){
        mActive = active;
    }
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

    }

    @Override
    public void afterTextChanged(Editable s) {
        if(mActive){
            etStrings.set(mPosition, s.toString());

        }
    }
}
Comments