4

I have a ListView in my content_main.xml layout. The contents of this listview are set via listview.setAdapter(myCustomAdapter). I also have a TextView in the content_main.xml layout.

I created my own custom Adapter called ArrayAdapterItem which extends ArrayAdapter. In this adapter's getView() method I'm trying to get access to the TextView that is contained in content_main.xml. I don't know how to do that. I need to be able to do this because I want to update this TextView with new information if some item in the list is clicked. However I cannot gain access to this through parent.findViewbyId(R.id.main_activity_textView). This method is returning null at runtime.

I tried googling this, but only getting answers on different topics which is not related to mine.

I'm new to android. The solution to this might be simple, but I cannot find any tutorials or questions on stackoverflow that deal with this.

MainActivity.java

package com.example.simran.listviewtest;

    import android.app.AlertDialog;
    import android.os.Bundle;
    import android.support.design.widget.FloatingActionButton;
    import android.support.design.widget.Snackbar;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.Toolbar;
    import android.view.View;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.widget.ListView;

    public class MainActivity extends AppCompatActivity {
        AlertDialog alertDialogStores;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);

            showList();

            FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
            fab.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                            .setAction("Action", null).show();
                }
            });
        }

        public void showList(){

            // add your items, this can be done programatically
            // your items can be from a database
            ObjectItem[] ObjectItemData = new ObjectItem[20];

            ObjectItemData[0] = new ObjectItem(91, "Mercury");
            ObjectItemData[1] = new ObjectItem(92, "Watson");
            ObjectItemData[2] = new ObjectItem(93, "Nissan");
            ObjectItemData[3] = new ObjectItem(94, "Puregold");
            ObjectItemData[4] = new ObjectItem(95, "SM");
            ObjectItemData[5] = new ObjectItem(96, "7 Eleven");
            ObjectItemData[6] = new ObjectItem(97, "Ministop");
            ObjectItemData[7] = new ObjectItem(98, "Fat Chicken");
            ObjectItemData[8] = new ObjectItem(99, "Master Siomai");
            ObjectItemData[9] = new ObjectItem(100, "Mang Inasal");
            ObjectItemData[10] = new ObjectItem(101, "Mercury 2");
            ObjectItemData[11] = new ObjectItem(102, "Watson 2");
            ObjectItemData[12] = new ObjectItem(103, "Nissan 2");
            ObjectItemData[13] = new ObjectItem(104, "Puregold 2");
            ObjectItemData[14] = new ObjectItem(105, "SM 2");
            ObjectItemData[15] = new ObjectItem(106, "7 Eleven 2");
            ObjectItemData[16] = new ObjectItem(107, "Ministop 2");
            ObjectItemData[17] = new ObjectItem(108, "Fat Chicken 2");
            ObjectItemData[18] = new ObjectItem(109, "Master Siomai 2");
            ObjectItemData[19] = new ObjectItem(110, "Mang Inasal 2");

            // our adapter instance
            ArrayAdapterItem adapter = new ArrayAdapterItem(this, R.layout.list_view_row_item, ObjectItemData);

            // create a new ListView, set the adapter and item click listener
            ListView listViewItems = (ListView)findViewById(R.id.main_activity_listView);
            listViewItems.setAdapter(adapter);
            listViewItems.setOnItemClickListener(new OnItemClickListenerListViewItem());

        }

        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.menu_main, menu);
            return true;
        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
            int id = item.getItemId();

            //noinspection SimplifiableIfStatement
            if (id == R.id.action_settings) {
                return true;
            }

            return super.onOptionsItemSelected(item);
        }
    }

ArrayAdapterItem.java

            package com.example.simran.listviewtest;

        import android.app.Activity;
        import android.content.Context;
        import android.view.LayoutInflater;
        import android.view.View;
        import android.view.ViewGroup;
        import android.widget.ArrayAdapter;
        import android.widget.TextView;

        import org.w3c.dom.Text;

        /**
         * Created by simra on 12/23/2015.
         */
        public class ArrayAdapterItem extends ArrayAdapter<ObjectItem> {
            Context mContext;
            int layoutResourceId;
            ObjectItem data[] = null;

            public ArrayAdapterItem(Context mContext, int layoutResourceId, ObjectItem[] data) {
                super(mContext, layoutResourceId, data);

                this.layoutResourceId = layoutResourceId;
                this.mContext = mContext;
                this.data = data;
            }


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

                /*
                 * The convertView argument is essentially a "ScrapView" as described is Lucas post
                 * http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
                 * It will have a non-null value when ListView is asking you recycle the row layout.
                 * So, when convertView is not null, you should simply update its contents instead of inflating a new row layout.
                 */
                if (convertView == null) {
                    // inflate the layout
                    LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
                    convertView = inflater.inflate(layoutResourceId, parent, false);
                }

                //trying set the text of the textView in the main_activity.
                TextView mainActivityTextView = (TextView) parent.findViewById(R.id.main_activity_textView);
                mainActivityTextView.setText("some new text");

                // object item based on the position
                ObjectItem objectItem = data[position];

                // this sets the text and tag for the item in the list. Works fine
                TextView textViewItem = (TextView)   convertView.findViewById(R.id.textViewItem);
                textViewItem.setText(objectItem.itemName);
                textViewItem.setTag(objectItem.itemId);

                return convertView;

            }
        }

content_main.xml

     `<?xml version="1.0" encoding="utf-8"?>
        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingBottom="@dimen/activity_vertical_margin"
            android:paddingLeft="@dimen/activity_horizontal_margin"
            android:paddingRight="@dimen/activity_horizontal_margin"
            android:paddingTop="@dimen/activity_vertical_margin"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"
            tools:context="com.example.simran.listviewtest.MainActivity"
            tools:showIn="@layout/activity_main">

            <TextView
                android:id="@+id/hello_world"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Hello World!"
                android:layout_alignParentTop="true"/>

            <ListView
                android:id="@+id/options_list"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_below="@id/hello_world">

            </ListView>

        </RelativeLayout>`

list_view_row_item.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"
        android:padding="10dp" >

        <TextView
            android:id="@+id/textViewItem"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:text="Item name here..."
            android:textSize="15dp" />
    </RelativeLayout>

ObjectItem.java

    package com.example.simran.listviewtest;

/**
 * Created by simra on 12/23/2015.
 */
public class ObjectItem {
    public int itemId;
    public String itemName;

    // constructor
    public ObjectItem(int itemId, String itemName) {
        this.itemId = itemId;
        this.itemName = itemName;
    }
}
simcity
  • 57
  • 1
  • 7
  • you should implement a listener to the adapter which will make changes to textView when some item is clicked in the listView – Pankaj Nimgade Dec 24 '15 at 09:43
  • @PankajNimgade I don't know what you mean by that? Are you trying to say add a listener to each individual item in the getView() method of the Adapter? Can you elaborate what you are saying or what it would look like in the code? Or are you saying add the listener to the adaper in the mainActivity class? I'm new to Android so I have no idea what you mean. – simcity Dec 24 '15 at 09:49
  • @simcity, I am sorry for ambiguous comment, you can complete your requirement by simply adding a line of code and you will be done, I have answered that, Kindly check it – Pankaj Nimgade Dec 24 '15 at 10:11

5 Answers5

3

You have three options (just three examples):

  • Use the click listener provided with the ListView. (preferred method)
  • Inject the dependency through the adapters constructor.
  • Use the listener pattern to notify the activity.

Note: I'm not sure why you would need to update a TextView when the getView method gets called, getView can be called quit often (when scrolling for example), this means the TextView will almost update randomly. I would go for option 1 which is the most reliable and preferred way to react to clicks on items in your list.

Option 1:

public class ExampleActivity extends Activity implements OnItemClickListener {

    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //Set layout etc

        textView = (TextView) findViewById(some id); //Find the TextView

        ListView list = (ListView) findViewById(some id); //Find the ListView
        //Set adapter etc.
        list.setOnItemClickListener(this);
    }


    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int pos, long id) {
        textView.setText("Some text"); //Get the text from your adapter for example
    }
}

Option 2:

public ArrayAdapterItem(Context mContext, int layoutResourceId, ObjectItem[] data, TextView textview) {
    //etc.
}

Option 3:

Adapter:

    package com.example.simran.listviewtest;

    import android.app.Activity;
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.TextView;

    import org.w3c.dom.Text;

    /**
     * Created by simra on 12/23/2015.
     */
    public class ArrayAdapterItem extends ArrayAdapter<ObjectItem> {
        Context mContext;
        int layoutResourceId;
        ObjectItem data[] = null;
        ArrayAdapterItemCallback callback;

        public interface ArrayAdapterItemCallback {
            updateText(String text);
        }



        public ArrayAdapterItem(Context mContext, int layoutResourceId, ObjectItem[] data, ArrayAdapterItemCallback callback) {
            super(mContext, layoutResourceId, data);

            this.layoutResourceId = layoutResourceId;
            this.mContext = mContext;
            this.data = data;
            this.callback = callback;
        }


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

            /*
             * The convertView argument is essentially a "ScrapView" as described is Lucas post
             * http://lucasr.org/2012/04/05/performance-tips-for-androids-listview/
             * It will have a non-null value when ListView is asking you recycle the row layout.
             * So, when convertView is not null, you should simply update its contents instead of inflating a new row layout.
             */
            if (convertView == null) {
                // inflate the layout
                LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
                convertView = inflater.inflate(layoutResourceId, parent, false);
            }

            //trying set the text of the textView in the main_activity.
            callback.updateText("some new text");

            // object item based on the position
            ObjectItem objectItem = data[position];

            // this sets the text and tag for the item in the list. Works fine
            TextView textViewItem = (TextView)   convertView.findViewById(R.id.textViewItem);
            textViewItem.setText(objectItem.itemName);
            textViewItem.setTag(objectItem.itemId);

            return convertView;

        }
    }

Activity:

public class ExampleActivity extends Activity implements UpdateActivity {
    //etc.

    TextView text; //Init this in the onCreate

    @Override
    void updateText(String text){
         text.setText(text);
    }
}
Rolf ツ
  • 8,611
  • 6
  • 47
  • 72
  • Thanks for the answer. I had thought about this, but I thought maybe there was a simpler way in Android that I just didn't know of. Thanks again for quick response. – simcity Dec 24 '15 at 09:57
  • @simcity I have added an additional option for you ;) – Rolf ツ Dec 24 '15 at 10:02
1

When working with listview adapters in Android, they should almost always be placed as an inner class of the class using them - in this case it's your MainActivity class. When the adapter is an inner class it can use all the attributes of the enclosing class. If the textView you want to update isn't there already, that's where it should be.

Joakim
  • 3,224
  • 3
  • 29
  • 53
0

You can use the LocalBroadCastManager, bye this you can communicate within your app from anywhere to anywhere

You can check out , how to use the LocalBraodcastManager by using this.

how to use LocalBroadcastManager?

Community
  • 1
  • 1
Lakhwinder Singh
  • 6,799
  • 4
  • 25
  • 42
0

what you need is not very hard try to think again what exactly you want,

What you have is TextView to populate the information which is in an instance variable of instance ObjectItem type,

You can easily get the object from the list which is clicked like this

listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                ObjectItem singleItem = (ObjectItem) listView.getItemAtPosition(position);
                textView.setText(""+singleItem.itemName);
                //this is the textView which you should already get the reference in Main Activity

            }

        });

when you evaluate what you need it is easy to reduce the code, there is no need to implement some code which you may not use for any other work. Sorry for the comment but that is another way to turn your car around :)

Pankaj Nimgade
  • 4,529
  • 3
  • 20
  • 30
-1

you should replace :

parent.findViewById(...) by convertView.findViewById(...)
Michael Dorner
  • 17,587
  • 13
  • 87
  • 117
GiapLee
  • 436
  • 2
  • 8