Reference to TextView object from nested class - android

I'm new to Android programming and probably I don;t understand Java very well yet, so i got this problem with my program.
Every time I press button on my menu I get the java.lang.NullPointerException.
Is there any way to reference to this TextView object and change its text when item2 on menu is clicked?
public class MainActivity extends Activity {
TextView tv;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainActivity.this.tv = (TextView) findViewById(R.id.tekst1);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.mymenu, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.item2) {
MainActivity.this.tv.setText("aaa");
}
return super.onOptionsItemSelected(item);
}
}
EDIT:
mymenu xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="#+id/item1"
android:icon="#android:drawable/ic_menu_week"
android:title="Option 1"/>
<item
android:id="#+id/item2"
android:icon="#android:drawable/ic_menu_month"
android:title="Option 2"/>
</menu>
activity_main.xml
<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" >
<TextView
android:id="#+id/tekst1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="#string/hello_world"
tools:context=".MainActivity" />
</RelativeLayout>

You need to load the layout BEFORE retrieving the element.
Just replace
MainActivity.this.tv = (TextView) findViewById(R.id.tekst1);
setContentView(R.layout.activity_main);
By
setContentView(R.layout.activity_main);
MainActivity.this.tv = (TextView) findViewById(R.id.tekst1);
The findViewById method tries to find an element (from an ID) inside the hierarchy of the view. That's why you need to load this hierarchy (from the XML file) before! Otherwise you search in an empty hierarchy of views

You have to change your onCreate method to this:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MainActivity.this.tv = (TextView) findViewById(R.id.tekst1);
}
You have to reference your views after doing setContentView for your Activty.

By using the setContentView(int layoutResId) method android platform is creating all the view objects contained in your layout xml file provided to the setContentView(int layoutResId) method. This means that before the setContentView(int layoutResId) method is called the findViewById(int resId) method will return null for any view references in the layout, causing some potential NullpointerExceptions. To avoid these errors it's a good habit to place the setContentView(int layoutResId) method call at the very top of the onCreate() method.
Check this out : http://www.jayway.com/2009/03/26/layout-resources-in-android/

Related

Object reference becomes null on invoking findViewById() method

I'm learning actionviews and was following this short tutorial:
http://wptrafficanalyzer.in/blog/adding-custom-action-view-to-action-bar-in-android/
But I don't know why the EditText object becomes null at the runtime. Please help me with this.
MainActivity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
/** Create an option menu from res/menu/items.xml */
getMenuInflater().inflate(R.menu.items, menu);
/** Get the action view of the menu item whose id is search */
View v = (View) menu.findItem(R.id.search).getActionView();
/** Get the edit text from the action view */
EditText txtSearch = ( EditText ) v.findViewById(R.id.txt_search);
/** Setting an action listener */
txtSearch.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
Toast.makeText(getBaseContext(), "Search : " + v.getText(), Toast.LENGTH_SHORT).show();
return false;
}
});
return super.onCreateOptionsMenu(menu);
}
}
items.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/photo"
android:title="Photo"
app:showAsAction="ifRoom|withText"
/>
<item
android:id="#+id/video"
android:title="Video"
app:showAsAction="ifRoom|withText"
/>
<item
android:id="#+id/mobile"
android:title="Mobile"
app:showAsAction="ifRoom|withText"
/>
<item
android:id="#+id/search"
android:title="Search"
app:showAsAction="ifRoom|collapseActionView"
android:actionLayout="#layout/search_layout"
/>
</menu>
search_layout.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="match_parent"
android:orientation="horizontal">
<EditText
android:id="#+id/txt_search"
android:inputType="text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</RelativeLayout>
In your comment you stated the xml file names are search_layout.xml and items.xml. Now, in your code, you'll notice this line:
setContentView(R.layout.activity_main);
And this is important, so listen up: This line of code basically says, here is the corresponding xml file (layout resource element) that belongs to this java class. Now, what is the point of this? Well, if you want to access something that is in the content of an xml file called hello, and change the image of an image button, you cant do it until you specify where that image button is.
XML: I'm what the screen looks like!
Java: I'm what to do with some screen. What screen? Well, that screen is described in the setContentView line.
So, as you go deeper into android, you will start to get more and more XML files, and you need to specify which one you are talking about, so that the java (which is the brain of your program) knows what to do and where to do it.
Hope this helped, let me know if it did!
Ruchir
Your setContentView(R.layout.activity_main); layout is referencing to the wrong file. Change to (i guess is that the name of the file) setContentView(R.layout.search_layout);

TextView failure

I'm programming my first android app.
I want to set text on a TextView.
(I already searched here and found out, how to do it...But it still don't work)
Do you know, what the problem is?
This is my Java code.
package com.example.randomcraps;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.TextView;
import com.example.*;
public class MainActivity extends Activity {
TextView text = (TextView) findViewById(R.layout.number);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
public void getRandomNumber(){
int i;
double savePoint;
savePoint = Math.random();
savePoint = savePoint*100+1;
i = (int)savePoint;
text.setText(i);
}
}
This is my XML Code
<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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginTop="26dp"
android:text="#string/Button1"
android:onClick="getRandomNumber" />
<TextView
android:id="#+id/number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="#string/RandomNumber" />
</RelativeLayout>
Change to
TextView text;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.number); // id of textview in activity_main.xml
}
findViewById looks for a view with the id mentioned in the current inflated layout. So you need to set layout to the activity and then initialize your views.
Also change
text.setText(i);
// looks for a resource with the id mentioned if not found you get ResourceNotFoundException
To
text.setText(String.valueOf(i));
// int i; i is an int value. Use String.valueOf(intvalue)
Edit:
Your method signature is different. It should be
public void getRandomNumber(View V){ // missing View as param
... //rest of the code
}
Coz you have
android:onClick="getRandomNumber"
Quoting from docs
public static final int onClick
Name of the method in this View's context to invoke when the view is clicked. This name must correspond to a public method that takes exactly one parameter of type View. For instance, if you specify android:onClick="sayHello", you must declare a public void sayHello(View v) method of your context (typically, your Activity).
Change your code to this.
TextView text;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.number);
}
Also
text.setText(String.valueOf(i));
NOTE: findViewByID finds view from content. So basically you have to use that method after you set your content.
Set text color after setText and for guarantee set the font size. Sometimes it makes the color default white.

Android - Popup menu when list item view pressed?

i would like to implement a popup menu similar to google's play store as shown below.
so basically from what i understand, i'll need an activity and a layout for this activity with a listview defined in it. i need to create my custom adapter. also, i need to create a list layout would contain the information and a view (with the 3 dots) that will serve as the button to launch the popup menu? the issue that i'm seeing here is that how do i create a listener for this view only and how do i reference the value for that specific list item in the list view.
i don't have any code available yet as i haven't started anything related to this. i'm currently getting info in theory for now but if required i will create a sample code.
thanks.
Using popup menu it's quite simple to create a menu with these three steps:
1 - Add a click listener to the menu button using OnClickListener or as i prefer from the layout xml:
<ImageButton android:id="#+id/menu_button" android:onClick="showMenu" ... />
2 - Create the menu layout menu_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/item_settings"
android:showAsAction="ifRoom|withText"
android:title="Settings"
android:visible="true"/>
<item
android:id="#+id/item_about"
android:showAsAction="ifRoom|withText"
android:title="About"
android:visible="true"/>
</menu>
3 - Create a popup menu, inflate the xml layout and show it:
public void showMenu (View view)
{
PopupMenu menu = new PopupMenu (this, view);
menu.setOnMenuItemClickListener (new PopupMenu.OnMenuItemClickListener ()
{
#Override
public boolean onMenuItemClick (MenuItem item)
{
int id = item.getItemId();
switch (id)
{
case R.id.item_settings: Log.i (Tag, "settings"); break;
case R.id.item_about: Log.i (Tag, "about"); break;
}
return true;
}
});
menu.inflate (R.menu.menu_layout);
menu.show();
}
ActionBarCompat List PopupMenu implementation is here (with back port available because it uses ABC)!
You can also get this sample from Github or from SDK (Mr.Morgan commented below)
/sdk/samples/android-19/ui/ActionBarCompat-ListPopupMenu. Make sure to
install Samples for SDK under Android 4.4.2 (API 19)
You can use like this:
public class MainActivity extends Activity {
ListView listView_Actions;
ArrayList<String> actionsArrayList;
Button btn_ViewPopUp;
ArrayAdapter<String> actionsAdapter;
static final int CUSTOM_DIALOG_ID1 = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_ViewPopUp=(Button) findViewById(R.id.btn_ViewPopUp);
actionsArrayList=new ArrayList<String>();
actionsArrayList.add("Action 1");
actionsArrayList.add("Action 2");
}
#Override
protected void onStart() {
super.onStart();
btn_ViewPopUp.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showDialog(CUSTOM_DIALOG_ID1);
actionsAdapter = new MyCustomBaseAdapter(getApplicationContext(), R.layout.list_actions, actionsArrayList);
listView_Actions.setAdapter(actionsAdapter);
}
});
}
#Override
protected Dialog onCreateDialog(int id) {
Dialog dialog = null;
switch (id) {
case CUSTOM_DIALOG_ID1:
dialog = new Dialog(MainActivity.this);
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
dialog.setContentView(R.layout.list_actions);
listView_Actions = (ListView) dialog.findViewById(R.id.listView_Actions);
break;
}
return dialog;
}
class MyCustomBaseAdapter extends ArrayAdapter<String>
{
public MyCustomBaseAdapter(Context context, int textViewResourceId, ArrayList<String> actionsArrayList) {
super(context, textViewResourceId,actionsArrayList);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = inflater.inflate(R.layout.action_list_cell, null);
final TextView lblContactAction;
lblContactAction = (TextView) v.findViewById(R.id.txtContactAction);
lblContactAction.append(actionsArrayList.get(position));
return v;
}
}
}
Now XML files:
action_list_cell.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"
android:background="#android:color/background_light" >
<TextView
android:id="#+id/txtContactAction"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=""
android:textSize="18dp"
android:textColor="#android:color/black" />
</LinearLayout>
list_actions.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"
android:background="#drawable/rounded_corner_top">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#DB6A16"
android:orientation="vertical"
android:paddingBottom="2dp"
android:paddingLeft="2dp"
android:paddingRight="2dp" >
<ListView
android:id="#+id/listView_Actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff" >
</ListView>
</LinearLayout>
</LinearLayout>
</LinearLayout>
first of all you need to make your custom adapter with a view that has the 3 dots.
then in the getView() or newView() method you set the listener to the 3 dots image.
i think that PopupMenu is what you are looking for, it's is supported since API 11.
if you want to support also earlier version of the API you can use PopupMenu class provided by the support library v7.
the usage is pretty straight forward.
you define it with the id of the view you want the menu to show next to, and then you can directly inflate a menu resource there as if it was a common menu.
Now showDialog is deprecated, use PopupMenu instead
And AppCompat PopupMenu f you want to support version before V11
public class MainActivity extends Activity {
Button button1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//Creating the instance of PopupMenu
PopupMenu popup = new PopupMenu(MainActivity.this, button1);
//Inflating the Popup using xml file
popup.getMenuInflater().inflate(R.menu.popup_menu, popup.getMenu());
//registering popup with OnMenuItemClickListener
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
Toast.makeText(MainActivity.this,"You Clicked : " + item.getTitle(),Toast.LENGTH_SHORT).show();
return true;
}
});
popup.show();//showing popup menu
}
});//closing the setOnClickListener method
}
}
You have to set the Listener of the Button in the getView()-Method of your List-Adapter.
In this getView()-Method you assign a Layout to one List-Item. if you have done this, you just have to set the Listener on this View (Button), and handle the onClick() Event.
Not sure if i understand you correctly but you can trigger this method to open a pop up dialog with a listview.
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Title if Any");
builder.setItems(R.array.listoptions, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int itemClicked) {
String[] option_array = getResources().getStringArray(R.array.listoptions);
String optionSelected = option_array[itemClicked];
}
});
return builder.create();
}
See Adding a List
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="listoption">
<item>Install</item>
<item>Add to listview</item>
</string-array>
</resources>
Hope this helps.

Android ActionBar setActionView layout issue

I've been trying to use the setActionView from the ActionBar in ICS
Seems like it should be straight forward but somehow I'm not getting the layout alignment that I would hope for. As you can see in the image below the 'target' icon is centered correctly within it's layout. But when I setActionBar(progress) the progress view is always aligned to the right whatever I try.
Here are the 2 states, before and after clicking the menu item. As you can see the progress view is always aligned to the right. I've tried changing the gravity options in the my progress layout xml from left to right to center and whatever I do change it doesn't seem to change anything.
I haven't found any info regarding this problem so I'm thinking I must be doing something wrong.
Do anyone have a clue?
Thanks for the help!
Here's my action bar menu layout 'action_bar_menu.xml'
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="#+id/locate"
android:title="locate"
android:icon="#drawable/locate"
android:showAsAction="ifRoom|withText" />
</menu>
Here's my progressbar layout 'inderterminate_progress.xml'
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ProgressBar android:layout_width="25dp"
android:layout_height="25dp"
android:layout_gravity="center"
android:indeterminate="true"
style="?android:attr/progressBarStyleInverse"/>
</FrameLayout>
And finally here's my testx Activity
public class HelloAndroidActivity extends Activity {
/**
* Called when the activity is first created.
* #param savedInstanceState If the activity is being re-initialized after
* previously being shut down then this Bundle contains the data it most
* recently supplied in onSaveInstanceState(Bundle). <b>Note: Otherwise it is null.</b>
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
getActionBar().setTitle("Test");
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.action_bar_menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
if (R.id.locate == item.getItemId()) {
final MenuItem menuItem = item.setActionView(R.layout.inderterminate_progress);
new Thread(new Runnable() {
#Override
public void run() {
SystemClock.sleep(3000);
runOnUiThread(new Runnable() {
#Override
public void run() {
menuItem.setActionView(null);
}
});
}
}).start();
}
return true;
}
}
It seems that explicitly defining the style and adding a 4dip padding in the root of the layout to inflate as shown below solves this issue
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="4dip"
android:paddingRight="4dip"
style="?android:attr/actionButtonStyle" />
This seems to be used in the android stylesheet here
A little late but the right solution is not an absolute value such as 4dp. The right approach is to set the minWidth to ABS values:
android:minWidth="#dimen/abs__action_button_min_width"
Example progress bar:
<?xml version="1.0" encoding="utf-8"?>
<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="#dimen/abs__action_button_min_width"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="true"
android:layout_gravity="center"
style="#android:style/Widget.ProgressBar.Small"/>

Accessing a view inside ActionBar

I'm trying to add an Horizontal Progress bar to my view like so:
res/menu.xml
<item android:id="#+id/menuItemProgress"
android:title="Progress"
android:actionLayout="#layout/component_cancellable_progressbar"
android:showAsAction="always"/>
component_cancellable_progressbar.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/searchProgressWrapper"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
<ProgressBar android:id="#+id/searchProgress"
android:layout_height="30dp"
android:layout_width="150dp"
style="#style/Custom.Widget.ProgressBar.Horizontal"
android:max="100" />
<ImageView android:id="#+id/cancelSearch"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:paddingRight="8dp"
android:layout_gravity="right|center_vertical"
android:src="#android:drawable/ic_notification_clear_all"
android:scaleType="fitXY" />
</FrameLayout>
How do I access this ProgressBar from within an Action (To make it Visisble / Invisible / Progress) ?
it is possible to get the view of the action item.
however, do note that sometimes action items get to be inside the overflow menu so you might get a null instead.
so, how can you do it?
here's a sample code:
public boolean onCreateOptionsMenu(final Menu menu) {
getSupportMenuInflater().inflate(R.menu.main, menu);
new Handler().post(new Runnable() {
#Override
public void run() {
final View syncItemView = findViewById(R.id.action_search);
...
this was tested when using actionBarSherlock library, on android 4.1.2 and android 2.3.5 .
another alternative is to use a more extensive way , used on the showcaseView library, here .
onCreate() and after you can simply access it via findViewById() like normal. Problem was caused by something else.
You can override onCreateOptionsMenu and catch your view there:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.getItem(0).getActionView();
...
or by searching the id
View v = (View) menu.findItem(R.id.search).getActionView();
I inserted a custom drop down menu in the action bar and was able to gain control of it this way.
Following is a very helpful link for actionBar.Hope you will able to implement what you want.
http://thiranjith.wordpress.com/2011/07/15/actionbar-design-pattern-example-for-android/
public class ActionBar extends FrameLayout {
private ProgressBar mProgress;
public ActionBar(Context context, AttributeSet attrs) {
super(context, attrs);
mInflater =(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
FrameLayout barView = (RelativeLayout) mInflater.inflate(R.layout.actionbar, null);
addView(barView);
mProgress = (ProgressBar) barView.findViewById(R.id.actionbar_progress);
public void showProgressBar() { ... }
public void hideProgressBar() { ... }
public boolean isProgressBarVisible() { ... }
}
Then from your activity control your progressbar like following.
public class MainActivity extends Activity {
private ActionBar mActionBar;
#Override
public void onCreate(Bundle savedInstanceState) {
mActionBar = (ActionBar) findViewById(R.id.actionBar);
mActionBar.showProgressbar()
}
}

Categories

Resources