How do I refactor findViewById without class cast exception? - android

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]);
}

Related

How to create method which will find view by Id and set it into variable?

There are several switches, which must be set same way:
private SwitchCompat switch1,switch2,...,switch10;
private void initSwitch(#NonNull SwitchCompat switchCompat) {
switchCompat.setOnCheckedChangeListener(this);
switchCompat.setTypeface(...);
}
How to pass switch id to initSwitch, so it would set all variables switch1, switch2, ..., switch10?
Because this will not work:
private void init(){
initSwitch(switch1, R.id.switch1)
initSwitch(switch1, R.id.switch2)
...
initSwitch(switch1, R.id.switch10)
}
private void initSwitch(#NonNull SwitchCompat switchCompat,int id) {
switchCompat.findById(id)
switchCompat.setOnCheckedChangeListener(this);
switchCompat.setTypeface(...);
}
As an answer to your question, I agree with Nilesh Rathod
But for this purpose a suggest you use something like ButterKnife
class ExampleActivity extends Activity {
#BindView(R.id.switch1) SwitchCompat switch1;
#BindView(R.id.switch2) SwitchCompat switch2;
#BindView(R.id.switch3) SwitchCompat switch3;
#Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.bind(this);
// TODO Use fields...
}
}
or if you want to listen on setOnCheckedChangeListener you don't need to define them
for example, we define onClickListener at the following code without any definition of views
#OnClick({R.id.switch1,R.id.switch2,R.id.switch3})
public void onClick(View view) {
switch(view.getId) {
case R.id.switch1: {
//do something here
break;
}
}
}
Try this way
Create a method like this
#SuppressWarnings("unchecked")
public <T extends View> T $(int id) {
return (T) findViewById(id);
}
Change your init() like this
switch1=$(R.id.switch1);
switch2=$(R.id.switch2);
switch10=$(R.id.switch10);
You can also use Butter Knife
Also other option is Data Binding
if you want to use kotlin then no need to findViewById()
You can use databinding.
Another way would be to traverse your layout like this and set the properties to your Switch.
LinearLayout layout = (LinearLayout)findViewById(R.id.root); // whatever layout you are using
setPropToSwitch(layout);
public void setPropToSwitch(LinearLayout layout) {
for (int i = 0; i < layout.getChildCount(); i++) {
View v = layout.getChildAt(i);
if (v instanceof SwitchCompat) {
//set properties
}
}
}
I didn't say it clearly, so this is my fault, but I can't add any libraries or use Kotlin because my great team won't let me.
It is simple, I just had "a window".
switch1= initSwitch(R.id.switch1);
switch2= initSwitch(R.id.switch2);
switch3= initSwitch(R.id.switch3);
....
switch10= initSwitch(R.id.switch10);
private SwitchCompat initSwitch(#IdRes int id) {
final SwitchCompat switchCompat = findViewById(id);
switchCompat.setOnCheckedChangeListener(this);
switchCompat.setTypeface(...);
return switchCompat;
}
Thank you all for your help.

how change changed textview android

I passed the data from the first actvity (like int VNIMANI and int OBRATNOST). This data set my TextView after I came on second activity. now I need a button. And when I click on the button I need increment +1. But the code doesn't work.
TextView tvPaklic = (TextView) findViewById(R.id.paklic);
String paklic = String.valueOf( + 10+ (VNIMANI+OBRATNOST));
tvPaklic.setText(paklic);
}
int newPaklic = 0;
public void plusPaklic (View v){
newPaklic = newPaklic + 1;
displayPaklicDve (newPaklic);
}
private void displayPaklicDve(int newPaklic) {
TextView tvpaklicdve = (TextView) findViewById(R.id.paklic);
String paklicdve = String.valueOf(newPaklic);
tvpaklicdve.setText(paklicdve);
}
I would really like to suggest you refer this one Read this, will solve your problem
You were used 2 Textview objects with referring one id check that.
TextView tvPaklic = (TextView) findViewById(R.id.paklic);
TextView tvpaklicdve = (TextView) findViewById(R.id.paklic);

Null pointer exception on setting visibility of ImageView

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);
}

NullPointerException if I setOnClickListener for button from array

I created array of buttons in a loop. It seems to work, but if I add OnClickListener to each button, I get a NullPointerException. How do I fix that?
This is my code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
fieldModel=new Field();
buttons=new Button[10][10];
for(int i=0; i<10; i++) {
for (int j = 0; j < 10; j++) {
String buttonID = "button" + i + j;
int resID = getResources().getIdentifier(buttonID, "id", getPackageName());
buttons[i][j] = ((Button) findViewById(resID));
buttons[i][j].setOnClickListener(new View.OnClickListener() { // <-- I get the exception here...
#Override
public void onClick(View v) {
"some action"
}
});
In R.layout.main_layout, are there 100 buttons named 'button00' to 'button99'? if any one is missing, it will result in a null pointer at the line you have marked.
It would also be worth looking at using a GridView, or a RecyclerView with GridLayoutManager, instead of adding the buttons manually - if it would suit your app.
You get the exception because the id isn't contained by the activity layout. You have to add them first in the layout file if you want to match the Button object through findViewById or, if you have them already, make sure the Id you use in findViewById (resId) is correct.

Testing TextView text colour using Robolectric for Android

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.

Categories

Resources