Stepper Motors Experiment with PSLab

PSLab device is capable of building up a complete science lab almost anywhere. While the privilege is mostly taken by high school students and teachers to perform scientific experiments, electronic hobbyists can greatly be influenced from the device. One of the usages is to test and debug sensors and other electronic components before actually using them in their projects. This blog will explain how steppers motors can be used with PSLab.

A stepper motor is an electromechanical device which converts electrical power into mechanical power. Also it is a brushless, synchronous electric motor that can divide a full rotation into an expansive number of steps. The stepper motor uses the theory of operation for magnets to make the motor shaft turn a precise distance when a pulse of electricity is provided. Stepper motors are similar to switched reluctance motors. [1]


Figure 1: Showing the working of a stepper motor [4]                                                      

Figure 1 shows the animation of a simplified stepper motor. Unlike a brushless DC motor which rotates continuously when a fixed DC voltage is applied to it, a step motor rotates in discrete step angles as shown in the above figure.

How Stepper Motors Work?

  • Stepper Motor works on the principle of electromagnetism.
  • Stepper motors consist of a permanent magnetic rotating shaft, called the     rotor, and electromagnets on the stationary portion that surrounds     the motor, called the stator.
  • Figure 1 illustrates one complete rotation of a stepper motor. At position 1, we can see that the rotor is beginning at the upper     electromagnet, which is currently active (has voltage applied to it).
  • To move the rotor clockwise (CW), the upper electromagnet is deactivated and the right electromagnet is activated, causing the rotor to move 90 degrees CW, aligning itself with the active magnet.
  • This process is repeated in the same manner at the south and west     electromagnets until we once again reach the starting position.

           Figure  (2): Showing different stages of stepper motors’ working cycle [3]

What are the most common reasons to choose stepper motors over other types? [2]

  1. Positioning     Since steppers move in precise repeatable steps, they excel in applications requiring precise positioning such as 3D printers, CNC, Camera platforms and X,Y Plotters. Some disk drives also use stepper motors to position the read/write head.
  2. Speed Control – Precise increments of movement also allow for excellent control of rotational speed for process automation and robotics.
  3. Low Speed Torque – Normal DC motors don’t have very much torque at low speeds. A Stepper motor has maximum torque at low     speeds, so they are a good choice for applications requiring low speed with high precision.

Applications of Stepper Motors [2]

  1. Industrial Machines – Stepper motors are used in automotive gauges and machine tooling automated production equipments.
  2. Office Equipments – Stepper motors are incorporated inside PC based scanning equipment, data storage tape drives, optical disk drive head driving mechanism, printers, bar-code printers, scanners
  3. Medical – Stepper motors are used inside medical scanners, samplers, and also found inside digital dental photography, fluid pumps, respirators and blood analysis machinery.
  4. Consumer Electronics – Stepper motors in cameras for automatic digital camera focus and zoom functions.

       

Figure  (3) :Figure showing stepper motors being used in robo -arms [5]

Implementation of Stepper Motor in PSLab

Figure  (4) :A screenshot of Stepper Motor Experiment using PSLab Android App.

  • In the PSLab the stepper motor experiment is implemented to tell the user what a stepper motor is  and how to use it.
  • There is one field to enter the number of steps i.e the breaks in one one rotation which the stepper motor will have.
  • Using PSLab device experiment “Stepper Motor”, a user can acquire any number of steps just by entering the step value in the text box.
  • The following code is implemented for executing the function.
private void setSteps() {
         int stepCount = Integer.parseInt(steps.getText().toString());
         if (stepCount > 0) {
               stepForward(stepCount);
         } else {
               stepBackward(stepCount);
         }
}
  • The other two buttons are designed for choosing the direction in which the motor  will rotate.
  • The following code is for the backward function.
private void stepBackward(final int steps) {
    java.lang.Runnable runnable = new java.lang.Runnable() {
        @java.lang.Override
        public void run() {
            scienceLab.stepBackward(steps, 100);
        }
    };
    new java.lang.Thread(runnable).start();
}
  • Thus when the stepper motor  is connected to the PSLab device and the android application experiment is made to run, the stepper motor will rotate accordingly.

Resources

  1. https://learn.adafruit.com/all-about-stepper-motors/what-is-a-stepper-motor
  2. https://www.elprocus.com/stepper-motor-types-advantages-applications/
  3. https://www.imagesco.com/articles/picstepper/02.html
  4. https://en.wikipedia.org/wiki/Stepper_motor
  5. https://www.instructables.com/id/Robot-Arm-MK2-Plus-Stepper-Motor-Used/

Continue Reading

Working with Logic Analyzer in PSLab Android app

This blog demonstrates the working of Logic Analyzer instrument available in PSLab Android app. It also includes a detailed description of the features available in the Logic Analyzer instrument along with a step by step guide on how to work with it which will be beneficial to first-time users of the PSLab application.

The functionality of the Logic Analyzer available in PSLab Android app is same as that in PSLab Desktop App. So, it would be easy for a user of PSLab Desktop Application to get acquainted with this Logic Analyzer. The only difference in this instrument is the changed and attractive UI which makes working with it very easy.

Why use Logic Analyzer?

The Logic Analyzer instrument provides the functionality of capturing and plotting the digital waves on the screen so that it would be easy for a user to determine the time relationship between different waves. So, this instrument would be very useful while working with timing diagrams, protocol decodes, state machines traces, assembly language, or with source-level software.

How to generate different digital pulses in the PSLab app?

Logic Analyzer needs to be provided with some input of digital pulses among whom time relationship is to be found out. Digital pulses generated from different systems can be directly provided as input to the Logic Analyzer for analyzing. But PSLab provides a functionality to generate digital pulses up to some constrained frequency.

Following are the steps to generate different digital waves in PSLab Android application :

  • Open PSLab Android application and click on the Wave Generator tile as shown in figure 1. After opening the instrument, the screen will look as shown in figure 2.

Figure 1. Wave Generator instrument tile available in PSLab Android app

Figure 2. The main screen of the Wave Generator instrument

  • Click on the MODE button to change the mode to PWM. The screen will look as shown in figure 3.

Figure 3. PWM mode in Wave Generator

  • PSLab device provides generation of maximum four digital waves at once. In this example, I will proceed by utilizing only two pins i.e. SQR1and SQR2 (where SQR = Acronym of square wave generator and the number next to it is the pin ID available on the PSLab device) to demonstrate the working of Two Channel Mode in Logic Analyzer. Set the duty cycles and frequency for the selected pins as desired (try to keep all the duty cycles different from each other to understand the process of measurement easily).

NOTE: User can also set phase angle for different waves but I will proceed with defaults.

How to analyze the generated waves in Logic Analyzer?

  • Now go back and select the Logic Analyzer tile as shown in figure 4 from the list of available instruments. A screen as shown in figure 5 should open.

Figure 4. Tile of Logic Analyzer instrument available in the PSLab app

Figure 5. The main screen of the Logic Analyzer instrument

On the right-hand side, you can see a slider whose initial value is SELECT which shows the information on how to use the slider below it. Below the Channel Selection area is the Analyze button used to fetch and plot the data which is generated or provided to the respective Logic Analyzer pins i.e. ID1, ID2, ID3, and ID4.

The blank area on the left is where the graph will be plotted after fetching data points. Below it is the Axis Indicator used to indicate the position of the highlighter so that time measurement can be done easily. To the right of the Axis Indicator is a small light which indicates the status of the device. It turns GREEN if the device is connected else it remains in RED.

  • In this blog, I will demonstrate the Two Channel Mode. But all the other available modes need the same implementation by only varying the number of pins in use. So, slide to 2 in the Carousel View and a screen as shown in figure 6 will pop up.

Figure 6. Two Channel Mode in Logic Analyzer

  • Connect the wires on the PSLab device as shown in Figure 7.

Figure 7. Connecting wires on PSLab

NOTE: The Logic Analyzer pins used in this demonstration are ID1 and ID2. But any IDx pin can be chosen for analysis. But try to maintain the selected choice throughout the implementation.

  • Now from the Channel Selection area, select the channel for the first card to  ID1 (default) and that for the second card to ID2. For Edges Selection, maintain the defaults.

NOTE: There are several options available for plotting the digital waves besides the default selected i.e.

  1. Every Edge – Plot every edge of the signal
  2. Falling Edges – Plot only falling edges of the signal (When a signal comes from 1 to 0 state)
  3. Rising Edges Only – Plot only rising edges of the signal (When a signal comes from 0 to 1 state)
  4. Disabled – Don’t plot the selected wave
  • After Channel Selection, press the Analyze button to plot the data. On pressing the Analyze button, a circular loading sign will appear showing that the data is being fetched and converted to data that can be plotted. As soon as the data is ready to be plotted, the loading sign vanishes and the graph appears as shown in figure 8.

Figure 8. GIF showing the loading and analyzing processes

  • The time relationship between the plotted data can be found out by clicking over the rising/falling edges and noting the time shown in the Axis Indicator as shown in figure 8.
  • An example of Edge Selection is shown in figure 9.

Figure 9. Example of Edge Selection option

Here, EVERY FALLING EDGE option is selected for the ID1 channel and EVERY RISING EDGE option is selected for the ID2 channel.

So in this way, the Logic Analyzer instrument available in PSLab Android application can be used to ease out the process of calculating the time interval between different edges for different/same digital pulse/s.

Resources

  1. PSLab Android Application – https://github.com/fossasia/pslab-android (Link to repo)
  2. PSLab device pins sticker – https://github.com/fossasia/pslab-artwork/blob/master/Sticker/pslabdesign.png

Continue Reading

Implementing the discrete Seekbar for Wave Generator

The Wave Generator instrument in PSLab Android app allows us to produce waveforms having different values of properties like frequency, duty, phase etc.

The range of these properties allowed by PSLab Device are :

Table showing the range of properties that can be set for waves by PSLab device
Wave Property Range
Min Max Step Size
Frequency 10 Hz 5000 Hz 1 Hz
Phase 360°
Duty 10% 100% 10%

We can set these values using the up/down arrow buttons provided by the wave generator but the problem is that the range of values is very high and least counts are small so it is convenient to set the values using only the up and down arrow buttons.

Therefore we need something that could allow us to directly set any value of our choice while keeping the UI interactive.

The solution to this problem – “Discrete Seekbar”. It contains a slider having points at equal intervals and whose length represents the range of the values and a head that slides over the slider and is used to select a specific value from a range of values.

I have included the discrete Seekbar in Wave Generator by using a third-party library if you want to add Seekbar directly you can do that by directly using the default Seekbar widget provided by Android SDK and setting the following attribute in as shown below.

android:theme = “@style/Widget.AppCompat.SeekBar.Discrete”

Refer to this post[2] for implementing Seekbar directly without an external library.

The reason I chose this library is that:-

  • It offers various implementation of different types of Seekbar like discrete and continuous.
  • Implementation of Seekbar is simpler and it offers various customizations like thumb color, track color, tick text etc.  

In following steps I will implement the discrete Seekbar:

Step 1 Adding the dependency

For this project, I will be using an external library “IndicatorSeekbarLibrary” by Warkiz[1], for adding the dependency we need to include the following code in our build.gradle file.

dependencies{
implementation 'com.github.warkiz.widget:indicatorseekbar:2.0.9'
}

Step 2 Including the Seekbar in layout

For this step, we need to add the Seekbar widget using <com.warkiz.widget.IndicatorSeekBar> XML tag in our wave generator layout file to include the Seekbar in our layout as shown in the code below:

<com.warkiz.widget.IndicatorSeekBar
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:isb_max="5000"
    app:isb_min="0"
    app:isb_ticks_count="5"
    app:isb_thumb_color="@color/color_green"
    app:isb_thumb_size="20dp"
    app:isb_track_background_color="@color/color_gray"
    app:isb_track_background_size="2dp"
    app:isb_track_progress_color="@color/color_blue"
    app:isb_track_progress_size="4dp" />

Some important attributes used above:

app:isb_max : defines the max value that can be achieved by the Seekbar.

app:isb_min :  defines the min value that can be achieved by the Seekbar

app:isb_ticks_count: no. of ticks(interval) that has to be shown on the slider

We can see different components of Seekbar like track, indicator, thumb, tick of SeekBar in the following diagram[2].

Figure 1 depicts the different attributes of the slider
(Source – https://github.com/warkiz/IndicatorSeekBar/blob/master/README.md)

Step 3 Attaching the listener to the Seekbar in Java file

In this step we need to attach the listener to the Seekbar to record changes in the Seekbar made by the user, for this we will create a new listener with the help of onSeekBarChangeListener interface and attach it with the Seekbar as shown in following code

IndicatorSeekBar seekbar = (IndicatorSeekBar) findViewbyId(R.id.seekbar);

seekBar.setOnSeekChangeListener(new OnSeekChangeListener() {
            @Override
            public void onSeeking(SeekParams seekParams) {
                /* called when the user is sliding the thumb */
            }

            @Override
            public void onStartTrackingTouch(IndicatorSeekBar seekBar) {
                /* called when the sliding of thumb is started */
            }

            @Override
            public void onStopTrackingTouch(IndicatorSeekBar seekBar) {
                /* called when the sliding of thumb stops */
            }
        });

After following all the above steps, I  implemented the Seekbar shown in Figure 2 below in my wave generator and now it becomes really easy to set different values of properties for without having to continually press the up/down button.

Figure 2 shows the Seekbar included in wave generator beside up/down arrow button

Resources

  1. warkiz/IndicatorSeekBar library  – Github Repo of the Indicator SeekBar library
  2. http://nileshsenta.blogspot.com/2016/10/discrete-seekbar-without-third-party.html – Blog by Nilesh Shenta on how to implement discrete without third party library

 

Continue Reading

Implementing Carousel Slider in PSLab Android App

This blog is a demonstration for creating a Carousel Picker in Android by taking an example of the Carousel Picker made in PSLab Android app under PR #1007. Some improvement to this would be to add custom animation to the ViewPager and adjusting the ViewPager sliding speed. So first let’s start with the basics and terminology of Carousel.

What is Carousel?

Carousel according to the dictionary means roundabout or merry-go-round. The term was mainly used for the traditional amusement ride of a merry-go-round in amusement parks with seats of horses. The same is the working of Carousel View in Android. It gives a smooth sliding effect to slide between a variety of options available.

How to implement Carousel View in the app?

Following are the steps to implement a basic Carousel View in the app. Further effects and upgrades can be given as per the need.

  • The first step is to add jitpack to your app’s gradle file
maven { url 'https://jitpack.io '}
  • Now add a library dependency in your project level gradle file
compile 'com.github.Vatican-Cameos:CarouselPicker:v1.0

The above dependency uses the View Pager and Gesture Detector functionality provided by Android. The Gesture Detector class detects the swipe gesture made by the user and the View Pager highlights the relevant label in the Carousel box according to the swipe done i.e left or right.

  • Now Carousel Picker is ready to be added directly to layouts. So, add the Carousel by adding the following layout code at a proper section in layouts file.
<in.goodiebag.carouselpicker.CarouselPicker
	android:id="@+id/carouselPicker"
	android:layout_width="match_parent"
	android:layout_height="wrap_content"
	android:layout_marginTop="20dp"
	android:layout_marginBottom="20dp"
	android:background="#DDD"
	apps:items_visible="three" />

Here, the items_visible is used to provide the Carousel Picker with the number of max items to be seen at a time on screen where only one item will be in focus. Other items are adjusted on the side and can be viewed by scrolling.

  • Now as we have implemented the layouts, so now’s the time to set adapter and resource type for Carousel to hold in Java files. First, find the Carousel View with its id.
CarouselPicker carouselPicker = findViewById(R.id.carouselPicker);
  • Now set a list of items to be added in the Carousel Picker. The items can be both images and texts.
List<CarouselPicker.PickerItem> items = new ArrayList<>();

To add images :

items.add(new CarouselPicker.DrawableItem(R.mipmap.ic_launcher));

To add texts/strings :

items.add(new CarouselPicker.TextItem("Example", 10));

Here, the integer that is added after the text indicates the size in sp of the text that is to be displayed in Carousel View.

  • Now after creating a list of items, make an adapter which provides this list of information to Carousel Picker.
CarouselPicker.CarouselViewAdpater adapter = new CarouselPicker.CarouselViewAdpater(this, items);
  • Now set the adapter for the Carousel View :
carouselPicker.setAdapter(adapter);
  • To dynamically add items to the Carousel View, simply change the list of items in the list provided to the adapter and then use
adapter.notifyDataSetChanged();
  • Now to change the functionality of the app with every Carousel item, implement the onPageChangeListener as Carousel View implements ViewPager class.
carouselPicker.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        	@Override
        	public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        	}

        	@Override
        	public void onPageSelected(int position) {
        	}

        	@Override
        	public void onPageScrollStateChanged(int state) {
          }

Following GIF shows how Carousel View looked after implementation in PSLab app. Each option provided in the view was used to provide user with a different channel selection mode.

Figure 1. GIF of implemented Carousel View in PSLab app

So in this way, a Carousel Picker or Carousel View can be implemented in the app. Further functionalities of animations, mirroring, shadow effect, all can be done with just minor changes in the above code. And to fully customize the look of the Carousel or to enable infinite scrolling feature, a local Carousel Picker can be implemented by just making a custom adapter and a class that extends ViewPager class. Below are the resources to implement both custom and dependency based Carousel View.

Resources

  1. https://www.youtube.com/watch?v=sTJm1Ys9jMI – Youtube Video for dependency based Carousel View
  2. https://www.youtube.com/watch?v=4ct0oPf_u2o – Youtube Video for implementing infinite scrolling
  3. http://www.codexpedia.com/android/android-carousel-view-using-viewpager/ – An article to implement custom Carousel View

 

 

 

 

 

Continue Reading

Working with Logic Analyzer in PSLab application

This blog demonstrates the working of Logic Analyzer instrument available in PSLab Desktop Application. It also includes a detailed description of the features available in the Logic Analyzer instrument. Also, it provides a step by step guide on how to work with the Logic Analyzer provided by PSLab which will be beneficial to first-time users.

What is a Logic Analyzer?

A Logic Analyzer is an electronic instrument used to capture and display digital signals with an added functionality of providing the time difference between different edges of different pulses. It is mainly used to observe the time relationship between different digital signals. An example of a standard Logic Analyzer available in the market is as shown in figure 1.

Figure 1. Standard Logic Analyzer

How to generate different digital pulses in PSLab?

Logic Analyzer needs to be provided with some input of digital pulses among whom time relationship is to be found out. Digital pulses generated from different systems can be directly provided as input to the logic analyzer for analyzing. But PSLab provides a functionality to generate digital pulses up to some constrained frequency.

Following are the steps to generate different digital waves in the PSLab desktop application :

  • Go to Advanced Control Section of PSLab app. The screen should look like one as shown in Figure 2.

Figure 2.  Advanced Control Section

  • PSLab device provides generation of maximum four digital waves at once. In this example, I will proceed by utilizing all the four pins i.e. SQR1, SQR2, SQR3, SQR4 (where SQR = Acronym of square wave generator and the number next to it is the pin ID available on the PSLab device). Set the duty cycles for each of the pins as desired (try to keep all the duty cycles different from each other to understand the process of measurement easily). After setting it should look something like Figure 3.

Figure 3. Configuring PWM

NOTE: User can also set phase angle for different waves but I will proceed keeping all without any phase difference.

  • Now set the frequency of the digital waves in the tab provided next to text Frequency and then press the SET button. This should generate desired digital waves when connected.

How to analyze the generated waves in Logic Analyzer?

  • Now go to the Experiments section and click on the Logic Analyzer instrument as shown in Figure 4.

Figure 4. Test and Measurement Page

  • Now a screen as shown in Figure 5 should open which is the main screen for Logic Analyzer Instrument.

Figure 5. Logic Analyzer Main Page

On the right, you can see three buttons i.e Start, Plot Data and Raw Data. Below that selection for the number of channels is provided. And at last, the time measurement tool is provided which can measure the time difference between different edges of different digital waves. The graph at the center is the place where all the waves generated will be plotted.

  • Now as we have generated four different waves, we need to navigate to Four Channel Mode in the Channel Selection section. There you can observe four pins i.e. ID1, ID2, ID3, and ID4 are selected by default as shown in Figure 6. So, we need to connect the pins SQR1, SQR2, SQR3 and SQR4 with pins ID1, ID2, ID3 and ID4 on the PSLab device.

Figure 6. Channel Selection Section

NOTE: There are several options available for plotting the digital waves besides the one selected in the above image i.e.

  1. Every Edge – Plot every edge of the signal
  2. Falling Edges – Plot only falling edges of the signal (When a signal comes from 1 to 0 state)
  3. Rising Edges Only – Plot only rising edges of the signal (When a signal comes from 0 to 1 state)
  4. Disabled – Don’t plot the selected wave

Figure 7. Connecting wires on PSLab device

  • Connect the wires on the PSLab device as shown in Figure 7.
  • Now, as the device is connected, we can use the three buttons located at the top right corner to plot the digital waves. The functionalities of all the three buttons are as follows:
  1. Start – It collects exactly 2500 sample points from the wave generated to be plotted
  2. Plot Data – It plots the data on the graph if the samples are collected successfully
  3. Raw Data – It provides a sheet containing time at particular intervals and the difference between the data points at that particular time
  • Press the Start button and as soon as the samples are collected, press the Plot Data button. Then the screen should look something like Figure 8.

Figure 8. Final graph of input provided

Zoom in further, and the screen will look like Figure 9.

Figure 9. Zoomed In graph for better visualization

  • So now, the waves are plotted and are ready to be analyzed. Time difference between any two edges for any two distinct or a similar wave can be found out by using the TIME INTERVAL MEASUREMENT TOOL which is as shown in Figure 10.

Figure 10. Time Interval Measurement Tool

  • The working of this tool can be explained by taking an example as follow :

Figure 11. Configuring the Time Interval Measurement Tool

Suppose time difference between the rising edge of ID1 and falling edge of ID3 is to be measured. So, set the parameters as shown in Figure 11 for the following situation.

The timeout of the Logic Analyzer can be set to any desired value from 10mS to 9999 mS. Here, I will proceed with 10mS of the timeout. Now, press the measure button to see the result. It will be same as the Figure 12 shown below if all the configurations are set as the one in the  example :

Figure 12. Calculated time difference displayed

So in this way, many calculations can be taken out very easily and can be viewed at once at a single place without manually doing any calculations. Also, the data generated can be stored in the local system by pressing the Save Data button located at the bottom right corner.

Resources

  1. PSLab Desktop Application – https://github.com/fossasia/pslab-desktop-apps (Link to repo)
  2. PSLab device pins sticker – https://github.com/fossasia/pslab-artwork/blob/master/Sticker/pslabdesign.png

 

Continue Reading

Submitting a Github Issue through a Google Form

The Pocket Science Lab Android app has various functionalities which have been already implemented but it been on the verge of development, many functionalities are yet to be implemented completely, one such functionality is how the users report the issues of the app, to which comes the idea of using a Google form inside the app for the users to fill it and the issue get directly opened in Github.

Submitting a Github issue through a Google forms requires two things:-

    1. A Github access token which gives access to open a new issue.
      • To generate a Github access token one must follow these steps[2]
        • Go to the personal settings.

        • Select  Developers settings option from it.
        • In Developers settings option Go to personal access tokens and generate an access token.
    1. A fully-structured Google form which has all the details about the issue i.e the title of the issue, the body of the issue, label, etc..
      • Using a Google account create a Google Form which have all the relevant questions about that issue such as title of the issue, body of the issue, label etc..

Once done with all the steps follow these steps to send a Github issue[1]

    1. Click the Responses tab, in it click the More icon.
    2. Select Choose a response destination.
    3. Select New spreadsheet: Creates a new spreadsheet in Google Sheets for responses.
    4. Click Create to create and open the sheet.

Configure the App Script Logic[1]

    1. You should have a newly created blank spreadsheet with headers automatically generated from your form.
    2. Click Tools > Script editor… to launch the App Script editor coding environment. This Script will be bound to your sheet, so you can listen for form submissions and fire off a new issue to your GitHub repo.
    3. In the script editor write the following code
function onFormSubmit(e) {

var title = e.values[1];
var body = e.values[2];
var label = "User opened issue"
var payload = {
"title": title,
"body": a_body,
"label": label,
};

var options = {
"method": "POST",
"contentType": "application/json",
"payload": JSON.stringify(payload)
};
var response = UrlFetchApp.fetch("https://api.github.com/repos/abhinavraj23/AgeGroup/issues?access_token="+ghToken, options)
}

Note:The onFormSubmit function includes an event object e, which includes the form/spreadsheet field values as a simple array with values in the same order as they appear in the spreadsheet. e.values[0] is the first spreadsheet column

The following google-app script uses GitHub Issues API for posting a new issue in Github.

4.Give your app script project a name and save it .

Set up the Trigger[1]

        1. From within the app script editor, click Resources > Current project’s triggers.
        2. Click to add a trigger
          1. Run: onFormSubmit
          2. Events: From spreadsheet, On form submit
        3. Click Save and accept any authorizations to access your forms and access web services on your behalf.
        4. This trigger will listen to form submissions and pass the data to your function, which POSTs the new issue to your GitHub repo.

Thus using these steps one can submit an issue in github through a Google Form and thus the Google Forms can be used in the app as the users can send the issues using a google form, and through this method one can also get the email-id of the user for further contact and thus this is a very  useful method.

Resources

      1. Bmcbride, google-form-to-github-issue,gist.github.com: https://gist.github.com/bmcbride/62600e48274961819084#set-up-the-trigger
      2. Github help, Creating personal access token,help.github.com: https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/

Continue Reading

Implementing Card View in PSLab app

Card View was announced by Google in I/O ‘14 conference. Although it started a bit slow, but now we can see most of the apps like Snapchat, Google, Facebook, etc. using this widget. So, this blog is solely contributed on how to implement Card View in your own app by taking example of PSLab application.

What is Card View ?

CardView is a view container or ViewGroup that inherits its nature from FrameLayout which further inherits from ViewGroup itself. The only thing that separates a CardView from any other ViewGroups is its nature to behave like a card, more specifically the shadow and rounded corners. The basic customization that a CardView provides includes CornerRadius, Elevation, MaxElevation, ContentPadding, CompatPadding, PreventCornerOverlap, and a dedicated CardBackgroundColor or say Card Background which is the most necessary feature for a card to look cool.

Step by Step description how CardView was implemented in PSLab

  • First step is to add dependencies in your project as widgets like Card View, Recyclerview, etc. are not included in a common repository of widgets provided by Google.

App level dependency :

compile 'com.android.support:cardview-v7:26.0.0'
compile 'com.android.support:recyclerview-v7:+'

If you are using Android Studio 3.0+ than add the following dependency instead of above :

implementation 'com.android.support:cardview-v7:26.0.0'
implementation 'com.android.support:recyclerview-v7:27.1.1'
  •  Now we can use Card View widget in our app. So, first make add card view in layout section like this :
<android.support.v7.widget.CardView
    	android:id="@+id/card_view"
    	android:layout_width="match_parent"
    	android:layout_height="@dimen/total_height_card"
    	android:layout_gravity="center"
    	android:layout_margin="@dimen/card_margin"
    	card_view:cardCornerRadius="@dimen/card_radius">
 </android.support.v7.widget.CardView>

These are the basic attributes that are used while declaring a card view. Other possible attributes can be :

  1. Elevation – Used to elevate card to give a depth effect
  2. MaxElevation – Used to give constraint to the depth effect
  3. ContentPadding – Used to provide padding between content and the card
  4. PreventCornerOverlap – To prevent different corners to overlap as shown in figure 1.

Figure 1. Image showing corner overlapping in CardView

  • Now to set the objects inside the Card View, mostly RelativeLayout is preferred as it gives the freedom to place objects in reference of others whereas LinearLayout provides freedom to place them in only one direction. Other layouts such as FrameLayout, Tables, etc. can be used as per the need of the app.
  • Now we will create a layout that will hold all the cards using RecyclerView.
<android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:scrollbars="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
  • Now after setting the layouts, it’s time to make adapter which inflates the information in the cards which is then represented using RecyclerView.
public class ApplicationAdapter extends RecyclerView.Adapter<ApplicationAdapter.Holder> {

	private List<ApplicationItem> applicationList;
	private final OnItemClickListener listener;
	/**
 	* View holder for application list item
 	*/
	public class Holder extends RecyclerView.ViewHolder {

    	TextView header, description;
    	ImageView applicationIcon; //Background Image

    	public Holder(View itemView) {
        super(itemView);
        this.header = itemView.findViewById(R.id.heading_card);
        this.description = itemView.findViewById(R.id.description_card);
        this.applicationIcon = itemView.findViewById(R.id.application_icon);
    	}

    	public void setup(final ApplicationItem applicationItem, final OnItemClickListener listener) {
      header.setText(applicationItem.getApplicationName());
      description.setText(applicationItem.getApplicationDescription());
      applicationIcon.setImageResource(applicationItem.getApplicationIcon());
         }
	}

	public ApplicationAdapter(Context mContext, List<ApplicationItem> applicationList, OnItemClickListener listener) {
    	this.mContext = mContext;
    	this.applicationList = applicationList;
    	this.listener = listener;
	}

     @Override
	public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
    	View itemView = LayoutInflater.from(parent.getContext())
            	.inflate(R.layout.application_list_item, parent, false);
    	return new Holder(itemView);
	}

Following is the detailed explanation of each and every method :

  1. Holder(View ) – As name suggests, it holds all the items that are included in a single card together
  2. setup() – This method can contain any number of parameters as per requirement. It basically sets the data in the views in the card
  3. ApplicationAdapter() – Constructor
  4. onCreateViewHolder() – It inflates the layout containing CardView as soon as the data gets ready to be fed in it
  • Now as adapter is ready, we can declare RecyclerView in Java code to implement CardView. The main reason to use RecyclerView is that it provides the feature of scrollability so that a number of cards can be adjusted on the screen. ScrollView can also be used but it slows down the app as it tries to load all the card at once rather than loading cards as per use like RecyclerView.
RecyclerView listView = view.findViewById(R.id.applications_recycler_view);
    	RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(context, rows);
    	listView.setLayoutManager(mLayoutManager);
    	listView.setItemAnimator(new DefaultItemAnimator());
    	listView.setAdapter(applicationAdapter);

Here, we have used GridLayoutManager to use grids along with RecyclerView. It is optional and can be used as per requirement. Also, before setting adapter, fill the adapter with relevant data or else no card will be seen in actual app.

  • Now the app is ready to be built and tested on mobile device. This is how it looks in the PSLab application after implementing the above guide :

Figure 2. Screenshot of CardView implemented in PSLab app

So, in this way great user experience can be given by using this very basic widget. But great attention should be given while designing the objects inside the card as the selection and position of the objects is what makes the card look good. Objects used in making cards for PSLab very well suited the app and so are designed like that. Practice should be done by taking reference of some very good apps like Snapchat, Google, etc. and from Material Designs provided by Google before implementing them in actual project.

Resources

  1. https://www.androidhive.info/2016/05/android-working-with-card-view-and-recycler-view/ – This article gives a better practice by implementing a real world example
  2. https://developer.android.com/reference/android/support/v7/widget/CardView – Official documentation by Google on CardView
  3. https://developer.android.com/guide/topics/ui/layout/recyclerview – Official documentation by Google on RecyclerView

Continue Reading

Creating Instruction Guide using Bottomsheet

The PSLab android app consists of different instruments like oscilloscope, multimeter, wave generator etc and each instrument has different functionality and usage so it is necessary that there should be an instruction guide for every instrument so that the user can easily read the instruction to understand the functionality of the instrument.

In this we will create an instruction guide for the Wave Generator which will contain information about the instrument, it’s functionalities, steps for how to use the instrument.

The main component that I used to create instruction guide is Bottom SheetBottom Sheet is introduced in Android Support v23.2 . It is a special UI widget which slide up from the bottom of the screen and it can be used to reveal some extra information that we cannot show on the main layout like bottom menus,  instructions etc.

They are of two types :

  1. Modal Bottom Sheet:–  This Bottom Sheet has properties very similar to normal dialogs present in Android like elevation only difference is that they pop up from the bottom of screen with proper animation and they are implemented using BottomSheetDialogFragment Class.

  2. Persistent Bottom Sheet:– This Bottom Sheet is included as a part of the layout and they can be slid up and down to reveal extra information. They are implemented using BottomSheetBehaviour Class.

For my project, I used persistent Bottom Sheet as modal Bottom Sheet can’t be slid up and down by the swipe of the finger whereas persistent Bottom Sheet can be slid up and down and can be hidden by swipe features.

Implementing the Bottom Sheet

Step 1: Adding the Dependency

To start using Bottom Sheet we have to add the dependency (We have also include Jake Wharton-Butterknife library for view binding but it is optional.)

dependencies {

   implementation fileTree(include: ['*.jar'], dir: 'libs')

   implementation "com.android.support:appcompat-v7:26.0.1"
   implementation "com.android.support:design:26.0.1"
   implementation "com.jakewharton:butterknife:8.8.1"

   annotationProcessor "com.jakewharton:butterknife-compiler:8.8.1"

Step 2: Creating Bottom Sheet layout file

In this step, we will create the layout of the Bottom Sheet, as our purpose of making Bottom Sheet is to show extra information regarding the instrument so we will include ImageView and TextView inside the layout that will be used to show the content later.

Some attributes in the layout worth noting are:

  • app:layout_behavior: This attribute makes the layout act as Bottom Sheet.
  • app:behavior_peekHeight: This is the height of the Bottom Sheet when it is minimized.
  • app:behavior_hideable: Defines if the Bottom Sheet can be hidden by swiping it down.

Here, we will also create one extra LinearLayout having height equal to the peek_height. This  LinearLayout will be at the top of the BottomSheet as shown in Figure 1 and it will be visible when the BottomSheet is in a minimized state(not hidden). Here we will put text view with like “Show guide” and an arrow pointing upwards so that it is easier for the user to understand that sheet can be viewed by sliding up.

Figure 1 LinearLayout containing textview and imageview

Here is the gist[2] that contains code for the layout of the Bottom Sheet guide

After this step, we can see a layout of Bottom Sheet in our Android Editor as shown in Figure 2

Figure 2 shows the layout of the Bottom Sheet

Step 3: Creating the Container view layout containing content and Bottom Sheet

For container view, we will create new layout under Res Layout and name it “container_view_wavegenerator.xml”

In this layout, we will use ‘Coordinator Layout’ as ViewGroup because persistent Bottom Sheet is implemented using BottomSheetBehavior class which can only be applied to the child of ‘CoordinatorLayout’.

Then add the main layout of our instrument and the layout of the Bottom Sheet inside this layout as its child.

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent">

   <include layout="@layout/activity_wave_generator" />

   <include layout="@layout/bottom_sheet_custom" />

Step 4: Setting Up Bottom Sheet and Handling callbacks

Now we will head over to the “WaveGenerator.java” file(or any instrument java file)Here we will handle set up Bottom Sheet and handle callbacks by using following classes:

BottomSheetBehavior provides callbacks and makes the Bottom Sheet work with CoordinatorLayout.

BottomSheetBehavior.BottomSheetCallback() provides the callback when the Bottom Sheet changes its state. It has two methods that need to be overridden:

  1. public void onSlide(@NonNull View bottomSheet, float slideOffset)

    This method is called when the Bottom Sheet slides up and down on the screen. It has slideOffset as a parameter whose value varies from -1.0 to 0.0 when the Bottom Sheet comes from the hidden state to collapsed and 0.0 to 1.0 when it goes from collapsed state to expanded state.

  2. public void onStateChanged(@NonNull View bottomSheet, int newState)

    This method is called when BottomSheet changed its state. Here, let us also understand the different states which can be attained by the Bottom Sheet:

    • BottomSheetBehavior.STATE_EXPANDED : When the Bottom Sheet is fully expanded showing all the content.
    • BottomSheetBehavior.STATE_HIDDEN : When the Bottom Sheet is hidden at the bottom of the layout.
    • BottomSheetBehavior.STATE_COLLAPSED : When the Bottom Sheet is in a collapsed state that is only the peek_height view part of the layout is visible.
    • BottomSheetBehavior.STATE_DRAGGING : When the Bottom Sheet is dragging.
    • BottomSheetBehavior.STATE_SETTLING : When the Bottom Sheet is settling either at expanded height or at collapsed height.

We will implement these methods in our instrument class, and also put the content that needs to be put inside the Bottom Sheet.

@BindView(R.id.bottom_sheet)
LinearLayout bottomsheet;
@BindView(R.id.guide_title)
TextView bottomSheetGuideTitle;
@BindView(R.id.custom_dialog_schematic)
ImageView bottomSheetSchematic;
@BindView(R.id.custom_dialog_desc)
TextView bottomSheetDesc;

BottomSheetBehavior bottomSheetBehavior;

@Override
protected void onCreate(Bundle savedInstanceState) { 
              
           //main instrument implementation code

           setUpBottomSheet()
}

private void setUpBottomSheet() {

   bottomSheetBehavior = BottomSheetBehavior.from(bottomsheet);

    bottomSheetGuideTitle.setText(R.string.wave_generator);
   bottomSheetSchematic.setImageResource(R.drawable.sin_wave_guide);
   bottomSheetDesc.setText(R.string.wave_gen_guide_desc);

  bottomSheetBehavior.setBottomSheetCallback(new 
  BottomSheetBehavior.BottomSheetCallback() {
       @Override
       public void onStateChanged(@NonNull View bottomSheet, int newState) {
           if (newState == BottomSheetBehavior.STATE_EXPANDED) {
               bottomSheetSlideText.setText(R.string.hide_guide_text);
           } else {
               bottomSheetSlideText.setText(R.string.show_guide_text);
           }
       }

       @Override
       public void onSlide(@NonNull View bottomSheet, float slideOffset) {
           Log.w("SlideOffset", String.valueOf(slideOffset));
        }
      });
}

After following all the above steps the Bottom Sheet will start working properly in the Instrument layout as shown in Figure 3

Figure 3 shows the Bottom Sheet in two different states

To read more about implementing Bottom Sheet in layout refer this: AndroidHive article- working with bottomsheet

Resources

  1. Developer Documentation – BottomSheetBehaviour
  2. Gist containing xml file for layout of Custom Bottomsheet

Continue Reading

Creating Control Panel For Wave Generator using Constraint Layout

 

In the blog Creating the onScreen Monitor Using CardView I had created the monitors to view the wave properties in this blog we will create the UI of controlling panel that will be used for that monitors with multiple buttons for both analog and digital waveforms.

Which layout to choose?

In today’s world, there are millions of Android devices present with different screen sizes and densities and the major concern of an Android developer is to make the layout that fits all the devices and this task is really difficult to handle with a linear or relative layout with fixed dimensions.

To create a complex layout with lots of views inside the parent using linear layout we have to make use of the attribute layout_weight for their proper stretching and positioning, but such a complex layout require a lot of nesting of weights and  android tries to avoid it by giving a warning :

Nested Weights are bad for performance

This is because layout_weight attribute requires a widget to be measured twice[1]. When a LinearLayout with non-zero weights is nested inside another LinearLayout with non-zero weights, then the number of measurements increases exponentially.

So, to overcome this issue we will make use of special type of layout “Constraint Layout” which was introduced in Google I/O 2016.

Features of Constraint Layout:-

  • It is similar to Relative Layout as all views are laid out according to their relationship with the sibling, but it is more flexible than Relative Layout.
  • It helps to flatten the view hierarchy for complex layouts.
  • This layout is created with the help of powerful tool provided by Android which has a palette on the left-hand side from where we can drag and drop the different widgets like TextView, ImageView, Buttons etc. and on the right-hand side it provides options for positioning, setting margins and other styling option like setting color, change text style etc.
  • It automatically adjusts the layout according to the screen size and hence doesn’t require the use of layout_weight attribute.

In following steps, I will create the controlling panel for Wave generator which is a complex layout with lots of buttons with the help of constraint layout.

Step 1: Add the dependency of the Constraint Layout in the Project

To use Constraint layout add the following to your build.gradle file and sync the project

dependencies {
    implementation "com.android.support.constraint:constraint-layout:1.1.0"
}

Step 2: Applying Guidelines to the layout

Guidelines[3] are anchors that won’t be displayed in your app, they are like one line of a grid above your layout and can be used to attach or constraint your widgets to it. They are only visible on your blueprint or preview editor. These will help to position and constraint the UI components on the screen easily.

For adding guidelines :

As shown in Figure 1 Right-click anywhere on the layout -> Select helpers -> Select horizontal or vertical guideline according to your need.

Figure 1 shows the horizontal guideline being added to the layout.

And for positioning the guideline we have to set the value of attribute layout_constraintGuide_percent  

Let’s say we want the guideline to be at the middle of the screen so we’ll set :

app:layout_constraintGuide_percent=”0.50″

For my layout I have added three guideline :

  • One horizontal guideline at 50%
  • Two vertical guidelines at 30% and 65%

Doing this will bifurcate the screen into six square blocks as shown in below figure :

Figure 2 shows the blueprint of constraint layout containing two vertical and one horizontal guidelines with their percentage offset from respective bases

Step 3: Adding the buttons in the blocks

Until now we have created six squares blocks, now we have to put a button view in each of the boxes.

  • First drag and drop button view from the Palette (shown in Figure 3) on the left side inside the box.

    Figure 3 shows the layout editor palette

     

  • Then we have to set constraints of this button by clicking on the small circle present on the middle of edges and dragging it onto the side of the block facing it.

    Figure 4 shows the button widget getting constrained to sides

     

  • Set the layout_width and layout_height attribute of the button to be “0dp”, doing this the button will expand in all the direction occupying all the space with respect to the border it has been constrained with.

    Figure 6 shows the button widget expanding to all the available space in the box

Similarly, adding buttons in all the square blocks and providing proper theme color we will have a blueprint and layout as shown in Figure 6.

Figure 6 shows the waveform panel blueprint and actual layout for analog waves with six buttons

Following the same steps until now, I have created the other controlling panel layout having buttons for digital waves as shown in Figure 7

Figure 7 shows other constraint layout for digital waves having seven buttons

Detailing and combining the panels to form Complete UI

After adding both the panels we have created in this layout inside the Wave Generator we have the layout as shown in Figure 8

Figure 8 shows the UI of Wave Generator as shown by a actual Android device in the PSLab app.

As we can see on adding the panels the button created inside the layout shrink so as to adapt to the screen and giving out a beautiful button-like appearance.

Resources   

  1. Blog on Nested Weights are bad for performance
  2. Developer Article – Build a Responsive UI with ConstraintLayout
  3. Information about Guidelines

Continue Reading

Implementing Leak Canary in PSLab Android App

This post discusses the issue of memory leaks and how to handle them efficiently and what are the tools available which help developers in managing the memory leaks. After working on PR #824 opened under PSLab – Android repository I have got a greater idea about how to manage the memory efficiently and what are the tools that should be used to ease the work.

What are memory leaks and how it affects the quality of app?

In simple words, memory leaks happen when you hold on to an item for long after its purpose have been served. It is as simple as that. But let us dive in further to understand more about this topic. Programming languages like C and C++ need memory management done by user whereas in higher level languages like Java, Python, etc. low-level memory management and garbage collection is done automatically by the system. But it is due to programming faults that memory leaks happen and so care needs to be taken with higher level languages too in handling memory efficiently.

In Android or say in any OS (operating system), every item has to be destroyed or say deleted or freed from the memory after its purpose is served. But if the reference of this object is passed on to any other object which has a greater time of importance than this, then it will try to hold this object for long and so the garbage collector won’t be able to collect it and so there will be memory leaks in the code. This is how memory leaks occurs inside an app.

Now, the issue of memory leaks is utmost important among developers as due to it, the app becomes slow, laggy, eats up a lot of memory and the app crashes after some time of use which creates a very bad user experience. As the user keeps on using the app, the heap memory also keeps on increasing and due to memory leaks, this heap can’t be freed by the garbage collector. Thus, all these issues contribute to making the threads or processes running inside the app slower and it can result in a lag of time from microseconds to milliseconds too!!

How can you detect these memory leaks?

This blog is mostly for Android developers and so I will use the environment of Android Studio for reference. For controlling memory leaks, Android Studio has a very powerful tool named Monitors. There are individual monitors not only for memory usage but for CPU, GPU, and network usage as well. An example of it is shown in figure 1 below.

Figure 1. Monitor in Android Studio

Now how to observe the graphs that are produced by Monitors to see if there are any memory leaks? The first alarming case is when the memory usage graph constantly increases and doesn’t come down as time passes and even not decreases when you put the app in the background. The tools which are used to undo memory leaks as soon as they are found are:

  1. Allocation Tracker: The allocation tracker comes with an indicator to show the percentage of memory allocated to different types of objects in your app. The developer can have a clear idea about which object is taking what amount of memory and which objects are exceeding the memory limit. But it is itself not enough as the developer needs other tools to dump the extra memory.
  2. Leak Canary Library: It is the most used library by developers to check for memory leaks in an app. This library runs along with app and dumps memory when needed, looks for potential memory leaks  and gives a notification for a memory leak with a clean trace to find the root of the leak with sub-roots attached to it as shown in figure 2 :

Figure 2. Screenshot from Leaks application made by Leak Canary for PSLab app

It is clearly visible from the image that the applications show the root of the memory leak with an indication of how much memory is leaked in the toolbar.

Explanation of leak shown in figure 2 :

In the PSLab app, there is a navigation drawer consisting of all main functionalities in it. It is as shown in figure 3 :

Figure 3. Navigation drawer in PSLab

The memory leak as shown in figure 2 originated in the following steps :

  • It started with ArrayList which is here the list of items as shown in figure 3.
  • After it comes to the ScrollContainer which helps in scrolling this list on small screens.
  • Then comes the Drawer Layout which is the actual layout seen in figure 3 that slides over the main layout which is here the Instruments layout.
  • At last, comes the InputMethodManager which is introduced by Leak Canary library which watches the activity that is being opened.
  • Here, InputMethodManager kept watching on Drawer Layout but after closing the layout too it referenced it which is due to the source code of LeakCanary Library and so memory Leak occurred.

How to stop this leak from occurring ?

A simple way is to add a transparent activity as soon as the layout is closed for a very small time i.e. 500 ms so that the reference watcher gets shifted from the actual layout. This solution is based on the article published on Medium [5].

How to implement Leak Canary in your app?

Below is the step-by-step guide on implementing Leak Canary library in your app to implement a watcher for memory leaks :

    • Add dependencies (App Level) in your project to implement Leak Canary
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.5.4'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
      1. debugImplementation – For debug flavor of app
      2. releaseImplementation – For release flavor of app
      3. testImplementation – For testing the current flavor of the app

Add dependencies according to the need for the application.

Add Realm dependencies (Project Level) in your app to create a database which can be used by Leak Canary to maintain and provide crash reports as shown in the figure above.

NOTE: Any database can be used here according to the need of the app

buildscript {
            repositories {
                     jcenter()
                         }
            dependencies {
                classpath "io.realm:realm-gradle-plugin:0.88.2"
           }
       }
 apply plugin: 'realm-android'

App-level dependency :

compile 'io.realm:android-adapters:2.0.0'
  • Add an activity class in your application to construct the Leak Canary for your entire application. In PSLab Android application, it was made as under :
package org.fossasia.pslab;

import android.app.Application;

import com.squareup.leakcanary.LeakCanary;
import com.squareup.leakcanary.RefWatcher;

import io.realm.Realm;

public class PSLabApplication extends Application {

	public RefWatcher refWatcher;

	@Override
	public void onCreate() {
    	super.onCreate();
    	Realm.init(this);

    	initializeLeakCanary();
	}

	private void initializeLeakCanary() {
    	if (LeakCanary.isInAnalyzerProcess(this)) {
        	return;
    	}
    	refWatcher = LeakCanary.install(this);
	}
}

Explanation of the above-implemented code :

  1. First import all the necessary libraries
  2. Realm.init(this) is used to initiate the database as soon as the layout of the Leak Canary is ready to work so that before any crashes, the database is ready to accept the entry
  3. initializeLeakCanary() method first checks if the analyzer is in the process i.e. if the Leak Canary is already initiated so that there’s no need to again initiate it else a reference watcher is initiated with variable refWatcher which looks out for any potential memory leaks

After this, you can provide a watcher with an object to watch by writing :

refWatcher.watch(object);

Now your app is ready to handle any case of memory leaks and thus the developer can find the root of the issue if any and can solve it with ease. The app will now work 94% more efficiently than what it used to be with memory leaks. Thus, a greater user experience can be provided now but in the backend!!

Resources

  1. How to use Leak Canary – Article on Stack Overflow
  2. Everything you need to know about memory leaks – Article on medium.com
  3. Leak Canary: Detect all memory leaks -Another great article on medium.com
  4. https://github.com/square/leakcanary – Actual GitHub repo of Leak Canary library
  5. https://medium.com/@amitshekhar/android-memory-leaks-inputmethodmanager-solved-a6f2fe1d1348 – Medium article on how to solve InputMethodManager related leaks

 

Continue Reading
Close Menu