#activityclasses
Explore tagged Tumblr posts
Text
AAET Classes
ADMISSION OPEN JOIN HURRY!
9999478454
www.aaetclasses.in
#kidsclasses #englishgrammar #drawingsketch #aaetclasses
#programmingcourses #education #aaet #art #activity #activityclasses #kids #dancing #aaetclasses
0 notes
Photo
All around are beautiful sights, flowers, birds, sweets and kites, Basant Panchami truly delights! Happy Basant Panchami!
#purpleturtle#preschool#onlineclasses#admissionopen#ActivityClasses#purpleturtlenft#happybasantpanchami
0 notes
Link
0 notes
Text
Tutorial How To Create Custom Android Code Templates
Mobile App Development: Tutorial How To Create Custom Android Code Templates
(No Ratings Yet) Loading...
Introduction
This tutorial will show you how to create custom Android code templates of your own. Most Android developers would have used Android code templates at least once to start projects. But have you tried creating your own Android code templates? In this tutorial, we will show you how to create a template that can be used to generate a Android project from Android Studio IDE that contains Google Analytics configuration. (Google Analytics v4 for Android)
Tung Dao Xuan, [email protected], is the author of this article and he contributes to RobustTechHouse Blog
Video & Source Code
Source Code
You can download the source code at GoogleAnalyticApplication-2015-05-31.
Step by Step Video
[vc_video title=”Video Tutorial How To Create Custom Android Code Template” link=”https://www.youtube.com/watch?v=rhsBrBcgMkQ”]
High Level View of Code Generation Process
If you are not familiar with the code generation process, please also check out the documentation of the full process here.
Steps To Create Custom Android Code Templates For Google Analytics
To build your own template, please ensure that:
You understand the code generation process described above at a high level.
You have some knowledge about FreeMarker
You have some knowledge about Android IDE Template Format and you can see the documentation here.
Step 1: Create Google Analytic Application Folder
This is for the template directory you need. On Windows, place it in: path-to-your-installation-android-studio-folder\plugins\android\lib\templates\activities. Please change your path appropriately on Linux, Mac OS etc.
Then, create the root folder and other files inside your GoogleAnalyticApplication folder.
Step 2: Create template.xml file
Each template directory must contain a template.xml file. This XML file contains the metadata about the template, including the name, description, category and user-visible parameters that the IDE will present as options to the user. The XML file also indicates the name of the recipe XML file which gets processed by FreeMarker, and the global variables XML file if there are global variables besides the template parameter values that should be visible to all FreeMarker-processed files (.ftl files).
<?xml version="1.0"?> <template format="3" revision="4" name="Google Analytics Application" minApi="7" minBuildApi="14" description="Creates a new application that has already Google Analytics configuration."> <category value="Activity" /> <formfactor value="Mobile" /> <parameter id="activityClass" name="Activity Name" type="string" constraints="class|unique|nonempty" suggest="${layoutToActivity(layoutName)}" default="MainActivity" help="The name of the activity class to create" /> <parameter id="layoutName" name="Layout Name" type="string" constraints="layout|unique|nonempty" suggest="${activityToLayout(activityClass)}" default="activity_main" help="The name of the layout to create for the activity" /> <parameter id="classApplication" name="Class extends Application" type="string" constraints="nonempty|class" help="The name of class that extends from Application" /> <parameter constraints="nonempty|string" id="googleAnalyticID" name="Google Analytic ID" type="string" help="Id of Google Analytic" /> <parameter id="dispatchPeriod" name="Dispatch Period" help="Frequency of automatic dispatch in seconds. Defaults to 30 minutes (1800 seconds)." type="string" default="1800"/> <parameter id="autoActivityTracking" name="Auto Activity Tracking" help="If true, views (Activities) will be tracked automatically. false by default." type="boolean" default="false"/> <!-- 128x128 thumbnails relative to template.xml --> <thumbs> <!-- default thumbnail is required --> <thumb>template_google_analytics.png</thumb> </thumbs> <globals file="globals.xml.ftl" /> <execute file="recipe.xml.ftl" /> </template>
There are parameters: activityClass, layoutName, classApplication, googleAnalyticID, dispatchPeriod, autoActivityTracking which will be shown in popups when you create a project.
Step 3: Create globals.xml.ftl file
The optional globals XML file contains global variable definitions, for use in all FreeMarker processing jobs for this template.
<?xml version="1.0"?> <globals> <global id="manifestOut" value="${manifestDir}" /> <global id="srcOut" value="${srcDir}/${slashedPackageName(packageName)}" /> <global id="resOut" value="${resDir}" /> </globals>
Step 4: Create folder & files inside root folder
The root folder contains template source code & template resource to generate.
4a. Create AndroidManifest.xml.ftl
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="${packageName}"> <application android:name="${packageName}.${classApplication}" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> <meta-data android:name="com.google.android.gms.analytics.globalConfigResource" android:resource="@xml/analytics_global_config" /> <activity android:name=".activities.MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
There are parameters: packageName & classApplication that are declared in template.xml file above.
4b. Create Application.java.ftl
package ${packageName}; import android.app.Application; import com.google.android.gms.analytics.GoogleAnalytics; import com.google.android.gms.analytics.Tracker; /** * Created by TungDX on 5/29/2015. */ public class ${classApplication} extends Application { private static GoogleAnalytics analytics; private static Tracker tracker; @Override public void onCreate() { analytics = GoogleAnalytics.getInstance(this); tracker = analytics.newTracker("${googleAnalyticID}"); } public static GoogleAnalytics getGoogleAnalytics() { return analytics; } public static Tracker getTracker() { return tracker; } }
There are parameters: packageName & googleAnalyticID which are parameters declared in template.xml file above.
4c. Create MainActivity.java.ftl
package ${packageName}.activities; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import ${packageName}.${classApplication}; import ${packageName}.R; public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override protected void onStart() { super.onStart(); ${classApplication}.getGoogleAnalytics().reportActivityStart(this); } @Override protected void onStop() { super.onStop(); ${classApplication}.getGoogleAnalytics().reportActivityStop(this); } }
There are parameters: packageName & classApplication which are parameters declared in template.xml file above.
4d. Create activity_main.xml.ftl
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin"> <TextView android:text="@string/ready" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
4e. Create strings.xml.ftl
<resources> <#if !isNewProject> <string name="title_${activityToLayout(activityClass)}">${escapeXmlString(activityTitle)}</string> </#if> <string name="ready">Google Analytic is ready!</string> </resources>
4f. Create dimens.xml
<resources> <!-- Default screen margins, per the Android Design guidelines. --> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> </resources>
4g. Create recipe.xml.ftl file
The recipe XML file contains the individual instructions that should be executed when generating code from this template. For example, you can copy certain files or directories (the copy instruction), optionally run the source files through FreeMarker (the instantiate instruction), and ask the IDE to open a file after the code has been generated (the open instruction).
<?xml version="1.0"?> <recipe> <dependency mavenUrl="com.android.support:support-v4:${targetApi}.+" /> <dependency mavenUrl="com.android.support:appcompat-v7:${targetApi}.+"/> <dependency mavenUrl="com.google.android.gms:play-services:6+" /> <instantiate from="AndroidManifest.xml.ftl" to="${escapeXmlAttribute(manifestOut)}/AndroidManifest.xml" /> <instantiate from="src/app_package/Application.java.ftl" to="${escapeXmlAttribute(srcOut)}/${classApplication}.java"/> <instantiate from="src/app_package/activities/MainActivity.java.ftl" to="${escapeXmlAttribute(srcOut)}/activities/${activityClass}.java"/> <instantiate from="res/xml/analytics_global_config.xml.ftl" to="${escapeXmlAttribute(resOut)}/xml/analytics_global_config.xml"/> <instantiate from="res/layout/activity_main.xml.ftl" to="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml"/> <copy from="res/values/dimens.xml" to="${escapeXmlAttribute(resOut)}/values/dimens.xml"/> <merge from="res/values/strings.xml.ftl" to="${escapeXmlAttribute(resOut)}/values/strings.xml" /> <open file="${escapeXmlAttribute(srcOut)}/activities/${activityClass}.java" /> <open file="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" /> </recipe>
4h. Check Dependencies
4i. Check AndroidManifest.xml.ftl
<instantiate from="AndroidManifest.xml.ftl" to="${escapeXmlAttribute(manifestOut)}/AndroidManifest.xml" />
4j. Check Application.java.ftl
<instantiate from="src/app_package/Application.java.ftl" to="${escapeXmlAttribute(srcOut)}/${classApplication}.java"/>https://robusttechhouse.com/wp-admin/post.php?post=6937&action=edit&message=10#
4k. Check MainActivity.java.ftl
<instantiate from="src/app_package/activities/MainActivity.java.ftl" to="${escapeXmlAttribute(srcOut)}/activities/${activityClass}.java"/>
4l. Check analytics_global_config.xml.ftl
<instantiate from="res/xml/analytics_global_config.xml.ftl" to="${escapeXmlAttribute(resOut)}/xml/analytics_global_config.xml"/>
4m. Generate files: activity_main.xml, dimens.xml, strings.xml from template to project.
<instantiate from="res/layout/activity_main.xml.ftl" to="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml"/> <copy from="res/values/dimens.xml" to="${escapeXmlAttribute(resOut)}/values/dimens.xml"/> <merge from="res/values/strings.xml.ftl" to="${escapeXmlAttribute(resOut)}/values/strings.xml" />
4n. Open files after the project is generated.
<open file="${escapeXmlAttribute(srcOut)}/activities/${activityClass}.java" /> <open file="${escapeXmlAttribute(resOut)}/layout/${layoutName}.xml" />
Try Generating A Project For Your Own Template
If your Android Studio IDE is running, please restart it to see your own template as shown in following image.
If you encounter this error when you are generating a project from the template:
AssertionError: Wrong line separators: ‘…plication;\r\n\r\nimport…’ at offset 29:
Please check your line separators in all your files in the template. Please ensure that you use the correct line separators for your computer’s OS. Eg Window uses LF, Linux or MAC OS use CRLF.
Conclusion
And that’s it. It isn’t that difficult to create custom Android code templates and you will benefit from it in the long-term because you would adhere to the DRY (Don’t Repeat Yourself) principle and save yourself some time. Have fun coding!
RobustTechHouse is a leading tech company focusing on mobile app development, ECommerce, Mobile-Commerce and Financial Technology (FinTech) in Singapore. If you are interested to engage RobustTechHouse on your projects in Singapore, you can contact us here.
References
Video showing the steps
Source code can be downloaded at GoogleAnalyticApplication-2015-05-31
Custom Android Code Templates Slides
GoogleSource Templates
ADT Template Format Documentation by Roman Nurik
Tutorial How To Create Custom Android Code Templates was originally published on RobustTechHouse - Mobile App Development Singapore
0 notes
Text
Juggling Daggers: Changing Things Up In Tests
Dependency injection is a great tool to break up your dependency creation into reusable pieces. This helps separate your code into logical chunks where some create the dependencies and others consume them. This separation helps in your unit tests because you have a clear list of dependencies for each object so you can easily pass in mock versions.
In this post I will examine the use of dependency injection in integration tests with Espresso. Some components, such as a network or database layer, need to be swapped out with fake versions for faster tests that are sealed off from the outside. A good dependency injection setup can provide a path for you to change the components you provide in your test environment. The sample project (linked at the end of this post) uses Dagger 2.15 along with the Dagger-Android libraries to simplify the setup.
Production Setup
This post will start with the main Dagger setup code before moving over to the test setup. The configuration is fairly standard, so not much time will be spent covering how it works in detail.
First, a Module is created to provide the dependencies the app needs. In this case, the module provides a NerdStore that tracks a list of nerds. The function at the top of the module is the main provider function. The second one at the bottom is an implementation detail that just provides the dependencies the nerd store needs. Implementing modules in this way provides a nice separation of concerns and ensures that if you want to replace your modules in test you only need to provide a single dependency per module since none of the other dependencies are used elsewhere in the project.
@Module class AppModule { @Provides @Singleton fun provideNerdStore(nerds: List<Nerd>): NerdStore { return LiveNerdStore(nerds) } // Implementation-detail provides functions below @Provides fun provideNerds(): List<Nerd> { return listOf( Nerd("Brian"), Nerd("Kristin"), Nerd("Chris") ) } }
Next, another Module is created to specify the classes that need the dependencies. Leaning on the @ContributesAndroidInjector annotation here simplifies this file so separate subcomponents do not need to be created for each Activity or added to a DispatchingAndroidInjector.
@Module abstract class InjectorModule { @ContributesAndroidInjector abstract fun contributeNerdListActivityInjector(): NerdListActivity }
With the modules out of the way, creating a component interface to orchestrate the injection is next. The modules are listed in the @Component annotation alongside the AndroidSupportInjectionModule. For this example, a plain Builder class annotated with @Component.Builder is used so the setup is simplified.
@Singleton @Component(modules = [ AndroidSupportInjectionModule::class, InjectorModule::class, AppModule::class ]) interface AppComponent : AndroidInjector<NerdApplication> { @Component.Builder abstract class Builder : AndroidInjector.Builder<NerdApplication>() }
Last but not least, an application subclass is needed to initialize the component. For simplicity, the DaggerApplication class is extended and an override of the applicationInjector function is implemented to return the generated DaggerAppComponent class. In this example, the component class could be initialized in the applicationInjector function and returned. Instead, the component is assigned to a property and initialized in onCreate. This is because the test configuration will need to reassign the injector property in the tests to control which dependencies are provided.
open class NerdApplication : DaggerApplication() { lateinit var injector: AndroidInjector<out DaggerApplication> override fun onCreate() { injector = DaggerAppComponent.builder().create(this) super.onCreate() } override fun applicationInjector(): AndroidInjector<out DaggerApplication> { return injector } }
With the NerdApplication class in place (and after registering it in the AndroidManifest.xml), the setup is complete and the classes can request their dependencies. In the listing below, the NerdListActivity class extends DaggerAppCompatActivity which automatically injects any properties annotated with @Inject. In this case, the NerdStore property is annotated so the component will create and inject an instance of it into the property.
class NerdListActivity : DaggerAppCompatActivity() { @Inject lateinit var nerdStore: NerdStore override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_nerd_list) for(nerd in nerdStore.nerds) { Log.d("NerdListActivity", "Have nerd $nerd") } } }
Test Setup
With the production code in place, the testing harness can be set up. There is a fake version of the LiveNerdStore that should be provided in the test classes, meaning a module needs to be created to provide it as well as a test component to serve the module.
class OtherNerdStore(override val nerds: List<Nerd>) : NerdStore
The production modules and component do not need to be overridden, as long as the test component provides all the dependencies the app needs. In this case, a test-specific module is created that returns the OtherNerdStore class in place of the LiveNerdStore. Since the provide function only specifies that a NerdStore is needed, this swap satisfies the application.
@Module class FakeAppModule { @Provides fun provideNerdStore(): NerdStore { return OtherNerdStore(listOf()) } }
After that, a test component is created to use in the test classes. The InjectionModule can be reused since there are no additional injections needed. If there were, another TestInjectionModule could be added that would list all of the test classes that need dependencies injected.
@Component(modules = [ AndroidSupportInjectionModule::class, InjectorModule::class, FakeAppModule::class // Module that returns OtherNerdStore ]) interface TestComponent : AndroidInjector<NerdApplication> { @Component.Builder abstract class Builder : AndroidInjector.Builder<NerdApplication>() }
Once the component is in place, the NerdApplication needs to be updated so the new component can be set on it and used for the injection. Since this should only be accessible from the test directory, this can be achieved by creating an extension function for NerdApplication in the test directory to set the new component and setup the injection again.
fun NerdApplication.setApplicationInjector(injector: AndroidInjector<NerdApplication>) { this.injector = injector.also { it.inject(this) } }
This extension function accepts an AndroidInjector class and sets it on the injector property on NerdApplication. At the same time, the inject() function must be called on the injector, passing in the application class as a parameter. This is necessary in order for the application to use the new injector in the future.
One last bit of prep will help clean up the test code. When an Espresso test needs to start an Activity, the ActivityTestRule is used to specify which class it should start. There is a function on the test rule class called beforeActivityLaunched() that can be overridden. This is where the production component will be swapped out for a test version before the activity launches. This ensures that the activity uses the test component instead of the production one. To centralize this, a subclass of ActivityTestRule is created that overrides the beforeActivityLaunched() function.
class InjectionActivityTestRule<T : Activity>( activityClass: Class<T>, private val componentBuilder: AndroidInjector.Builder<NerdApplication> ) : ActivityTestRule<T>(activityClass) { override fun beforeActivityLaunched() { super.beforeActivityLaunched() // setup test component before activity launches val app = InstrumentationRegistry.getTargetContext().applicationContext as NerdApplication val testComponent = componentBuilder.create(app) app.setApplicationInjector(testComponent) } }
This class takes in the activity class to start so it can pass it to the superclass constructor. It also takes in a AndroidInjector.Builder class so it knows which component to set on the application.
Then, in the beforeActivityLaunched() function, it accesses the application context from the InstrumentationRegistry and casts it directly to NerdApplication. With the application class, the test component can be fully created by calling create(app) on the builder. Finally, the injector is configured on the application class by calling setApplicationInjector() and passing in the test component as a parameter.
Having the extension function in the test directory ensures that the production code cannot call it. This safety is not extended to the test classes. It is possible for a test class to call the setApplicationInjector() function which could cause problems with the dependencies getting out of sync.
For extra security, extension function can be relocated into the InjectionActivityTestRule file and marked as private. This ensures that it is only accessible within that file so the test classes will be unable to modify the component.
class InjectionActivityTestRule<T : Activity>( activityClass: Class<T>, private val componentBuilder: AndroidInjector.Builder<NerdApplication> ) : ActivityTestRule<T>(activityClass) { override fun beforeActivityLaunched() { super.beforeActivityLaunched() // setup test component before activity launches val app = InstrumentationRegistry.getTargetContext().applicationContext as NerdApplication val testComponent = componentBuilder.create(app) app.setApplicationInjector(testComponent) } } private fun NerdApplication.setApplicationInjector(injector: AndroidInjector<NerdApplication>) { this.injector = injector.also { it.inject(this) } }
With the InjectionActivityTestRule in place, the Espresso test can be written. In this case, the test verifies that the injected property on the NerdActivity class is the fake version, OtherNerdStore, instead of the real LiveNerdStore.
@RunWith(AndroidJUnit4::class) class NerdListActivityTest { @get:Rule val activityTestRule = InjectionActivityTestRule( NerdListActivity::class.java, DaggerTestComponent.builder() ) @Test fun itInjectsTheCorrectNerdStoreImplementation() { val activity = activityTestRule.activity val nerdStore = activity.nerdStore assertThat(nerdStore, instanceOf(OtherNerdStore::class.java)) } }
Running this results in a passed test and a confirmation that the test component is being used to provide the dependencies instead of the production version.
Even though this setup is somewhat complex, I’m a fan because it gives you a higher level of control over the tests. Each test class can specify its own test component to provide the app dependencies. Some test classes are fine with a higher level of faked dependencies than others so you have more say in your test setup.
The component is also recreated before each test because the activity is recreated on each test run. This may slow down the execution time but it can have huge benefits by ensuring your tests run in an isolated fashion. All dependencies are created fresh when the component is recreated so even your singletons will not bleed state. You may still run into issues if your singletons point to the same files when saving data, but that can be remedied by providing unique file names to write to in each test or replacing your data caching with a fake, in-memory version.
I hope you have enjoyed my post on setting up dependency injection in tests. You can find a working example of the code from this post in my Github Repo. If you have any questions or comments, I would love to hear from you. Feel free to leave a comment below or you can reach out to me on Twitter @BrianGardnerAtl. Thanks for reading!
Juggling Daggers: Changing Things Up In Tests published first on https://johnellrod.weebly.com/
0 notes
Photo
Join Purple Turtle Bright Kids.
Live online classes. Fun and engaging activities. Kits will be securely delivered to your home. Qualified teachers.
Learn ✅ Public speaking ✅ Singing ✅ Dancing ✅ Arts & Craftand much more!
Make your child an all-rounder!
Book a FREE Demo now! https://bit.ly/3qZroAW
Connect with us!
Call us: +91 7411782102
Email us: [email protected]
#purpleturtle#preschool#onlineclasses#admissionopen#activityclasses#purpleturtlebrightkids#kidsluxurybrand#gradedreaders#childrenbooks#smartspeaktalkingbooks
0 notes
Photo
Get all benefits in just one program.
Enrol your child today at Bright Kids for Kids Ages 3+ Make your child qualified for more! Admission to a brighter start of the Year 2022 is now open. Book a FREE Demo now! https://bit.ly/3qZroAW Connect with us!
Call us: +91 7411782102
Email us: [email protected]
#purpleturtle#preschool#onlineclasses#admissionopen#activityclasses#purpleturtlebrightkids#kidsluxurybrand#talkingbooks#gradedreaders#childrenbooks
0 notes
Photo
The right time to start encouraging your child to speak confidently in English is now! Why wait?
Join Purple Turtle Bright Kids Online English Classes.
Book a FREE Demo now! https://bit.ly/3qZroAW
Connect with us!Call us: +91 7411782102
Email us: [email protected]
#purpleturtle#preschool#onlineclasses#admissionopen#activityclasses#purpleturtlebrightkids#kidsluxurybrand#talkingbooks#gradedreaders#childrenbooks
0 notes
Photo
Are you celebrating your child’s creativity?
Join Purple Turtle Bright Kids to make it easy. As the world celebrates International Creativity Month in January each year, we help you bring out your child’s creative genius with online classes.
Book a FREE Demo now! https://bit.ly/3qZroAW Connect with us!
Call us: +91 7411782102
Email us: [email protected]
0 notes
Photo
National Day of the Girls Child reminds us that it is our responsibility to give them the importance they deserve and work together for their happier lives.
#NationalGirlsChildDay
Connect with us!
Call us: +91 7411782102
Email us: [email protected]
0 notes
Photo
It's essential to be a good role model to our children
Connect with us!
Call us: +91 7411782102
Email us: [email protected]
0 notes
Photo
Learn singing, dancing, public speaking, phonics, early science, maths & much more! Schedule your
FREE demo classes now! https://bit.ly/3qZroAW
Connect with us!
Call us: +91 7411782102
Email us: [email protected]
0 notes
Photo
Why wait for school to open and close again interrupting your child’s education?
Visit https://purpleturtle.com/ Book your FREE demo now https://bit.ly/3qZroAW Connect with us!
Call us: +91 7411782102
Email us: [email protected]
0 notes
Photo
What are some games your child enjoys?
Connect with us!
Call us: +91 7411782102
Email us: [email protected]
0 notes
Photo
Let us salute the Indian Army for their untiring bravery and patriotism. Connect with us!
Call us: +91 7411782102
Email us: [email protected]
Book a Free Demo: https://bit.ly/3qZroAW
0 notes
Photo
Wishing you a happy & delightful Makar Sankranti!
Connect with us!
Call us: +91 7411782102
Email us: [email protected]
Book a Free Demo: https://bit.ly/3qZroAW
#HappyMakarSankranti#preschool#purpleturtle#onlineclasses#admissionopen#activityclasses#purpleturtlebrightkids
0 notes