How to comment Android's Activities with JavaDoc? - android

Activities are called in this way (an example):
Intent i = new Intent(context, MyActivity.class);
i.putExtra("par1", "value1");
i.putExtra("par2", 2);
startActivityForResult(i);
How can I comment MyActivity class with JavaDoc like methods?
For example in this case:
/**
* This activity show some data
* #param par1 String value of parameter1
* #param par2 int number of records to show
* #return returnValue boolean true if data is showed, false otherwise
*/
to have an idea of which parameters intent expects and what type of return offers.

Just write the JavaDoc part right in top of the class declaration.
/**
* JavaDoc
*/
public class MyActivity {

Right Click on a Method Name-> Source-> Generate Element Comment.
Shortcut
ALT+SHIFT+J

Declare the parameter constants as public static final String and add javadoc field documentation there.
Use #links to bind things together.
Example:
/**
* String containing foo parameter for {#link #XyzzyActivity}
*/
public static final String EXTRA_FOO = "par1";
/**
* XyzzyActivity
*
* Parameters understood: {#link #EXTRA_FOO}, ...
*
* Returns...
*/

Type /** at the top of your method, then press ENTER key. The comment part will become something like this:
/**
*
* #return
*/
You are also allowed to add
#author – who wrote this code
#version – when was it changed
#param – describe method parameters
#return – describe method return values
#throws – describe exceptions thrown
#see – link to other, related items (e.g. “See also…”)
#since – describe when code was introduced (e.g. API Level)
#deprecated - describe deprecated item and what alternative to use instead

Related

Why RemoteView.setColorStateList() not accessible?

My use-case is to set background for a view inside RemoteView layout.
remoteViews.setInt(R.id.infoRightTitle, "setBackgroundResource", R.drawable.icon)
remoteViews.setColorStateList(R.id.infoRightTitle, "setBackgroundTintList", ContextCompat.getColorStateList(appContext,R.color.red))
But i was surprised to find that setColorStateList was not available and shows a compilation error.
Unresolved reference: setColorStateList
RemoteViews.java
/**
* Call a method taking one int on a view in the layout for this RemoteViews.
*
* #param viewId The id of the view on which to call the method.
* #param methodName The name of the method to call.
* #param value The value to pass to the method.
*/
public void setInt(int viewId, String methodName, int value) {
addAction(new ReflectionAction(viewId, methodName, ReflectionAction.INT, value));
}
/**
* Call a method taking one ColorStateList on a view in the layout for this RemoteViews.
*
* #param viewId The id of the view on which to call the method.
* #param methodName The name of the method to call.
* #param value The value to pass to the method.
*
* #hide
*/
public void setColorStateList(int viewId, String methodName, ColorStateList value) {
addAction(new ReflectionAction(viewId, methodName, ReflectionAction.COLOR_STATE_LIST,
value));
}
I can see an annotation #hide in the code but no other comments while the method is public.
The code i have shared is simplified version to give a gist of the issue.
Need help to find the solution to this problem ?
As of API 31, setColorStateList is supported on RemoteViews.

Android - Testing navigation with NavigationComponent

I'm having trouble testing my navigation with NavigationComponent, Espresso and Mockito. I have this simple test:
#Test
fun testNavigation(){
val mockNavController = mock(NavController::class.java)
val firstScenario = launchFragmentInContainer<FirstFragment>()
firstScenario.onFragment { fragment ->
Navigation.setViewNavController(fragment.requireView(), mockNavController)
}
val expectedBundle = bundleOf(ARG_A to true)
onView(withId(R.id.button)).perform(click())
verify(mockNavController).navigate(R.id.action_first_fragment_to_second_fragment, expectedBundle)
}
The test fails with this error:
Argument(s) are different! Wanted:
navController.navigate(
2131361850,
Bundle[{ARG_A=true}]
);
-> at FirstFragmentTest.testNavigation(FirstFragmentTest.kt:60)
Actual invocation has different arguments:
navController.navigate(
2131361850,
Bundle[{ARG_A=true}]
);
-> at FirstFragment$onViewCreated$2.onClick(FirstFragment.kt:67)
The arguments and id are exactly the same, the only difference is that last line in the error showing where the on click was invoked. Also, the onClick() method in my test doesn't even seem to open the second fragment. It just stays on the first fragment.
Does someone know what's going wrong?
Thanks in advance!
Bundles can contain different kinds of information, of different types and sizes.
equals method of Bundle class is just default implementation that compares two objects by reference.
You'll have to implement comparison by yourself or use already approved solution.
I've found a static method of Bundle superclass BaseBundle called kindOfEquals:
/**
* Does a loose equality check between two given {#link BaseBundle} objects.
* Returns {#code true} if both are {#code null}, or if both are equal as per
* {#link #kindofEquals(BaseBundle)}
*
* #param a A {#link BaseBundle} object
* #param b Another {#link BaseBundle} to compare with a
* #return {#code true} if both are the same, {#code false} otherwise
*
* #see #kindofEquals(BaseBundle)
*
* #hide
*/
public static boolean kindofEquals(BaseBundle a, BaseBundle b) {
return (a == b) || (a != null && a.kindofEquals(b));
}
But because it does loose equality check that may be not the desired solution.
Update
BaseBundle is not public but you can still check its kindOfEquals implementation and take it as an example.

By what i can replace ViewTreeObserver.OnComputeInternalInsetsListener that is declared as hidden?

I try to import in my library some android internal source code. however i have some trouble to import this part of code :
private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer =
new ViewTreeObserver.OnComputeInternalInsetsListener() {
public void onComputeInternalInsets(
ViewTreeObserver.InternalInsetsInfo info) {
info.contentInsets.setEmpty();
info.visibleInsets.setEmpty();
info.touchableRegion.set(mTouchableRegion);
info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo
.TOUCHABLE_INSETS_REGION);
}
};
it's because in ViewTreeObserver.java OnComputeInternalInsetsListener is declared as hidden
/**
* Interface definition for a callback to be invoked when layout has
* completed and the client can compute its interior insets.
*
* We are not yet ready to commit to this API and support it, so
* #hide
*/
public interface OnComputeInternalInsetsListener {
/**
* Callback method to be invoked when layout has completed and the
* client can compute its interior insets.
*
* #param inoutInfo Should be filled in by the implementation with
* the information about the insets of the window. This is called
* with whatever values the previous OnComputeInternalInsetsListener
* returned, if there are multiple such listeners in the window.
*/
public void onComputeInternalInsets(InternalInsetsInfo inoutInfo);
}
later i use it like this
/**
* Make the touchable area of this popup be the area specified by mTouchableRegion.
* This should be called after the popup window has been dismissed (dismiss/hide)
* and is probably being re-shown with a new content root view.
*/
private void setTouchableSurfaceInsetsComputer() {
ViewTreeObserver viewTreeObserver = mPopupWindow.getContentView()
.getRootView()
.getViewTreeObserver();
viewTreeObserver.removeOnComputeInternalInsetsListener(mInsetsComputer);
viewTreeObserver.addOnComputeInternalInsetsListener(mInsetsComputer);
}
so by what i can replace ViewTreeObserver.OnComputeInternalInsetsListener, removeOnComputeInternalInsetsListener and addOnComputeInternalInsetsListener ? i don't even know the purpose of these functions ...

Consecutive Android Junit tests do not reflect the real data in the underlying database

Additional Information:
To clarify, the app under test uses a ContentProvider to access the database.
Edit:
If anyone is willing and able to help me debug this. The full project is available here. In the issue107-contentprovider branch, BaseballCardListAddCardsTest.
Question:
When I run two of my Android JUnit tests separately, they pass just fine. However, when I run them together, the first one passes and the second one fails. The problem appears to be that the first test run adds a row to the underlying database. tearDown() correctly deletes the database, but the second test still starts with the dirty data displayed in the ListView although the database does not contain the extra row. (I confirmed this using adb shell.) Does anyone have any ideas how I can fix this problem?
The Activity class being tested can be found here.
Here is my test code:
/**
* Tests for the {#link BaseballCardList} activity when the database contains
* data.
*/
public class BaseballCardListWithDataTest extends
ActivityInstrumentationTestCase2<BaseballCardList> {
/**
* Create instrumented test cases for {#link BaseballCardList}.
*/
public BaseballCardListWithDataTest() {
super(BaseballCardList.class);
}
/**
* Set up test fixture. This consists of an instance of the
* {#link BaseballCardList} activity, its {#link ListView}, and a populated
* database.
*
* #throws Exception
* If an error occurs while chaining to the super class.
*/
#Override
public void setUp() throws Exception {
super.setUp();
this.inst = this.getInstrumentation();
// Create the database and populate table with test data
InputStream cardInputStream = this.inst.getContext().getAssets()
.open(BBCTTestUtil.CARD_DATA);
BaseballCardCsvFileReader cardInput = new BaseballCardCsvFileReader(
cardInputStream, true);
this.allCards = cardInput.getAllBaseballCards();
cardInput.close();
this.dbUtil = new DatabaseUtil(this.inst.getTargetContext());
this.dbUtil.populateTable(this.allCards);
// Start Activity
this.activity = this.getActivity();
this.listView = (ListView) this.activity
.findViewById(android.R.id.list);
this.newCard = new BaseballCard("Code Guru Apps", 1993, 1, 50000, 1,
"Code Guru", "Code Guru Devs", "Catcher");
}
/**
* Tear down the test fixture by calling {#link Activity#finish()} and
* deleting the database.
*
* #throws Exception
* If an error occurs while chaining to the super class.
*/
#Override
public void tearDown() throws Exception {
this.dbUtil.deleteDatabase();
super.tearDown();
}
/**
* Check preconditions which must hold to guarantee the validity of all
* other tests. Assert that the {#link Activity} to test and its
* {#link ListView} are not <code>null</code>, that the {#link ListView}
* contains the expected data, and that the database was created with the
* correct table and populated with the correct data.
*/
public void testPreConditions() {
Assert.assertNotNull(this.activity);
BBCTTestUtil.assertDatabaseCreated(this.inst.getTargetContext());
Assert.assertTrue(this.dbUtil.containsAllBaseballCards(this.allCards));
Assert.assertNotNull(this.listView);
BBCTTestUtil.assertListViewContainsItems(this.inst, this.allCards,
this.listView);
}
/**
* Test that the {#link ListView} is updated when the user adds a new card
* which matches the current filter.
*
* #throws Throwable
* If an error occurs while the portion of the test on the UI
* thread runs.
*/
public void testAddCardMatchingCurrentFilter() throws Throwable {
this.testYearFilter();
Activity cardDetails = BBCTTestUtil.testMenuItem(this.inst,
this.activity, R.id.add_menu, BaseballCardDetails.class);
BBCTTestUtil.addCard(this, cardDetails, this.newCard);
BBCTTestUtil.clickCardDetailsDone(this, cardDetails);
this.expectedCards.add(this.newCard);
BBCTTestUtil.assertListViewContainsItems(this.inst, this.expectedCards,
this.listView);
}
/**
* Test that the {#link ListView} is updated when the user adds a new card
* after an active filter was cleared.
*
* #throws Throwable
* If an error occurs while the portion of the test on the UI
* thread runs.
*/
public void testAddCardAfterClearFilter() throws Throwable {
this.testClearFilter();
Activity cardDetails = BBCTTestUtil.testMenuItem(this.inst,
this.activity, R.id.add_menu, BaseballCardDetails.class);
BBCTTestUtil.addCard(this, cardDetails, this.newCard);
BBCTTestUtil.clickCardDetailsDone(this, cardDetails);
this.allCards.add(this.newCard);
BBCTTestUtil.assertListViewContainsItems(this.inst, this.allCards,
this.listView);
}
private List<BaseballCard> allCards;
private List<BaseballCard> expectedCards;
private Instrumentation inst = null;
private Activity activity = null;
private DatabaseUtil dbUtil = null;
private ListView listView = null;
private BaseballCard newCard = null;
private static final int TIME_OUT = 5 * 1000; // 5 seconds
private static final String TAG = BaseballCardListWithDataTest.class
.getName();
}
It appears that a ContentProvider's lifecycle is tied to that of an Application not of the Activity that acesses it. Also, from what I can tell, ActivityInstrumentationTestCase2 creates a single Application for all the tests; only the Activity is destroyed and restarted for each test. This means that the each test will share the same ContentProvider. This means that the database file is opened with the first access by the ContentProvider and closed only after all test methods in the ActivityInstrumentationTestCase2 have finished. Since the database file remains open between test cases, the data can be accessed even after the file is deleted from the underlying file system. My solution was to delete the rows of the database individually rather than deleting the entire database.

Android cancel Toast when exiting the app and when toast is being shown

I have read about this kind of problem here but the answers don't seem to be working.
I show a Toast when user clicks a button. When the user continously clicks the button the toast keeps on being displayed again and again even when the user exits the activity.
The length of the toast is short. Length of the toast cannot be changed as the text is long.
This is what i have tried as of now:
Toast toast;
toast=Toast.makeText(getApplicationContext(),"text",Toast.LENGTH_SHORT);
if(toast.getView().isShown()==false){
toast.show();
}
This did not work.
I tried :
if(toast.getView().isShown()==true){
toast.cancel();
}
in the onStop(). For some reason the cancel method never works.
If i put the .cancel() before i show the app... then there would be another null check for that. But after doing that also it did not work. I can show a dialog box instead of a toast but that would not be a solution.
Is there any way to check whether a toast is being displayed or not?
For reference
Toast Message in Android
How to avoid a Toast if there's one Toast already being shown
How to prevent Multiple Toast Overlaps
Cancelling an already open toast in Android
The trick is to keep track of the last Toast that was shown, and to cancel that one.
What I have done is to create a Toast wrapper, that contains a static reference to the last Toast displayed.
When I need to show a new one, I first cancel the static reference, before showing the new one (and saving it in the static).
Here's full code of the Boast wrapper I made - it mimics enough of the Toast methods for me to use it. By default the Boast will cancel the previous one, so you don't build up a queue of Toasts waiting to be displayed.
This code can be found in my Github gist:
mobiRic/Boast
If you just want to know how to cancel the notifications when exiting your app, you will find lots of help in there. If you have improvements or suggestions, please feel free to fork it and get in touch. This is a very old answer, but code has been stable in production on a few apps for some time.
BTW - this should be a direct drop-in replacement for Toast in most use cases.
package mobi.glowworm.lib.ui.widget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.support.annotation.Nullable;
import android.widget.Toast;
import java.lang.ref.WeakReference;
/**
* {#link Toast} decorator allowing for easy cancellation of notifications. Use this class if you
* want subsequent Toast notifications to overwrite current ones. </p>
* <p/>
* By default, a current {#link Boast} notification will be cancelled by a subsequent notification.
* This default behaviour can be changed by calling certain methods like {#link #show(boolean)}.
*/
public class Boast {
/**
* Keeps track of certain Boast notifications that may need to be cancelled. This functionality
* is only offered by some of the methods in this class.
* <p>
* Uses a {#link WeakReference} to avoid leaking the activity context used to show the original {#link Toast}.
*/
#Nullable
private volatile static WeakReference<Boast> weakBoast = null;
#Nullable
private static Boast getGlobalBoast() {
if (weakBoast == null) {
return null;
}
return weakBoast.get();
}
private static void setGlobalBoast(#Nullable Boast globalBoast) {
Boast.weakBoast = new WeakReference<>(globalBoast);
}
// ////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Internal reference to the {#link Toast} object that will be displayed.
*/
private Toast internalToast;
// ////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Private constructor creates a new {#link Boast} from a given {#link Toast}.
*
* #throws NullPointerException if the parameter is <code>null</code>.
*/
private Boast(Toast toast) {
// null check
if (toast == null) {
throw new NullPointerException("Boast.Boast(Toast) requires a non-null parameter.");
}
internalToast = toast;
}
// ////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Make a standard {#link Boast} that just contains a text view.
*
* #param context The context to use. Usually your {#link android.app.Application} or
* {#link android.app.Activity} object.
* #param text The text to show. Can be formatted text.
* #param duration How long to display the message. Either {#link Toast#LENGTH_SHORT} or
* {#link Toast#LENGTH_LONG}
*/
#SuppressLint("ShowToast")
public static Boast makeText(Context context, CharSequence text, int duration) {
return new Boast(Toast.makeText(context, text, duration));
}
/**
* Make a standard {#link Boast} that just contains a text view with the text from a resource.
*
* #param context The context to use. Usually your {#link android.app.Application} or
* {#link android.app.Activity} object.
* #param resId The resource id of the string resource to use. Can be formatted text.
* #param duration How long to display the message. Either {#link Toast#LENGTH_SHORT} or
* {#link Toast#LENGTH_LONG}
* #throws Resources.NotFoundException if the resource can't be found.
*/
#SuppressLint("ShowToast")
public static Boast makeText(Context context, int resId, int duration)
throws Resources.NotFoundException {
return new Boast(Toast.makeText(context, resId, duration));
}
/**
* Make a standard {#link Boast} that just contains a text view. Duration defaults to
* {#link Toast#LENGTH_SHORT}.
*
* #param context The context to use. Usually your {#link android.app.Application} or
* {#link android.app.Activity} object.
* #param text The text to show. Can be formatted text.
*/
#SuppressLint("ShowToast")
public static Boast makeText(Context context, CharSequence text) {
return new Boast(Toast.makeText(context, text, Toast.LENGTH_SHORT));
}
/**
* Make a standard {#link Boast} that just contains a text view with the text from a resource.
* Duration defaults to {#link Toast#LENGTH_SHORT}.
*
* #param context The context to use. Usually your {#link android.app.Application} or
* {#link android.app.Activity} object.
* #param resId The resource id of the string resource to use. Can be formatted text.
* #throws Resources.NotFoundException if the resource can't be found.
*/
#SuppressLint("ShowToast")
public static Boast makeText(Context context, int resId) throws Resources.NotFoundException {
return new Boast(Toast.makeText(context, resId, Toast.LENGTH_SHORT));
}
// ////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Show a standard {#link Boast} that just contains a text view.
*
* #param context The context to use. Usually your {#link android.app.Application} or
* {#link android.app.Activity} object.
* #param text The text to show. Can be formatted text.
* #param duration How long to display the message. Either {#link Toast#LENGTH_SHORT} or
* {#link Toast#LENGTH_LONG}
*/
public static void showText(Context context, CharSequence text, int duration) {
Boast.makeText(context, text, duration).show();
}
/**
* Show a standard {#link Boast} that just contains a text view with the text from a resource.
*
* #param context The context to use. Usually your {#link android.app.Application} or
* {#link android.app.Activity} object.
* #param resId The resource id of the string resource to use. Can be formatted text.
* #param duration How long to display the message. Either {#link Toast#LENGTH_SHORT} or
* {#link Toast#LENGTH_LONG}
* #throws Resources.NotFoundException if the resource can't be found.
*/
public static void showText(Context context, int resId, int duration)
throws Resources.NotFoundException {
Boast.makeText(context, resId, duration).show();
}
/**
* Show a standard {#link Boast} that just contains a text view. Duration defaults to
* {#link Toast#LENGTH_SHORT}.
*
* #param context The context to use. Usually your {#link android.app.Application} or
* {#link android.app.Activity} object.
* #param text The text to show. Can be formatted text.
*/
public static void showText(Context context, CharSequence text) {
Boast.makeText(context, text, Toast.LENGTH_SHORT).show();
}
/**
* Show a standard {#link Boast} that just contains a text view with the text from a resource.
* Duration defaults to {#link Toast#LENGTH_SHORT}.
*
* #param context The context to use. Usually your {#link android.app.Application} or
* {#link android.app.Activity} object.
* #param resId The resource id of the string resource to use. Can be formatted text.
* #throws Resources.NotFoundException if the resource can't be found.
*/
public static void showText(Context context, int resId) throws Resources.NotFoundException {
Boast.makeText(context, resId, Toast.LENGTH_SHORT).show();
}
// ////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Close the view if it's showing, or don't show it if it isn't showing yet. You do not normally
* have to call this. Normally view will disappear on its own after the appropriate duration.
*/
public void cancel() {
internalToast.cancel();
}
/**
* Show the view for the specified duration. By default, this method cancels any current
* notification to immediately display the new one. For conventional {#link Toast#show()}
* queueing behaviour, use method {#link #show(boolean)}.
*
* #see #show(boolean)
*/
public void show() {
show(true);
}
/**
* Show the view for the specified duration. This method can be used to cancel the current
* notification, or to queue up notifications.
*
* #param cancelCurrent <code>true</code> to cancel any current notification and replace it with this new
* one
* #see #show()
*/
public void show(boolean cancelCurrent) {
// cancel current
if (cancelCurrent) {
final Boast cachedGlobalBoast = getGlobalBoast();
if ((cachedGlobalBoast != null)) {
cachedGlobalBoast.cancel();
}
}
// save an instance of this current notification
setGlobalBoast(this);
internalToast.show();
}
}
Instead of cancelling the toast. change the text. For Example
Toast t;
t = Toast.makeText(this, "hi", 3000);
t.show();
when you need a different toast then use
t.setText("bye");
t.show();
And If you want to dismiss the toast simply call t.cancel()
You can cancel individual Toasts by calling cancel() on the Toast object. AFAIK, there is no way for you to cancel all outstanding Toasts, though.
Try keeping the timestamp of the last toast, and don't allow any new toasts until a timeout period has elapsed.
Something like:
private static final long TOAST_TIMEOUT_MS = 2000; // tweak this constant
private static long lastToastTime = 0;
public void onButtonClicked() {
long now = System.currentTimeMillis();
if (lastToastTime + TOAST_TIMEOUT_MS < now) {
Toast.makeText(...).show();
lastToastTime = now;
}
}
I wouldn't worry about a single toast sticking around for a second after the user exits the app -- this is a pretty standard behavior.

Categories

Resources