Robotium - Waiting for an Activity's tasks to complete - java

I've just started learning to use Robotium for testing my app. I have written a test case that resets a list of stats, and then checks if the values are equal to 0. The code is below:
public void testClearStats() {
solo.clickOnButton("Clear Stats");
solo.clickOnButton("Yes");
TextView views = (TextView) solo.getView(R.id.textViewsNum);
TextView prompts = (TextView) solo.getView(R.id.textPromptsNum);
TextView completions = (TextView) solo.getView(R.id.textCompleteNum);
assertEquals("0", views.getText().toString());
assertEquals("0", prompts.getText().toString());
assertEquals("0", completions.getText().toString());
}
The test was failing when it shouldn't because it was checking the values of the TextViews before their results were reset. To get around this, I added this line:
solo.waitForActivity(solo.getCurrentActivity().toString());
With this statement the test passes but it seems to take an unnecessary long time to complete. I was wondering if there was a better/correct way of way doing this, or is this the best way of doing it?
Thanks

You will have to wait on something, what you choose will depend on your application and without looking at it i cannot answer what will be the best thing to wait for.
What visual indicators do you have for the reset to occur? do you have a new activity open? Is there text telling it has complete? if it is literally just the three textfields. if it is then you might manage to use solo.waitfortext("0") although the better way will be to use the new concept of conditions and use the solo.waitForCondition(method) (the condition will probably be to wait for the text to be 0, but you would have put the condition into one place and then if you later find a better way then you only have to change it once).
public class WaitForReset implements Condition
{
public boolean isSatisfied()
{
TextView views = (TextView) solo.getView(R.id.textViewsNum);
TextView prompts = (TextView) solo.getView(R.id.textPromptsNum);
TextView completions = (TextView) solo.getView(R.id.textCompleteNum);
if(isViewZero(views) && isViewZero(prompts) && isViewZero(completions))
{
return true
}
else
{
return false;
}
}
private isViewZero(TextView textView)
{
if((textView!=null) && (textView.getText().toString() ==0))
{
return true;
}
else
{
return false;
}
}
}
You can then assert on the value of the waitforcondition being true!

You can always use waitForActivity and choose a specific timeout.solo.waitForActivity(YourActivity.class, timeout);

Related

How do I conditionally enable a TextView based on another TextView's contents?

I'm new to Android Studio, and programming an application.
I'm experimenting with it, and I want to know how you can enable (for example) Textview2 if Textview1 contains something.
I tried this code but it didn't work:
TextView2.setEnabled(false);
if (TextView1.length() > 0) {
TextView2.setEnabled(true);
}
Thanks in advance!
Welcome to SO, You can use contains method for check if your string has specific text.
if (TextView1.getText().toString().contains("yourText")) {
TextView2.setEnabled(true);
}
for checking if Textview1 has text. you can use method for checking:
//usage:
if(TextView1.getText().toString() != null || TextView1.getText().toString().length() > 0) //then do what you want.
be aware of null pointer exception by checking textview have a text.
I got the answer to my Question!
i did it like this:
if (TextView1.getText().toString().isEmpty()) {
//Do what you want here
}

How to load items in a RecyclerView in the same order as the API calls are done?

That's my problem:
I need to display some items in a RecyclerView in the same order they are called from the server to match the given design. However, I think I may probably be missing something very obvious on how Java actually works, because even though my calls are done in order, I've noticed the code placed after them is executed before a result is got from the server and afterwards, when the UI is updated, the order for the items displayed is not the same as originally intended.
That's the piece of code that has been taken away some days of my life now..
getGetMetricRangeAPI("bp_dia");
getGetMetricRangeAPI("bp_sys");
getGetMetricRangeAPI("glucose");
getGetMetricRangeAPI("lung_fev1");
getGetMetricRangeAPI("vo2");
getGetMetricRangeAPI("visceral");
getGetMetricRangeAPI("body_fat");
mGoalsRecyclerView.setAdapter(mGoalsAdapter);
GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 2);
mGoalsRecyclerView.setLayoutManager(layoutManager);
mGoalsRecyclerView.setNestedScrollingEnabled(false);
// mGoalsList is returning empty, as it should update *after* the
// response from the server, but for some reason, and that's what is
// confusing me a lot at the moment, that part of the code is read
// before it, so this whole for loop is being ignored at the moment.
for (GetAdvancedGoal goal : mGoalsList) {
mGoalsAdapter.addItem(goal);
}
Any help on that is really very much appreciated!! Thanks a lot!!! :)
Ps: I think another title for my question could be:
How do I make sure actions happen sequentially in Java?
As if I could make sure I can populate my adapter only when the mGoalsList array is completely filled (or even the hashmap, as per the suggestions), I could then order and display the items according to the desired sequence.
Thanks very much for your help!
You have multiple API calling at same time, there must be dependency between all this. For ordering of list according to api calling, you can use numbering assigned to each api calling and create hashmap of return result with numbers and displaying of list can be done according to numbers. But this is worst idea i think.
For better and pure solution, if a core developer. you must go for RxJava, you must be hearing about this. Here is description link:
RxJava
In RxJava, you defines dependency between calling of api's, here you can define observer's and observable's. Where Observer's always listen to observable(Sorry find detail description in link), so you must be insure that. 4th api should be call always after 2nd or 3rd one. Go for it, sorry i don't have any code related to that right now. if i will got that will post here.
getGetMetricRangeAPI("bp_dia",1);
getGetMetricRangeAPI("bp_sys",2);
getGetMetricRangeAPI("glucose",3);
getGetMetricRangeAPI("lung_fev1",4);
getGetMetricRangeAPI("vo2",5);
getGetMetricRangeAPI("visceral",6);
getGetMetricRangeAPI("body_fat",7);
Add an integer to your API call. Save the response in a HashMap and sort it according to this order
for (GetAdvancedGoal goal : mGoalsList) {
mGoalsAdapter.addItem(goal);
}
//this is missing in your code
mGoalsAdapter.notifyDataSetChanged()
That's the implementation of the hashmap suggestion that solved my problem
Added answer from #Ammer on my fragment
getGetMetricRangeAPI("bp_dia",1);
getGetMetricRangeAPI("bp_sys",2);
getGetMetricRangeAPI("glucose",3);
getGetMetricRangeAPI("lung_fev1",4);
getGetMetricRangeAPI("vo2",5);
getGetMetricRangeAPI("visceral",6);
getGetMetricRangeAPI("body_fat",7);
And that's my adapter using hashmap instead of arraylist
public void addItem(final GetAdvancedGoal item, int position) {
if (position == 0) {
mHashMap.put(item, 0);
mHashMapInvertedKeyValue.put(0, item);
} else if (position == 1) {
mHashMap.put(item, 1);
mHashMapInvertedKeyValue.put(1, item);
} else if (position == 2) {
mHashMap.put(item, 2);
mHashMapInvertedKeyValue.put(2, item);
} else if (position == 3) {
mHashMap.put(item, 3);
mHashMapInvertedKeyValue.put(3, item);
} else if (position == 4) {
mHashMap.put(item, 4);
mHashMapInvertedKeyValue.put(4, item);
} else if (position == 5) {
mHashMap.put(item, 5);
mHashMapInvertedKeyValue.put(5, item);
}
notifyDataSetChanged();
}
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
GetAdvancedGoal getAdvancedGoal = null;
if (mHashMapInvertedKeyValue.get(position) != null) {
getAdvancedGoal = mHashMapInvertedKeyValue.get(position);
// Name
holder.update_goal_editText.setText(getAdvancedGoal.getValue());
// Image
int id = getAdvancedGoal.getImageID();
switch (id) {
case R.drawable.blood_pressure:
SharedPreferences preferences = mActivity.getSharedPreferences("ADVANCED_METRIC_BP_SYS", Context.MODE_PRIVATE);
String valueSys = preferences.getString("bp_sys", "");
holder.update_goal_editText.setText(getAdvancedGoal.getValue() + "/" + valueSys);
holder.goal_image.setImageResource(R.drawable.blood_pressure);
break;
case R.drawable.glucose_level:
holder.goal_image.setImageResource(R.drawable.glucose_level);
break;
case R.drawable.visceral_fat:
holder.goal_image.setImageResource(R.drawable.visceral_fat);
break;
case R.drawable.lung_function:
holder.goal_image.setImageResource(R.drawable.lung_function);
break;
case R.drawable.v02_max:
holder.goal_image.setImageResource(R.drawable.v02_max);
break;
case R.drawable.body_fat:
holder.goal_image.setImageResource(R.drawable.body_fat);
break;
}
}
}

Making a TextView visible at runtime in java (Android)

I have two activities; the first activity starts the second one with some data passed through the intent.
Intent i = new Intent(this,BActivity.class);
i.putExtra("identify", "c2f");
startActivityForResult(i, 1);
In the second activity, I want to make some TextViews/EditTexts visible (which are initially set to invisible) based on the information passed from the first activity.
Here's the code for that:
tv1 = (TextView)findViewById(R.id.textView2);
tv2 = (TextView)findViewById(R.id.textView3);
et1 = (EditText)findViewById(R.id.editText1);
et2 = (EditText)findViewById(R.id.editText2);
button = (Button)findViewById(R.id.send_result);
Bundle extras = getIntent().getExtras();
String identifier = extras.getString("identify");
if(identifier == "c2f")
{
tv1.setVisibility(0);
tv1.setText("Celcius");
et1.setVisibility(0);
}
else if(identifier == "f2c")
{
tv1.setVisibility(0);
tv1.setText("Fahrenheit");
et1.setVisibility(0);
}
else if(identifier == "currency")
{
tv1.setVisibility(0);
tv1.setText("Amount");
tv2.setVisibility(0);
tv2.setText("Conv. Rate");
et1.setVisibility(0);
et2.setVisibility(0);
}
Now when the second activity starts, none of these TextViews or EditTexts seem to get visible!
identifier (string) holds the correct value passed from first activity and it even goes into the if conditions, but it doesn't make any view visible.
Am I making any mistake in trying to make these views visible?
Use .equals instead of == to string comparison. You can also use the variable after the quoted string to avoid nullpointer. And you can use TextView.VISIBLE, it's a constant to get it visible.
if("c2f".equals(identifier))
{
tv1.setVisibility(TextView.VISIBLE);
tv1.setText("Celcius");
et1.setVisibility(TextView.VISIBLE);
}
Simply use the View's constants for this.
your_view.setVisibility(View.VISIBLE);
This will make your View visible.
your_view.setVisibility(View.INVISIBLE);
This will make it invisible but still with the layout visible (basically, the space where it goes remains untouched)
your_view.setVisibility(View.GONE);
This will make your View disappear, like it never existed!
As pointed by giacomoni, please use equals for String comparison. Here is a link to explain why.
http://javarevisited.blogspot.in/2012/03/how-to-compare-two-string-in-java.html
Also, try using the standard View.VISIBLE etc constants for showing and hiding views. They are much more easy to use and understand. Happy coding. :)

If statement with booleans android

I have been having a problem with a Boolean in an if statement all day and it is really starting to irritate me now!! I have looked at other Android threads on here and the solutions just don't seem t work.
My code started off like this:
public class MainActivity extends Activity
{
public static boolean isSignedIn = false;
public final static String USERNAME_MESSAGE = "com.example.libnoise.MESSAGE";
Button btnSignIn;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnSignIn = (Button) findViewById(R.id.btnSignIn);
Intent intent = getIntent();
String message = intent.getStringExtra(PlayZone.USERNAME_MESSAGE);
if(isSignedIn == false))
{
btnSignIn.setText("SignIn");
}
else
{
btnSignIn.setText(message);
}
}
Then I had a thought that made it's not like other languages and I only need one "=" sign so I had it as this:
if(isSignedIn = false)
{
btnSignIn.setText("SignIn");
}
else
{
btnSignIn.setText(message);
}
That didn't work and that's when I started looking online, after finding a previous thread on here changed it to the following:
if("false".equals(isSignedIn))
{
btnSignIn.setText("SignIn");
}
else
{
btnSignIn.setText(message);
}
Now that doesn't look right to me in the first place but hoped it would work and it didn't.
As this is the MainActivity it loads first however since I added all this, the app crashes before it will even load when I take out the if statement it work as expected.
Any ideas?
This
if (isSignedIn == false)
is perfectly correct. (You could also write if (!isSignedIn), but that's just a matter of style.)
Note that, since you never change the value of isSignedIn (at least not in the code you have shown us), it will always be false.
i think you can simply use
if(!isSignedIn)
{
btnSignIn.setText("SignIn");
}
else
{
btnSignIn.setText(message);
}
the way you followed is also correct i didn't find any mistake in except you are using extra bracket in condition if(isSignedIn == false))
If statements with boolean are same how you do it in Java, == is the right way to compare
The problem in your code is extra bracket
if (isSignedIn == false))
Just to deviate from the question, but point out what is possibly your problem, your null pointer could be because you are accessing a UI object that may well not be ready to have it's text set yet.
While some API versions cope fine with what you're doing, I've found many device/API combos simply aren't ready to have anything changed from what's in the xml until onStart. The general guidance is to load data in onCreate, but not start doing anything until onStart.

Accessing program data from within onClick() inner class

i'm trying to access an EditText from an onClick() method within an onClickListener implementation for a button. here's the code:
transmit.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//data validation
///////////////////////
boolean valid = true;
if(((EditText)findViewById(R.id.drv_in)).getText().toString() == "") {
TX_FAIL_TEXT = "Missing Driver ID!";
showDialog(DIALOG_FAIL);
TX_FAIL_TEXT = "Transmission Failed!"; //reset the dialog fail text to default
valid = false;
}
Log.e("smsDRVERR",((EditText)findViewById(R.id.drv_in)).getText().toString());
//begin transmission
///////////////////////
if(valid) {
showDialog(DIALOG_TX_PROGRESS);
Thread t = new Thread(txRunnable);
t.start();
} else {
//do things if needed
}
}
});
the Log.e is never called (does not show up in logcat). and the program executes as if the conditional statement doesn't exist. how do i reference layout items properly in an onClick implementation? i've also tried the following line:
Log.e("smsDRVERR",((EditText)smsActivity.this.findViewById(R.id.drv_in)).getText().toString());
which was alluded to in this question i found on SO:
Inside OnClickListener I cannot access a lot of things - how to approach?
but it does not solve the problem. i'm missing something that i need to reference these items within this inner class, or maybe i have my syntax a bit jarbled. any help is appreciated.
You are not comparing your String correctly.
if(((EditText)findViewById(R.id.drv_in)).getText().toString() == "") {
is checking if the objects are equal, whereas you want to check if the values are equal. You should be using:
if(((EditText)findViewById(R.id.drv_in)).getText().toString().equals("")) {
Personally, I'd assign the value returned by getText to a String variable, rather than calling getText multiple times:
String myEditTextValue = (EditText)findViewById(R.id.drv_in)).getText().toString();
...
if ("".equals(myEditTextValue)) {
First, is your onClick method being called? Second, don't use == to do string comparisons; use .equals(). (Strings that are equal are not necessarily the same object, which is what == tests.)

Categories