A multi-purpose library containing view injection and threading for Android using annotations

Overview

SwissKnife Maven Central

Join the chat at https://gitter.im/Arasthel/SwissKnife

A multi-purpose Groovy library containing view injection and threading for Android using annotations. It's based on both ButterKnife and AndroidAnnotations.

With SwissKnife you can:

  • Inject views dynamically on any Object as long a you have a View to find them. No more findViewById and you don't have to extend any classes.
  • Add callback methods to several actions using @OnClick, @OnItemClick, etc.
  • Execute methods in the UI Thread or a background one using @OnUIThread and @OnBackground.
  • Make your variables persistent across state changes without messing with onSaveInstanceState.
  • Make anything Parcelable with the @Parcelable annotation - which can be used with @SaveInstance to automatize data persistance. NO MORE PARCELABLES! YAY!
  • Inject resources into your classes with @Res annotations (@StringRes, @AnontationRes, etc.).
  • Read intent extras automatically with @Extra annotation.

You can see an example here:

class MyActivity extends Activity {

  @StringRes(R.string.important_message)
  String reallyImportantMessage

  @Extra("api_key")
  String apiKey

  @SaveInstance
  public String myString;

  @OnClick(R.id.button)
  public void onButtonClicked(Button button) {
    Toast.makeText(this, "Button clicked", Toast.LENGTH_SHOT).show();
  }

  @OnBackground
  public void doSomeProcessing(URL url) {
    // Contents will be executed on background
    ...
  }

  @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // This must be called for injection of views and callbacks to take place
        SwissKnife.inject(this);

        // This must be called for saved state restoring
        SwissKnife.restoreState(this, savedInstanceState);

        // This mus be called for automatic parsing of intent extras
        SwissKnife.loadExtras(this)
    }
}

Collaborators

I'd really want to thank:

  • Mario García for his help on the new GH-Pages based documentation.
  • Dexafree for adding @SaveInstance annotation and helping with the testing.
  • Eugene Kamenev for adding DSL functionality to android-dsl branch.
  • Karol for injection on any object.
  • Andrew Reitz for keeping the build files up to date.
  • Pavel for his resource injection AST transforms.

You all make SwissKnife the great tool it is!

Documentation

If you want to learn more, you can check Swissknife's docs page.

It contains info about the install instructions, all the annotations, DSLs, configurations, etc.

You can find all the releases and their changes here: RELEASES

Using it

To use SwissKnife you must use Groovy on your Android project as the code generation is done using AST processing, which is a Groovy feature. You can learn how to do that using this plugin on the wiki pages.

Once your project App Module is configured to use Groovy you can add this library as a dependency cloning it with git clone or as a maven library on the build.gradle of your App Module:

dependencies {
    ...
    compile "com.arasthel:swissknife:1.4.0"
    ...
}

If you want SwissKnife to update automatically, you could just type:

dependencies {
    ...
    compile "com.arasthel:swissknife:+"
    ...
}

But make sure you remember to clear Gradle's cache to get the latest version.

Also, there is an IntelliJ IDEA plugin compatible with Android Studio that lets you auto-generate the annotations and compatible method declarations.

IDEA plugin

License

SwissKnife is licensed under Apache v2 License, which means that it is Open Source and free to use and modify.

Copyright 2014 Jorge Martín Espinosa (Arasthel)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Comments
  • NetworkOnMainThreadException with @OnBackground() ?

    NetworkOnMainThreadException with @OnBackground() ?

    I'm getting this error: android.os.NetworkOnMainThreadException

    When running this void:

    @OnBackground()
        public void getArchive()
        {
            try
            {
                String baseUrl = "http://xkcd.com/archive/";
                Document doc  = Jsoup.connect(baseUrl).get();
    
                List<String> comics = new ArrayList<String>();
    
                Elements metaElems = doc.select("div#middleContainer a");
                for (Element item : metaElems)
                {
                    Log.e("Item: ", item.attr("href"));
                    comics.add("http:\\/\\/imgs.xkcd.com\\/comics\\/squirrel_plan.png");
                }
    
                updateViewPager(comics);
    
            }
            catch (IOException e)
            {
    
            }
        }
    

    It shouldn't throw that error, since i'm running the network code in an background thread..

    opened by dasmikko 15
  • SwissKnife not working  in Activity (except MainActivity)

    SwissKnife not working in Activity (except MainActivity)

    I've been using SwissKnife with MainActivity, and everything is working fine.

    However, when I create a second Activity, swissknife cannot work.

    My second activity code as below (With a Button "testBtn" in layout)

    public class KFLoginActivity extends ActionBarActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_kflogin);
    
            //SwissKnife.inject(this);           //       #1   Compile Error
            SwissKnife.restoreState(this, savedInstanceState);
        }
        @OnClick(R.id.testBtn)
        def testIt(){
            Log.e("TEST","work withouit swissknife.inject")         //   #2 doesn't work
        }
    }
    

    Problem 1: If I input SwissKnife.inject(this) , Compile Error as below:

     Caused by: groovy.lang.MissingMethodException: 
    No signature of method: 
    me.android.KF.activities.Login.KFLoginActivity.injectViews() is applicable for argument types: 
    (me.android.KF.activities.Login.KFLoginActivity) values: 
    [me.android.KF.activities.Login.KFLoginActivity@4274bee0]
    

    Alright, I checked previous issues/answers, and it seems "SwissKnife.inject(this) " is not necessary? Then I comment it, and here comes another problem:

    Problem 2: @OnClick(R.id.testBtn) never works.

    P.S. I 'm a groovy player, and codes are in correct position under groovy/ folder as required. Any idea? Please help! Thanks

    opened by newjing 12
  • Question:  How to use @Parcelable in embeded Class?

    Question: How to use @Parcelable in embeded Class?

    Hi, I have two classese, A includes a list (or array/arraylist) of B, while I need to pass A as Parcelable. A and B have NO circular dependencies. I've tried many ways but failed. Seek for help. Thanks!

    @ Parcelable
    class A{
         .......
         List<B>   b           //also tried  B[] , not working
    }
    

    If I also add @ Parcelable to class B, then exception says: "ClassNotFoundException when unmarshalling: B" If I don't do that to B, got exception "unable to marshal value B "

    What's the proper way to handle this embeded situation?

    Many thanks!

    bug 
    opened by newjing 11
  • swissknife inject command crashes my wear app, also injected views are null

    swissknife inject command crashes my wear app, also injected views are null

    I have a fully functioning wear app trying to add SwissKnife too, but it barfs as soon as the inject method is called on SwissKnife. Also my injected views are null.

    code that crashes: https://gist.github.com/rvanderwerf/1dab5d2fbf4a469d700c @InjectView(value=R.id.pager) GridViewPager pager

    @InjectView(value=R.id.page_indicator)
    DotsPageIndicator dotsPageIndicator
    
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        SwissKnife.inject(this)
    
        pager = (GridViewPager) findViewById(R.id.pager)
        dotsPageIndicator = (DotsPageIndicator) findViewById(R.id.page_indicator)
        dotsPageIndicator.setPager(pager)
    

    I get this exception:

    Caused by: groovy.lang.MissingMethodException: No signature of method: com.tutosandroidfrance.wearsample.MainActivity.injectViews() is applicable for argument types: (com.tutosandroidfrance.wearsample.MainActivity) values: [com.tutosandroidfrance.wearsample.MainActivity@133ab8db] at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:58) at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:54) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) at com.arasthel.swissknife.SwissKnife.inject(SwissKnife.groovy:40) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93) at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite$StaticMetaMethodSiteNoUnwrapNoCoerce.invoke(StaticMetaMethodSite.java:151) at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.call(StaticMetaMethodSite.java:91) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) at com.tutosandroidfrance.wearsample.MainActivity.onCreate(MainActivity.groovy:45)

    If I take out the inject method call it works fine (but my injected views are still null).

    Here is the project with full source: https://github.com/rvanderwerf/WearDavinciEmmetGroovy

    opened by rvanderwerf 7
  • Created 10 new res-injecting annotations and transformator for them.

    Created 10 new res-injecting annotations and transformator for them.

    new Annotations: (String) @StringRes, (Integer,int) @IntegerRes, (Boolean,boolean) @BooleanRes, (Float,float) @DimenRes, (Integer,int) @ColorRes, (String[]) @StringArrayRes, (int[]) @IntegerArrayRes, (Drawable) @DrawableRes, (Animation) @AnimationRes, (ColorStateList) @ColorStateListRes

    Each annotation optionally applies single param(link to resource like R.sting.app_name, R.dimen.awesomeness_level), if annotation is applied without param, transformer will try to access resource by the name of variable.

    For now supported only resources from in-app package(i.e. R.), android.R. resources will not work.

    opened by MrBIMC 6
  • Errors using GAsyncTask

    Errors using GAsyncTask

    Hi,

    I have try to use the GAsyncTask but I have trouble when i use it. First I try the dsl but none of after, before or error method is know (at compile or at runtime) :

        async {
            return "my result"
        } after {
            uiThreadAction()
        }
    

    In secondary place, I tried to use the GAsyncTask directly like this :

        def task = new GAsyncTask<String>({
            return "my result"
        })
        task.before {
            log.error("before")
        }
        task.after {
            log.error("after = $it")
        }
        task.error { ex ->
            log.error("error()", ex)
        }
        task.execute()
    

    The before task is executed and the error give me that stackTrace for the doInBackground task :

    groovy.lang.MissingMethodException: No signature of method: MY_FRAGMENT$_getBackgroundNewEvent_background_closure3.doCall() is applicable for  argument types: (null, com.arasthel.swissknife.dsl.components.GAsyncTask) values: [null, com.arasthel.swissknife.dsl.components.GAsyncTask@52d5d5b8]
    Possible solutions: doCall(), doCall(java.lang.Object), findAll(), findAll()
            at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:284) ~[na:0.0]
            at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016) ~[na:0.0]
            at groovy.lang.Closure.call(Closure.java:423) ~[na:0.0]
            at com.arasthel.swissknife.dsl.components.GAsyncTask.doInBackground(GAsyncTask.groovy:56) ~[na:0.0]
            at android.os.AsyncTask$2.call(AsyncTask.java:288) ~[na:0.0]
            at java.util.concurrent.FutureTask.run(FutureTask.java:237) ~[na:0.0]
            at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) ~[na:0.0]
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) ~[na:0.0]
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) ~[na:0.0]
            at java.lang.Thread.run(Thread.java:841) ~[na:0.0]
    

    Thank you guys for this library Thomas

    bug 
    opened by tgirard12 6
  • Compile helper

    Compile helper

    I need to add the cast to Parselable everytime that I will use it... is there any way to avoid this?

    example: intent.putExtra(DrawerActivity.BUNDLE_ORDER, (Parselable) actualOrder);

    opened by danielgomezrico 6
  • Is swissknife broken on wear?

    Is swissknife broken on wear?

    I see your wear sample doesn't actually use any SwissKnife. Well I gave it a try on the wear sample, but it doesn't seem inject the view?

    Here is my gist..https://gist.github.com/rvanderwerf/9d4853fcbbb0990cefcf I just add the inject method which runs, but afterwards the textview isn't injected and is null?

    Or maybe I am doing something wrong?

    I have a working groovy app on wear, and when I try this my views aren't injected either.. but calling the SwissKnife.inject this causes the whole app to crash, even if I don't any sort of transformation. I can open a seperate one for that.

    bug 
    opened by rvanderwerf 5
  • Documentation clarification and startActivity DSL fix

    Documentation clarification and startActivity DSL fix

    • Adds a clarification for the SwissKnife.inject(this, getView()) in Fragments
    • Fixes a bug that would crash if startActivity(Class) was called with a null Closure
    opened by dexafree 5
  • Android dsl

    Android dsl

    Hi guys:

    I've been building the project using gradle in the command line, and I've noticed that some files in the project have your local configuration. I think those files shouldn't be included in order to allow any dev to build the project.

    I also found a bad dependency reference in android-dsl/build.gradle. That project is pointing at :androidapp:SwissKnife instead of just :SwissKnife . I've changed it and now dependency is resolved as expected.

    
     - compile project(':androidapp:SwissKnife')
     + compile project(':SwissKnife')
    

    Next I removed the .gradle/ dir. Unless you tell me otherwise I think it makes no sense to keep that directory.

    Last I would like to ask you something. Have you ever come across a classnotfoundexception during gradle build because it didn't find the class android/support/v4/widget/DrawerLayoutImpl

    After all changes I had an error. It has to do with the fact that when executing gradle build after removing all build/ directories. Once I had that error next time I built the project I never had that problem again.

    In case you face same error (maybe when deploying on Travis) the following command line worked for me:

    gradle generateDebugSources && gradle build

    Anyway I've raised an issue in the groovy-gradle plugin in case Cedric Champeau can give me a tip about this problem (https://github.com/melix/groovy-android-gradle-plugin/issues/31).

    I keep looking the new features, and are really great, domain classes 'ala' Grails, form handling/validation to say a few, I really like it, good work.

    opened by mariogarcia 5
  • SwissKnife.inject(Object target, View view) does not work in some conditions

    SwissKnife.inject(Object target, View view) does not work in some conditions

    I've been trying to use SwissKnife injection to implement the holder pattern on a ListView. In my project, I have several ListView. But, on one of them, the injection works, for the others, it fails with:

    groovy.lang.MissingMethodException:
        No signature of method: java.lang.Object.injectViews() is
        applicable for argument types: (android.widget.LinearLayout) values:
        [android.widget.LinearLayout{288e7075 V.E..... ......I. 0,0-0,0}]
    
    opened by ghost 4
  • Unable to apply Groovy plugin

    Unable to apply Groovy plugin

    Hello, I am trying to apply the Groovy plugin in Android Studio - like you suggested. However, I am getting this error:

    .GradleException: You must apply the Android plugin or the Android library plugin before using the groovy-android plugin

    Have you faced a similar issue?

    Thanks, Igor

    opened by IgorGanapolsky 1
  • @Inject for findFragmentById?

    @Inject for findFragmentById?

    Not sure if it's possible, but it feels like something that would be nice to deal with an @InjectSomething tag. Perhaps with supportFragmentManager vs fragmentManager distinction.

    Currently do this in my onCreate:

    frag = supportFragmentManager.findFragmentById(R.id.frag_something) as SomeFragment
    
    enhancement 
    opened by dsvensson 5
  • Feature request: inject views without declaration

    Feature request: inject views without declaration

    I am not familiar with Groovy AST transformations and it's capabilities, but would it be possible to parse the layout XML file during transformation, and then create getters (or fields) for each view found in the XML file? This would eliminate the need to add, for example @InjectView TextView myTextView, and simply be able to reference R.id.my_text_view in the activity code as myTextView.text = "..."

    For reference, this is implemented in the Xtendroid project (see https://github.com/tobykurien/Xtendroid/blob/master/Xtendroid/docs/index.md#activities-and-fragments) for activities, fragments, view holders, and custom views, eliminating a lot of boilerplate code and adding compile-time checking of view bindings and onClick handlers.

    enhancement 
    opened by tobykurien 3
Releases(v1.3.1)
  • v1.3.1(May 28, 2015)

  • v1.2.3(Apr 5, 2015)

    • Fixed @Parcelable annotation bug with List restoration.
    • Improved some DSL methods.
    • Added @Extra annotation.
    • Added DSL methods for fragments and activities - thanks @melix!
    Source code(tar.gz)
    Source code(zip)
  • v1.2.2(Jan 26, 2015)

    Changes:

    • Fixed a bug which caused an StackOverflowError on fragments when @Parcelable and @SaveInstance were used together.
    • All AST Transformations have been rewritten using GeneralUtils class. This produces better code when those transformations are applied and should be translated to better performance.
    • Updated Groovy version and Groovy plugin.
    Source code(tar.gz)
    Source code(zip)
  • v1.2.1(Jan 26, 2015)

  • v1.2.0(Jan 26, 2015)

  • v1.1.4(Jan 26, 2015)

  • v1.1.3(Jan 26, 2015)

  • v1.1.2(Jan 26, 2015)

  • v.1.1.1(Jan 26, 2015)

    Added DSL methods such as:

    view(R.id.my_view)
    

    To quickly load a view - as using findViewById(...), or:

    onClick(Closure closure)
    

    To add an OnClickListener callback to an item and execute the closure's code on click event, or:

    asListView(R.id.list_view, R.layout.list_row, Iterable<T> items, Closure toDoOnAdapter)
    

    This will create an ArrayAdapter using the provided items, inflate R.layout.list_row views, execute what's on the closure as the getView(...) code on the adapter and attach it to the ListView provided.

    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Jan 26, 2015)

  • v1.0.4(Jan 26, 2015)

  • v1.0.3(Jan 26, 2015)

  • v1.0.2(Jan 26, 2015)

  • v1.0.1(Jan 26, 2015)

Owner
Jorge Martin Espinosa
Jorge Martin Espinosa
Codegeneration tool for isomorphic server and mobile Go apps with gRPC & Protobuf. Share code between your backend, Android & iOS app! :sun_with_face:

Anakin Codegeneration tool for isomorphic server and mobile Go apps with gRPC & Protobuf. Share code between your backend, Android & iOS app! Descript

Kirill Biakov 17 Jun 25, 2020
Tons of extensively featured packages for Angular, VUE and React Projects

rxweb Clean Code. Built with Purpose Contributing to rxweb framework If you are thinking to make rxweb framework better, that's truly great. You can c

null 376 Jan 4, 2023
Kotlin code generation for commercetools platform type-safe product-types, reference expansion and custom fields

Kotlin code generation for commercetools platform type-safe product-types, reference expansion and custom fields

null 8 Dec 15, 2022
:package: Android Parcelables made easy through code generation.

Parceler Have a question? Ask it on StackOverflow. Found an issue? Please report it. In Android, Parcelables are a great way to serialize Java Objects

John Ericksen 3.6k Dec 27, 2022
Android Parcelable models made easy

AutoParcel AutoParcel is an AutoValue extension that enables Parcelable values generation. Just add implements Parcelable to your @AutoValue annotated

Francesco Sardo 1.4k Dec 23, 2022
A tool to generate Android ContentProviders.

Android ContentProvider Generator (acpg) A tool to generate Android ContentProviders. It takes a set of entity (a.k.a "table") definitions as the inpu

Benoit Lubek 623 Dec 13, 2022
A easy way to use android sharepreference

Favor A easy way of using Android SharedPreferences. How to use this library Using Gradle compile 'com.cocosw:favor:0.2.0@aar' Using Maven <depend

Kai Liao 467 Nov 10, 2022
A code generator to create Android ContentProvider

DatabaseCodeGenerator This project is a code generator written in Java used to generate Android code. Given a database schema JSON definition file, it

Foxykeep 297 Nov 25, 2022
Pure Java code generation tool for generating a fully functional ContentProvider for Android.

RoboCoP RoboCoP is a Java library that can generate a fully-functional ContentProvider from a simple JSON schema file. Get the latest version from our

Rain 246 Dec 29, 2022
Android 注解自动生成与 Flutter 通信的代码

Android-Flutter-Annotation 用于 Android 端项目,通过使用注解自动生成与 Flutter 通信的代码。 可生成的三种通信渠道有: MethodChannel EventChannel BasicMessageChannel 集成 在项目的 build.gradle

JOYY UED 4 Nov 1, 2021
A small tool to help you generate android projects that have a base code.

Volt Project A small tool to help you generate android projects that have a base code. Usage Change project in base directory. python volt-gen.py <pac

Victor Varenik 3 Feb 2, 2022
A simple Kotlin multi-platform abstraction around the javax.inject annotations.

Inject A simple Kotlin multi-platform abstraction around the javax.inject annotations. This allows using the annotations in Kotlin common code so that

Christopher 43 Aug 17, 2022
A sample Grocery Store app built using the Room, MVVM, Live Data, Rx Java, Dependency Injection (Kotlin Injection) and support Dark Mode

Apps Intro A sample Grocery Store app built using the Room, MVVM, Live Data, Rx Java, Dependency Injection (Kotlin Injection) and support Dark Mode In

Irsyad Abdillah 25 Dec 9, 2022
Library containing over 2000 material vector icons that can be easily used as Drawable or as a standalone View.

Material Icon Library A library containing over 2000 material vector icons that can be easily used as Drawable, a standalone View or inside menu resou

null 2.3k Dec 16, 2022
DrawBox: a multi-purpose tool to draw anything on canvas, written completely on jetpack compose

DrawBox DrawBox is a multi-purpose tool to draw anything on canvas, written comp

Akshay Sharma 172 Dec 30, 2022
A simple library for validating user input in forms using annotations.

ValidationKomensky for Android A simple library for validating user input in forms using annotations. Features: Validate all views at once and show fe

Inmite s.r.o. 512 Nov 20, 2022
Janishar Ali 2.1k Jan 1, 2023
Easy Response Mocking for Retrofit using annotations

Response Mocking for Retrofit using annotations. Assume Provides safe and easy way to mock API responses for retrofit-okhttp3.

Aniket Bhoite 25 Nov 16, 2021
An Android library containing a simple TableView and an advanced SortableTableView providing a lot of customisation possibilities to fit all needs.

SortableTableView for Android An Android library providing a TableView and a SortableTableView. Minimum SDK-Version: 11 | Compile SDK-Version: 25 | La

Ingo Schwarz 1.1k Dec 5, 2022
Android library that creates app shortcuts from annotations

Shortbread Android library that generates app shortcuts for activities and methods annotated with @Shortcut. No need to touch the manifest, create XML

Matthias Robbers 1.8k Dec 30, 2022