I am trying to set visibility of two imageviews inside a custom listview based on the value in a textView in the same listview. But, I am getting a NullPointerException
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.ImageView.setVisibility(int)' on a null object reference
on the line
iv_in_time.setVisibility(View.INVISIBLE);
My Java file is:
public class Attendance extends AppCompatActivity {
ImageButton ib_clear_srch;
EditText et_srch;
TextView tv_emp_name, tv_emp_status, tv_emp_in_time, tv_emp_out_time;
ImageView iv_in_time, iv_out_time, iv_pop_down, iv_emp_img;
ArrayList<EmpAttenModel> empAttenModelArrayList;
private EmpAttenAdapter empAttenAdapter;
ListView lv_emp_attendance;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_attendance);
et_srch = (EditText)findViewById(R.id.et_srch);
ib_clear_srch = (ImageButton)findViewById(R.id.ib_clear_srch);
ib_clear_srch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
et_srch.setText(null);
}
});
View v;
tv_emp_name = (TextView)findViewById(R.id.tv_emp_name);
tv_emp_status = (TextView)findViewById(R.id.tv_emp_status);
tv_emp_in_time = (TextView)findViewById(R.id.tv_emp_in_time);
tv_emp_out_time = (TextView)findViewById(R.id.tv_emp_out_time);
iv_in_time = (ImageView)findViewById(R.id.iv_in_time);
iv_out_time = (ImageView)findViewById(R.id.iv_out_time);
iv_pop_down = (ImageView)findViewById(R.id.iv_pop_down);
iv_emp_img = (ImageView)findViewById(R.id.iv_emp_img);
lv_emp_attendance = (ListView)findViewById(R.id.lv_emp_atten);
empAttenModelArrayList = new ArrayList<>();
empAttenModelArrayList.add(new EmpAttenModel("Ravi Sharma", "Status-Absent","In time", "Out time"));
empAttenModelArrayList.add(new EmpAttenModel("Ravi Sharma", "Status-Working","9:30 AM", "Out time"));
empAttenModelArrayList.add(new EmpAttenModel("Ravi Sharma", "Status-Present","9:30 AM", "5:00 PM"));
empAttenAdapter = new EmpAttenAdapter(empAttenModelArrayList,getApplicationContext());
lv_emp_attendance.setAdapter(empAttenAdapter);
TextView tv1;
for (int i = 0; i < lv_emp_attendance.getCount(); i++){
v = lv_emp_attendance.getAdapter().getView(i, null, null);
tv1 = (TextView)v.findViewById(R.id.tv_emp_status);
if(tv1.getText().toString().equals("Status-Absent")){
iv_in_time.setVisibility(View.INVISIBLE);
iv_out_time.setVisibility(View.INVISIBLE);
tv_emp_in_time.setVisibility(View.INVISIBLE);
tv_emp_out_time.setText("In time");
}
if(tv1.getText().toString().equals("Status-Working")){
iv_out_time.setVisibility(View.INVISIBLE);
}
}
}
}
Can anyone tell me how to solve this issue?
It seems it doesn't find the view with the id you provide and so your view get to be null and you can't make operations on it (other than check if it's null or not).
If both the imageviews and the textview you wanna work on are part of the layout of the row of your listview, as I believe, I think it would be easier to do you check directly in the adapter, where you create the view and set the right values.
Checking for the values and views in the activity just complicates things. You can do the check you're already doing in the adapter, where you have all your views correctly initialised.
you should check the imageview
if(iv_in_time != null){
iv_in_time.setVisibility(View.INVISIBLE);
}
Related
I am doing bubble display of selected contacts. Each telephone bubble is a LinearLayout, which contains ImageView and TextView. These bubbles are then displayed in another LinearLayout which is child of HorizontalScrollView.
It child/parent tree looks like this:
- HorizontalScrollView
|- LinearLayout (id="#+id/telField")
|- LinearLayout (id="#+id/telBox") <- is programmatically added to parent
|- TextView (id="#+id/telNumber")
|- ImageView (id="#+id/delNumber")
In my .java class I call this method to display "telBox" LinearLayout in "telField" LinearLayout:
public void createAdapter() {
telList = new ArrayAdapter<>(this, R.layout.text_buble, R.id.telNumber, telNumList);
telField = (LinearLayout) findViewById(R.id.telField);
telField.removeAllViews();
final int adapterCount = telNumList.size();
for (ik = 0; ik < adapterCount; ik++) {
final View item = telList.getView(ik, null, null);
telField.addView(item);
item.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
telField.removeView(item);
telNumList.remove(ik-1);
telList.notifyDataSetChanged();
refresh();
}
});
}
}
Method refresh(); – is custom method which helps to "reload" Activity: it gets App values, refreshes warning ImageViews and cals createAdapter() method.
Big button "SELECT" calls an Intent which returns a selected phone number from a contacts book. I call this code to update my LinearLayout with id "telField":
telNumList.add(cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER)));
createAdapter();
Problem I face is:
After I click on LinearLayout with id "telNumber" it one by one deletes every bubble (no matter which I clicked) until it reaches first added bubble. It also crashes 50/50 when reaches first added element, I have not figured out a dependency. The error it returns is "out of bounds error", so I think it is connected with ik - 1 line.
My question is: How do I better construct my ArrayAdapter?
In your code you are trying to remove the view by ik which is getting change continuously because of which your coding is removing last view I have modified your code as given below
for (ik = 0; ik < adapterCount; ik++) {
final int position=ik;
final View item = telList.getView(ik, null, null);
telField.addView(item);
item.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
telField.removeView(item);
telNumList.remove(position);
telList.notifyDataSetChanged();
//refresh();
createAdapter();
}
});
}
Here position will help you to remove the particular view which you want to remove. I hope this is what you are asking for.
Inside your for loop, write these line of code:
for (ik = 0; ik < adapterCount; ik++) {
final View item = telList.getView(ik, null, null);
item.setTag(ik);
telField.addView(item);
item.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
int index = Integer.parseInt(v.getTag().toString());
telNumList.remove(index);
refresh();
}
});
}
Hope it will help you out.
Usually when I have many elements in my android app, onCreate looks like this:
onCreate(){
ImageButton b1 = (ImageButton)findViewById(R.id.b1) ;
ImageButton b2 = (ImageButton)findViewById(R.id.b2) ;
ImageVuew v3 = (ImageButton)findViewById(R.id.v3) ;
ViewSwitcher v4 = (ViewSwitcher)findViewbyId(R.id.v4) ;
TextView v5 = (TextView)findViewById(R.id.v5) ;
//and so on
}
Android requires to do this class cast for every text,image,button etc in the app. But text,image,button,switcher are all subclasses of View class!
I try to add all views into one array of Views and loop through like this:
View[]clickableViews = {forkImageView, patronImageView,cabelImageView1,cabelImageView2, bulb_switcher,doublePlugImageView,kettleBaseImageView,kettleSwitcher} ;
int []image_views_ids = {R.id.forkImage, R.id.patronImage, R.id.bulb_switcher, R.id.cabel1, R.id.cabel2, R.id.longcabel, R.id.kettle_base, R.id.kettleSwitcher};
for( int i = 0 ; i < clickableViews.length;i++){
clickableViews[i] = findViewById(image_views_ids[i]);
}
It may throw class cast exception
Is there a way to still do it smart way?
Try the library Butterknife, I think its what you are looking for. It will make your code cleaner :)
The example from the website is:
class ExampleActivity extends Activity {
#InjectView(R.id.title) TextView title;
#InjectView(R.id.subtitle) TextView subtitle;
#InjectView(R.id.footer) TextView footer;
#Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.inject(this);
// TODO Use "injected" views...
}
}
You should cast into View class,too.
Your code will be like:
View[]clickableViews = {forkImageView, patronImageView,cabelImageView1,cabelImageView2, bulb_switcher,doublePlugImageView,kettleBaseImageView,kettleSwitcher} ;
int []image_views_ids = {R.id.forkImage, R.id.patronImage, R.id.bulb_switcher, R.id.cabel1, R.id.cabel2, R.id.longcabel, R.id.kettle_base, R.id.kettleSwitcher};
for( int i = 0 ; i < clickableViews.length;i++){
clickableViews[i] =(View)findViewById(image_views_ids[i]);
}
I am having a listview. Initially I get such row item.
But when I scroll down, then at some positions I get this,
I am not getting why this is happening. Here I am using TreeObserver to get width of firsttext view, so as to get the length of string displayed in firsttextview and display the rest in other.
Here is the code for this, I have two layouts inflated, I am posting code for this one.
if(type==0){
if(convertView==null){
convertView= inflater.inflate(R.layout.incoming_msg_row,parent, false);
holder=new ViewHolder();
holder.messageFirstPart = (TextView) convertView
.findViewById(R.id.messageFirstPart);
holder.messageLeftPart = (TextView) convertView
.findViewById(R.id.messageLeftPart);
holder.username= (TextView) convertView.findViewById(R.id.SendersName);
holder.time=(TextView) convertView.findViewById(R.id.timestamp);
holder.leftline=convertView.findViewById(R.id.leftline);
holder.rightline=convertView.findViewById(R.id.rightline);
holder.view3=convertView.findViewById(R.id.incoming_msg_row_innerlayout);
convertView.setTag(holder);
}
else
holder = (ViewHolder) convertView.getTag();
holder.messageFirstPart.setText(message[position]);
holder.username.setText("John");
holder.time.setText(timestamp[position]);
RelativeLayout mineLayout=
(RelativeLayout)convertView.findViewById(R.id.incoming_msg_row_innerlayout);
RelativeLayout.LayoutParams params=(LayoutParams) mineLayout.getLayoutParams();
for(int i=0;i<x.length;i++){
System.out.println(x[i]);
if(position==x[i]){
holder.time.setVisibility(View.GONE);
holder.leftline.setVisibility(View.GONE);
holder.rightline.setVisibility(View.GONE);
params.topMargin=20;
// holder.view3.requestLayout();
mineLayout.setLayoutParams(params);
break;
}
else{
holder.time.setVisibility(View.VISIBLE);
holder.leftline.setVisibility(View.VISIBLE);
holder.rightline.setVisibility(View.VISIBLE);
// params.topMargin+=0;
// holder.view3.requestLayout();
params.topMargin=90;
mineLayout.setLayoutParams(params);
}
}
if(position==0){
holder.time.setVisibility(View.VISIBLE);
holder.leftline.setVisibility(View.VISIBLE);
holder.rightline.setVisibility(View.VISIBLE);
params.topMargin=90;
mineLayout.setLayoutParams(params);
}
holder.messageFirstPart.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
#SuppressWarnings("deprecation")
#SuppressLint("NewApi")
#Override
public void onGlobalLayout() {
// TODO Auto-generated method stub
width = holder.messageFirstPart.getWidth();
int totalCharstoFit;
String chat = holder.messageFirstPart.getText().toString();
String substring=null,substringtwo=null;
totalCharstoFit =
holder.messageFirstPart.getPaint().breakText(chat, 0,
chat.length(), true, width, null);
substring = chat.substring(0, totalCharstoFit);
substringtwo = chat.substring(substring.length(),
chat.length());
holder.messageFirstPart.setText(chat);
holder.messageLeftPart.setText(substringtwo);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
holder.messageFirstPart.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
} else {
holder.messageFirstPart.getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
}
}
});
}
Hello world is a constant text defined somewhere in strings or in xml for the textview.
Check in xml that whether you have given. android:text="Hello world" or you mentioned in strings.xml and used that in textview. android:text="#string/hello" if you mentioned that in strings.
Hello world is usually a sort of "default text" you get after you created a new project and, probably, when you create your ListView's row, in the xml, you left the android:text field set with that string, and because of the recycling system of the ListView you are getting the default text. you have probably forget to set the text for that TextView
Try to define adapter like this;
ListView lv = (ListView) dialog.findViewById(R.id.lv);
lv.refreshDrawableState();
AdapterClass adapter = new AdapterClass (context, R.layout.row, adpArray);
try {
adapter.setNotifyOnChange(true);
adapter.notifyDataSetChanged();
} catch (Exception e) {
// TODO: handle exception
}
lv.invalidate();
lv.setAdapter(adapter);
lv.invalidate();
yaa.. there default text is HEllo world.. bt removing it.. makes text
view null at those postions where hello world was coming.
Ok. So i guess it might be due to "substringtwo" object returning null. Can you try moving
holder.messageLeftPart.setText(substringtwo);
into below if block
//Check for not string object null and non empty and not containing string value null
if(!TextUtils.isEmpty(substringtwo) && !substringtwo.equalsIgnoreCase("null")) {
//set message text here
}
OR
try initializing variable substringtwo to empty string i.e. String substringtwo = "";
I'm trying to TDD/test the text colour of a textView for android. However all of the properties seem to return either 0 or null, does anyone know why?
The code creating the text view:
public void setupTextView() {
LinearLayout layout = (LinearLayout) findViewById(R.id.layout);
TextView textView = new TextView(this);
textView.setText(job.getName());
if (job.getLastBuild().getBuildStatus().equals("SUCCESS")) {
textView.setTextColor(Color.parseColor("#007000"));
} else {
textView.setTextColor(Color.parseColor("#FF0000"));
}
layout.addView(textView);
}
I've ran the application and the code above works.
The properties I've tried accessing in the test code:
#Test
public void firstTextViewShouldReflectPassingJobStatus() throws Exception {
LinearLayout layout = layout = (LinearLayout) activity.findViewById(R.id.layout);
TextView gomoTextView = (TextView) layout.getChildAt(0);
System.out.println(gomoTextView.getCurrentTextColor()); //Returns 0
System.out.println(gomoTextView.getTextColors()); //Returns null
System.out.println(gomoTextView.getSolidColor()); //Returns 0
System.out.println(gomoTextView.getCurrentHintTextColor()); //Returns 0
//I also tried using `Robolectric.shadowOf()`:
ShadowTextView shadowGomoTextView = Robolectric.shadowOf(gomoTextView);
System.out.println(shadowGomoTextView.getTextColorHexValue()); //Returns 0
System.out.println(shadowGomoTextView.getHintColorHexValue()); //Returns null
}
Update to answer comments
I have a before in the unit test class which calls onCreate():
private LinearLayout layout;
private HomeActivity activity;
#Before
public void setUp() throws Exception {
activity = spy(new HomeActivity());
Jenkins mockJenkins = TestUtilities.getTestJenkins();
when(activity.getJenkins()).thenReturn(mockJenkins);
activity.onCreate(null);
layout = (LinearLayout) activity.findViewById(R.id.layout);
}
And the the onCreate method in the HomeActivity class:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Jenkins jenkins = getJenkins();
displayJenkins(jenkins);
}
And then display jenkins calls a load of other methods which include setupTextView()
Looking to the sources it's not implemented yet. I would suggest you to implement your own shadow as described here.
Robolectric 2.0 has been promoted to the alpha state. I think you issue should be fixed during release since they are going to use as much as possible real Android source code.
can anyone help me with coding a method to get all EditTexts in a view? I would like to implement the solution htafoya posted here:
How to hide soft keyboard on android after clicking outside EditText?
Unfortunately the getFields() method is missing and htafoya did not answer our request to share his getFields() method.
EDIT
MByD pointed me to an error, thus making my answer almost identical to that of blackbelt. I have edited mine to the correct approach.
You could do a for-each loop and then check if each view is of the type EditText:
ArrayList<EditText> myEditTextList = new ArrayList<EditText>();
for( int i = 0; i < myLayout.getChildCount(); i++ )
if( myLayout.getChildAt( i ) instanceof EditText )
myEditTextList.add( (EditText) myLayout.getChildAt( i ) );
You could also, instead of having a list of EditTexts, have a list of ID's and then just add the id of the child to the list: myIdList.add( child.getId() );
To access your layout you need to get a reference for it. This means you need to provide an ID for your layout in your XML:
<LinearLayout android:id="#+id/myLinearLayout" >
//Here is where your EditTexts would be declared
</LinearLayout>
Then when you inflate the layout in your activity you just make sure to save a reference to it:
LinearLayout myLinearLayout;
public void onCreate( Bundle savedInstanceState ) {
super( savedInstanceState );
setContentView( R.layout.myLayoutWithEditTexts );
...
myLinearLayout = (LinearLayout) findViewById( R.id.myLinearLayout );
}
You then have a reference to your the holder of your EditTexts within the activity.
Here's a method I wrote to recursively check all EditText children of a ViewGroup, handy for a long sign-up form I had to do and probably more maintainable.
private EditText traverseEditTexts(ViewGroup v)
{
EditText invalid = null;
for (int i = 0; i < v.getChildCount(); i++)
{
Object child = v.getChildAt(i);
if (child instanceof EditText)
{
EditText e = (EditText)child;
if(e.getText().length() == 0) // Whatever logic here to determine if valid.
{
return e; // Stops at first invalid one. But you could add this to a list.
}
}
else if(child instanceof ViewGroup)
{
invalid = traverseEditTexts((ViewGroup)child); // Recursive call.
if(invalid != null)
{
break;
}
}
}
return invalid;
}
private boolean validateFields()
{
EditText emptyText = traverseEditTexts(mainLayout);
if(emptyText != null)
{
Toast.makeText(this, "This field cannot be empty.", Toast.LENGTH_SHORT).show();
emptyText.requestFocus(); // Scrolls view to this field.
}
return emptyText == null;
}
You can do it by calling View#getFocusables, which will return an arraylist of all focusable views in a View.
Then you can either check if they are EditTexts, with (instanceof) or act on all of them.
This Methods walks recursively through all ViewGroups and collects their TextViews. I use this to assign a new Color to all TextViews (even those embedded in predefined Widgets like Switch etc that make use of TextViews)
private HashSet<TextView> getTextViews(ViewGroup root){
HashSet<TextView> views=new HashSet<>();
for(int i=0;i<root.getChildCount();i++){
View v=root.getChildAt(i);
if(v instanceof TextView){
views.add((TextView)v);
}else if(v instanceof ViewGroup){
views.addAll(getTextViews((ViewGroup)v));
}
}
return views;
}
Get all Edit Text in any type of layout.
public List<EditText> getAllEditTexts(ViewGroup layout){
List<EditText> views = new ArrayList<>();
for(int i =0; i< layout.getChildCount(); i++){
View v =layout.getChildAt(i);
if(v instanceof EditText){
views.add((EditText)v);
}
}
return views;
}