Office Hours — Today, December 29

Tuesday, December 27

Dec 29
8:55 AM
Mark M.
has entered the room
Mark M.
turned on guest access
Chandra S.
has entered the room
Mark M.
hello, Chandra!
how can I help you today?
Chandra S.
Hi, Mark
How to call getLayoutInflater from onCreateViewHolder if we separate the Adapter class in the different file?
Mark M.
either pass in the Activity into the RecyclerView.Adapter, or pass in a LayoutInflater into the RecyclerView.Adapter, via a constructor or setter
9:00 AM
Chandra S.
I didn't the second one: " pass in a LayoutInflater into the RecyclerView.Adapter, via a constructor or setter"
*didn't get
Mark M.
well, your activity or fragment is creating the RecyclerView.Adapter
your subclass of RecyclerView.Adapter can have a constructor or setter, that accepts a LayoutInflater, and holds onto that inflater in a field
your activity or fragment can call getLayoutInflater() and pass that LayoutInflater to that constructor or setter
Chandra S.
Ah, I see..
Is it better to separate or to combine in 1 file?
Mark M.
I cannot really answer that
either could be "better"
Chandra S.
Ok.. thanks..
Another question
If I want to put an EditText in every row of RecyclerView, how I get that input?
Mark M.
what I have been using combines two things
9:05 AM
Mark M.
first, I override onViewDetachedFromWindow(), which tells me that one of my ViewHolder's views is no longer going to be used, so there I grab whatever was in its EditText and hold it in my model/view-model/whatever object
however, that does not cover those ViewHolders that are still "alive" at the time (e.g., at the point the user triggers a configuration change, where I want to save data in the saved instance state bundle)
so, second, at those points where I need to make sure that I am holding the latest-and-greatest information of all the EditText widgets, I iterate over the adapter positions and call findViewHolderForAdapterPosition() on the RecyclerView
that method returns null if there is no "live" ViewHolder for that adapter position, or the ViewHolder if there is one
and I then get the latest text from the EditText from whichever ViewHolders I get
I am not completely confident in this approach, though it has been holding up so far
in principle, you could use TextWatcher with each of the EditText widgets and update your model/view-model/whatever whenever the text changes, but this adds some overhead
9:10 AM
Chandra S.
Many things I see for the first time :-) Thanks, Mark, I'll try to understand after the chat over
If I want to put Button, the easier approach can be used right?
Mark M.
yes, just attack a click listener to it
the same thing goes for CompoundButton implementations
there, the input is atomic: it's a click, or a checked-state change, or something
EditText has complex input
the closest analogy to calling setOnClickListener() on a Button would be adding a TextWatcher to an EditText
and, again, that's a possibility, particularly if you need real-time on-the-fly updates to the data
but, it adds overhead per keystroke
Ace R.
has entered the room
Ace R.
Hi all
Chandra S.
I see.. OK, thanks, Mark..
Mark M.
Chandra: let me take a question from Ace, and I will be back with you shortly
Chandra S.
Hi Ace, we meet again :-)
Mark M.
Ace: your turn! do you have a question?
9:15 AM
Ace R.
View paste
What is the best way to Handle Retrofit errors - thats my question.

Do I just put an if else statement like this inside the onResponse? Then display a toast to the user? See

http://stackoverflow.com/a/37541613

Or is there a better way?
Mark M.
well, with Retrofit 2.x, you have to implement onResponse() and onFailure()
on your Callback that you supply to enqueue()
I have assumed, possibly incorrectly, that a non-200 response would trigger onFailure()
Ace R.
okay i currently have something like this
View paste (8 more lines)
   call.enqueue(new Callback<List<TestModel>>() {
            @Override
            public void onResponse(Call<List<TestModel>> call, Response<List<TestModel>> response) {

                try {
                    mTestModelData = response.body();
                    if (mTestModelData != null) {
                        //bulkInsert arraylist of products
                        Utility.storeProductList(getActivity(), mTestModelData);
                    }
                } catch (Exception e) {
                    Log.v("Inside exception", e.toString());
                    e.printStackTrace();
                }

...
Mark M.
right
so, the issue is: under what circumstances is onFailure() called?
Ace R.
Do I just put if else condition to handle non 200 responses?
Mark M.
well, to be honest, I do not know
9:20 AM
Mark M.
again, I assumed that non-200 responses route to onFailure()
Ace R.
okay. yes they do
Mark M.
it is possible that Retrofit reserves onFailure() for other things (e.g., could not reach the server)
unfortunately, the Retrofit documentation is a bit weak
Ace R.
okay. yes I believe I have seen it route to onFailure
so in the onFailure I can just display a Toast to the user
Mark M.
I'd use something other than a Toast, but yes, you can let the user know about the problem
Ace R.
other than a Toast? what other options would you use so that i can apply it in my app?
Mark M.
well, a Toast is emphemeral -- if the user is not paying close attention to the screen, they might not see it
Ace R.
Okay. maybe a SnackBar?
Mark M.
whether you display the message somewhere inline in your main UI, or use a more durable overlay (e.g., a Snackbar) is up to you
Ace R.
okay makes sense.
Mark M.
let me take another question from Chandra, and I will be back with you in a bit
Chandra: your turn! do you have another question?
Ace R.
okay
Chandra S.
I saw GsonConverterFactory. What's the function? Is it to change the converter from the default to Gson?
Mark M.
are you referring to with Retrofit?
Chandra S.
Yes
9:25 AM
Mark M.
with Retrofit 2, there is no default converter
Retrofit 1.x assumed Gson as a converter with an option to replace it
Retrofit 2.x says that you have to provide a converter
Gson is a likely candidate, but there are others, particularly if the payload is not JSON
Chandra S.
Ok, thanks, Mark
I actually have another question related to Retrofit
Mark M.
since that one was pretty short, go right ahead
Chandra S.
If REST API that I consumed has multiple child, let say like this format:
View paste
{
    "contacts":
        {
                "person":
		  {
			"home":
			  ...
		  }
	}
}
I just want to retrieve node under "home", I should keep create class "Class" and "Person"?
Mark M.
AFAIK, Gson does not know how to return arbitrary inner pieces of the JSON
so I would assume that you need a Contacts class and a Person class, with just enough fields to get by
note that you do not need fields for every JSON property, if you will not be using that property
Chandra S.
Ok, got it.. Thanks
Mark M.
now, it is conceivable that another converter, such as Jackson, offers other options here
Gson and Moshi would require the full object tree to the objects that you want, AFAIK
9:30 AM
Mark M.
let me take another question from Ace, and I will return to you in a short while
Ace: your turn! do you have another question?
Chandra S.
Ok
Ace R.
I read the chapter about UI Automator, the bit that I still don't quite understand is how is how different is it from Espresso? Can you elabrorate what you mean by UI automator has greater ability to test an applicaton vs testing individual component.
Mark M.
Espresso only works within one app
UI Automator works across apps
so, for example, suppose you want to test your home screen launcher icon
you have no means of doing that with Espresso, as you cannot automate the home screen with Espresso
you can do that with UI Automator
similarly, suppose you want to test your integration with some app that you launch from yours (e.g., you open up a PDF viewer app)
you can launch an activity from Espresso and use mocks to determine if the Intent looked OK, but you cannot actually confirm if the activity that was started was what you wanted
with UI Automator, you can
Ace R.
okay. sounds quite powerful
9:35 AM
Mark M.
the downside is that since it relies upon the accessibility APIs, you have limited visibility into what you are testing
testing more than "did this text show up where I expected it?" is difficult
which is why UI Automator tends to be reserved for integration testing
Ace R.
okay, in regards to Mock test do I need to use Robotium to start mockito testing or just add Mockito dependency in Gradle?
Mark M.
Mockito and Robotium are independent
you do not need one to use the other
Ace R.
Okay what is Robotium use for?
Mark M.
Mockito lets you mock arbitrary stuff, but you are responsible for setting up the mocks
Robotium is effectively a canned set of mocks related Android SDK constructs
Ace R.
So with Robotium you dont have to setup the Mocks?
Mark M.
I'd phrase it more as "the setup of the mocks is easier"
Ace R.
okay thanks.
Mark M.
personally, I do not use either of them, outside of that one unit testing chapter in the book
9:40 AM
Ace R.
ohh
thats interesting
Mark M.
hence, I claim no deep expertise in either of them :-)
Ace R.
can I ask do you use instead?
Mark M.
Robotium is for unit testing (i.e., testing on the JVM, outside of Android)
Mockito can be used for instrumentation testing (i.e., testing in Android) as well as unit testing
but I tend to focus on testing real objects
Ace R.
testing real objects? what if you have a Database though? I was wondering how you would handle that?
Mark M.
if by "database" you mean SQLite on the device, I test the real database
if by "database" you mean some sort of Web service, I have a test Web service, but real Android code for hitting it
Ace R.
yes SQLite
okay hmmn, if you did test the real database it would insert real data in the actual database?
Mark M.
sure
Ace R.
do you just delete the data after the test?
Mark M.
yes
or, perhaps before the next one
I tend to use @Before more than @After
Ace R.
okay hmmn but what if its a production app with already real data
Mark M.
there are ~2 billion Android devices in the world, plus an infinite number of possible emulators
surely one of them does not have production data
Ace R.
ah!
makes sense
9:45 AM
Mark M.
now, I'm somewhat unusual, in that I have a rather large fleet of hardware here in my Secret Mountain Lair
so I do not claim that my approaches towards testing are necessarily apropos for everyone
Ace R.
okay.
Mark M.
so, having something to test on, that does not disturb any real data, is not an issue for me
Ace R.
okay got it
Mark M.
OK, it's free-for-all time
if anyone has any questions, just chime in
Chandra S.
What is the function of Call in Retrofit? Since I saw it's stated but never used
Mark M.
sure it is used
check my Retrofit 2.x samples in the book
Chandra S.
In onResponse method I mean
Mark M.
ah
well, among other things, you can get to the full parsed response there
such as HTTP headers
oh, no, wait, I'm thinking of the Response object
9:50 AM
Mark M.
ah, you can get to the original Request object via the Call
you can also call clone() to create a new Call (e.g., for retrying the request)
(though that would be more likely in onFailure() than in onResponse())
Ace R.
ah so clone will retry your original request if it fails for whatever reason?
Mark M.
but the Response object will be used more in onResponse()
it's more that given a fresh Call, you can execute() or enqueue() that new Call, to retry the request
I don't think you can do that with a Call that has been processed already
Ace R.
okay so in a Snackbar would you say its a good idea to call clone() if the user want to retry the request?
Chandra S.
I see.. ok, thanks Mark
Mark M.
Ace: if you mean from a Snackbar.Action (e.g., user clicks a "retry" button in the Snackbar), then that is a possibility
however, when you display a UI to the user, there may be some time gap between the original Call and the time you decide to retry it
in that case, I would tend to go back through my original code, as perhaps my call needs to change slightly, due to changes elsewhere in my app
Chandra S.
I actually have last question :-D Do the setRetainInstance(true) has drawbacks like memory leaks? How Android manage the lifecycle of the fragment?
Mark M.
OTOH, suppose you have set up your server to send a particular HTTP response code to indicate "we're busy, please retry"
9:55 AM
Mark M.