I am creating an extremely simple Android application to serve as a proof of concept and a reference for an application I will create in the future.
My goal is to create a ListView, each item containing a TextView and a Button that, when pressed, makes a Toast pop up displaying the content of the TextView.
Here is my code and xml:
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ListView
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#+id/mainListView1"/>
</LinearLayout>
entry.XML:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical"
android:orientation="horizontal"
android:id="#+id/entryLayout"
>
<TextView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:id="#+id/entryTextView1"
android:padding="10dp"
android:textSize="25sp"/>
<ImageButton
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="#android:drawable/ic_menu_close_clear_cancel"
android:id="#+id/entryImageButton"
/>
</LinearLayout>
MainActivity.Class
public class MainActivity extends Activity{
/* Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Set main.xml as user interface layout
setContentView(R.layout.main);
String[] companies = new String[] { "Test1", "Test2", "Test3",
"Test4", "Test4", "Test6", "Test7", "Test8", "Test9", "Test10"};
ArrayList<LinearLayout> views = new ArrayList<LinearLayout>();
for(int x=0; x!= companies.length-1; x++){
LinearLayout layout = (LinearLayout) findViewById(R.id.entryLayout);
TextView text = (TextView) layout.getChildAt(0);
text.setText(companies[x]);
ImageButton button = (ImageButton) layout.getChildAt(1);
button.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v){
LinearLayout layout = (LinearLayout) v.getParent();
TextView view = (TextView) layout.getChildAt(0);
Toast.makeText(MainActivity.this,view.getText(), Toast.LENGTH_SHORT).show();
}
});
views.add(layout);
}
ListView listView = (ListView) findViewById(R.id.mainListView1);
for(LinearLayout layout: views){
listView.addView(layout);
}
}
I get an Kin the line
TextView text = (TextView) layout.getChildAt(0);
And for the life of me I can't figure out why. This is likely due to my lack of knowledge to how certain functions in the API work.
Your immediate issue is that findViewById looks in the layout you've inflated with setContentView() and since the Views you are trying to inflate aren't in that layout, they return null.
So this line returns null
LinearLayout layout = (LinearLayout) findViewById(R.id.entryLayout);
which causes a NPE at this line as you've noticed
TextView text = (TextView) layout.getChildAt(0);
because layout is null.
The bigger issue is the way you are going about using your ListView. Since you want to use a custom layout for the rows, you should be using a custom Adapter and inflate the appropriate layout there . You can then utilize Adapter's getView() method to set the data in each row as needed.
This tutorial can help you get started on that.
You also may want to watch Google I/O World of ListView
ListView Docs
Related
I have an XML file that has a TextView, and I want to change its gravity from the main activity.
I used this code in the main activity:
// I just coppied the related codes
TextView tvValue;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvValue = findViewById(R.id.tv_value);
// the tv_value id is from the (word_item.xml) file
}
private void OnClickFunc(View view) {
tvValue.setGravity(Gravity.RIGHT);
}
and the problem is that I get a NullPointerException error on a null object reference.
I know that I should somehow connect the xml file with the main activity.
word_item.xml file:
<?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="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<TextView
android:id="#+id/tv_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Word" />
</LinearLayout>
Thank you and I appreciate your help.
if you havent included the word_item.xml in your activity_main.xml then the error is obvious
so this is how you can include another file in any xml file in android
<include layout="#layout/word_item.xml" />
then things ll work as you expect
Try to first inflate the other layout as follows the initialize the view
LayoutInflater inflater = LayoutInflater.from(MainActivity.this); final View v = inflater.inflate(R.layout.word_item, null);
Then
Textview tvValue = findViewById(R.id.tv_value); private void OnClickFunc() { tvValue.setGravity(Gravity.RIGHT);
Where did you initialize textView variable?? Variable must be initialize after setContentView in OnCreate method in Activity.
I want to inflate TextViews to LinearLayout.
I have a layout activity_play_game and java class PlayGameActivity.
Currently, for hardcoded number of TextViews it looks like this:
Now I tried to add number of TextViews according to the value of variable numberForbiddenWords. I added a piece of code that looks like this:
LinearLayout playGame = (LinearLayout) findViewById(R.id.activity_play_game);
TextView temp;
TextView[] textViews = new TextView[numberForbiddenWords];
for(int i = 0; i < numberForbiddenWords; i++) {
temp = new TextView(this);
playGame.addView(temp);
textViews[i] = temp;
}
And I have a method that adds textViews to the activity_play_game. Unfortunately now it looks like this:
As you can see it added TextViews at the bottom. So I removed all TextViews from activity_play_game and added LinearLayout to inflate TextViews:
How can I inflate TextViews to this LinearLayout above the buttons?
I found that kind of solution:
activity_to_add_words:
<?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"
android:orientation="vertical">
<TextView
android:id="#+id/textout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
In the java class:
final View addView;
LayoutInflater layoutInflater = (LayoutInflater) getBaseContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
addView = layoutInflater.inflate(R.layout.activity_to_add_words,
null);
final TextView textOut = (TextView) addView.findViewById(R.id.textout);
but this is for a View, not TextView. Do you know how to do it?
Get reference of your LinearLayout container_blue and add TextView's to it.
Try this:
LinearLayout playGame = (LinearLayout) findViewById(R.id.container_blue);
TextView temp;
TextView[] textViews = new TextView[numberForbiddenWords];
for(int i = 0; i < numberForbiddenWords; i++) {
temp = new TextView(this);
temp.setText("TextView " + String.valueOf(i));
temp.setId(i);
temp.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
playGame.addView(temp);
textViews[i] = temp;
}
make one layout file using textview like this :
layout_textview.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:id="#+id/txt_spin"
android:textSize="18sp"
android:background="#fff"
android:padding="5dp"
android:textColor="#000"
android:layout_height="wrap_content"/>
then apply following code in your java file:
LinearLayout playGame = (LinearLayout) findViewById(R.id.container_blue);
LayoutInflater li =(LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = li.inflate(R.layout.layout_textview, null);
TextView txt= (TextView) view.findViewById(R.id.txt_spin);
playGame.addView(view);
Hope it works for you...happy coding..:)
As far as I see your initial problem was about adding the items dynamically before the three buttons. If you want to add them before the three buttons simply call playGame.addView(temp,0); This will always add the item to the first position in the layout.
If you need a specific order of the added views you need to play with the for loop to add them in the right order.
I spent an hour trying to add "Load More" Button and indeterminate ProgressBar to the footer of my ListView.
The supposed scinario works like this:
When the button is clicked, ProgressBar is shown while AsyncTask is downloading 20 items. when the items are inserted to the ListView, the ProgressBar dismisses and the Button appears again in the footer.
I come to the following solution and would be nice if you have better solution:
layout/progress_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/load_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
/>
And assuming you have the following fields in the Activity:
private ListView listview;
private Button loadMoreButton;
private ProgressBar progressBar;
after preparing your list view add the footer like this, (at the end of the activity.onCreate()):
loadMoreButton = new Button(this);
loadMoreButton.setText("Load More");
progressBar = (ProgressBar) LayoutInflater.from(this).inflate(R.layout.progress_bar, null);
loadMoreButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//downloadItems();
listview.removeFooterView(loadMoreButton);
listview.addFooterView(progressBar);
}
});
When the data is ready (either first page or subsequent pages), call the following after adapter update.
//adapter.notifyDataSetChanged();
listview.removeFooterView(progressBar);
listview.addFooterView(loadMoreButton);
If you have better solutions, please share it in the answers.
Instead of removing and adding a view as footer.. you can have both button and progressbar in the same footer view and make visibility VISIBLE and Visibility GONE according to the requirement.
I came to a solution without adding/removing the footer. Just put the two views (Load More Button and ProgressBar) in LinearLayout. Add the linearlayout as listview footer for first time only. Then change between the button and progressbar by changing visibility property.
Here is the updated code:
layout/list_footer.xml
<?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="vertical">
<Button
android:id="#+id/load_more_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:text="Load More"/>
<ProgressBar android:id="#+id/load_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone"
android:indeterminate="true" />
</LinearLayout>
call this method at the end of Activity.onCreate() to add footer and handle button click (load data, hide button and show progress).
private void prepareListFooter() {
View view = (View) LayoutInflater.from(this).inflate(R.layout.list_footer, null);
loadMoreButton = (Button) view.findViewById(R.id.load_more_button);
progressBar = (ProgressBar) view.findViewById(R.id.load_progress);
listview.addFooterView(view);
loadMoreButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//downloadMore();
loadMoreButton.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
}
});
}
also this code after adapter change to show the button and hide the progress.
adapter.notifyDataSetChanged();
loadMoreButton.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
I am trying to write an Android Wear application. For now I've got a TextView and would like to set the text programmatically.
private TextView mTextView;
private TextView text;
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
setContentView(R.layout.activity_my);
final WatchViewStub stub = (WatchViewStub)findViewById(R.id.watch_view_stub);
text = (TextView)findViewById(R.id.text);
stub.setOnLayoutInflatedListener((stub -> {
mTextView = (TextView)stub.findViewById(R.id.text);
}};
text.setText("test");
}
When trying to run the application like that I get a nullpointerexception at
text.setText("test");
That led me to assume that the TextView "text" was not found. Normally on Android phone applications it is just fine to call the
text = (TextView)findViewById(R.id.text);
Directly after
setContentView();
But now there are things like the WatchViewStub and the setOnLayoutInflatedListener. Maybe there's something I've overseen?
However, how do I specify my TextView correctly on the Android Wear platform?
Edit:
activity_my.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.wearable.view.WatchViewStub
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:id="#+id/watch_view_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:rectLayout="#layout/rect_activity_my"
app:roundLayout="#layout/round_activity_my"
tools:context=".MyActivity"
tools:deviceIds="wear">
</android.support.wearable.view.WatchViewStub>
rect_activity.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MyActivity"
tools:deviceIds="wear_square">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/text"
android:textSize="30sp"
android:layout_centerInParent="true"/>
</RelativeLayout>
round_activity.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MyActivity"
tools:deviceIds="wear_round">
<TextView
android:id="#+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/text"
android:textSize="30sp"
android:layout_centerInParent="true"/>
</RelativeLayout>
According to code from your Activity:
private TextView mTextView;
private TextView text;
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
setContentView(R.layout.activity_my);
final WatchViewStub stub = (WatchViewStub)findViewById(R.id.watch_view_stub);
text = (TextView)findViewById(R.id.text);
stub.setOnLayoutInflatedListener((stub -> {
mTextView = (TextView)stub.findViewById(R.id.text);
}};
text.setText("test");
}
Why do you have two TextViews? You have only one either in your rect_activity: or round_activity: layouts.
You have to understand how WatchViewStub works. You cannot access views from your rect/round layouts right after setContentView because they are not inflated yet. Like you did - you can access your views only in OnLayoutInflatedListener listener callback.
You have tried to find your mTextView inside this callback - which is the way you should do it.
What is wrong?
You should remove following lines:
text = (TextView)findViewById(R.id.text);
and this one: (it also causes your NullPointerException)
text.setText("test");
and keep only the mTextView field.
What should you do?
Add following like right after mTextView = (TextView)stub.findViewById(R.id.text);:
mTextView.setText("test");
It must be incide the OnLayoutInflatedListener.
Your final code should look like:
private TextView mTextView;
public void onCreate(Bundle savedInstance) {
super.onCreate(savedInstance);
setContentView(R.layout.activity_my);
final WatchViewStub stub = (WatchViewStub)findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener((stub -> {
mTextView = (TextView)stub.findViewById(R.id.text);
mTextView.setText("test");
}};
}
You do not have TextView in activity_my.xml
text = (TextView)findViewById(R.id.text);
if rect_activity.xml and round_activity.xml are for different activities then you need to create new activities and call setContentView for those xml
Only after that you can use the views in your code.
Instead of adding an OnLayoutInflatedListener you can extend InsetActivity and set your content view in InsetActivity.onReadyForContent():
import android.support.wearable.activity.InsetActivity;
public class MainActivity extends InsetActivity {
...
#Override
public void onReadyForContent() {
setContentView(R.layout.activity_main);
someTextField = (TextView) findViewById(R.id.some_field);
I cannot figure out why but I keep getting E/AndroidRuntime(709): java.lang.NullPointerException at any point I try to call the buttons titled yes and no. The buttons are created in an xml layout and called using the findViewById method, a similar technique I've used in several properly working buttons in the same program. The only difference between these buttons and the rest is that their xml code is kept in a separate layout file that is not the main.xml.
If I only want to show the buttons and don't call them within the java code they will show up just as they should. The error occurs when I try to apply anything to them in the java code, such as setClickable() and setOnClickListener().
The code below outlines the creation of the button and layout in the xml and the java code shows a method that creates a popup when called.
Java Code:
private void getLogoutOption() {
LayoutInflater layoutInflater = (LayoutInflater)getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE);
View popupView = layoutInflater.inflate(R.layout.logoutoption, null);
final PopupWindow logoutoption = new PopupWindow(popupView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
Button yes = (Button) findViewById (R.id.yes);
yes.setClickable(true);
yes.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
logoutoption.dismiss();
switchActivity(8);
}
});
Button no = (Button) findViewById (R.id.no);
no.setClickable(true);
no.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
logoutoption.dismiss();
}
});
logoutoption.showAsDropDown(search, 50, -30);
}
XML CODE:
<?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:background="#android:color/transparent" >"
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/menu_default" >
<TextView
android:id="#+id/logoutmessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:text="Are you sure you would like to logout?"
android:textColor="#color/gold" />
<Button
android:id="#+id/yes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/logoutmessage"
android:layout_centerInParent="true"
android:text="YES"
android:textColor="#color/green" />
<Button
android:id="#+id/no"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/logoutmessage"
android:layout_toRightOf="#id/yes"
android:text="NO"
android:textColor="#color/red" />
</RelativeLayout>
</RelativeLayout>
Button yes = (Button) findViewById (R.id.yes);
should be
Button yes = (Button) popupView.findViewById (R.id.yes);
By default findViewById() will be searching your content view for the view with the specified ID (e.g. if you used setContentView(R.layout.main), it will be searching through the main.xml structure for those views). If you're searching an inflated layout, you have to call findViewById() on that particular inflated layout.
Change:
Button yes = (Button) findViewById (R.id.yes);
Button no = (Button) findViewById (R.id.no);
To:
Button yes = (Button) popupView.findViewById (R.id.yes);
Button no = (Button) popupView.findViewById (R.id.no);
Hi The problem is you are getting id as you take in Activity.In Activity view created by setContentView(R.layout.main).In Your code you are inflating new view so you should use
Button yes = (Button)popupView.findViewById (R.id.yes);