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
Lightweight, minimalistic dependency injection library for Kotlin & Android

‼️ This project is in maintenance mode and not actively developed anymore. For more information read this statement. ‼️ Katana Katana is a lightweight

REWE Digital GmbH 179 Nov 27, 2022
A SharedPreference "injection" library for Android

PreferenceBinder A SharedPreferences binding library for Android. Using annotation processing, this library makes it easy to load SharedPreferences va

Denley Bihari 232 Dec 30, 2022
:syringe: Transfuse - A Dependency Injection and Integration framework for Google Android

Transfuse Transfuse is a Java Dependency Injection (DI) and integration library geared specifically for the Google Android API. There are several key

John Ericksen 224 Nov 28, 2022
Guice (pronounced 'juice') is a lightweight dependency injection framework for Java 6 and above, brought to you by Google.

Guice Latest release: 5.0.1 Documentation: User Guide, 5.0.1 javadocs, Latest javadocs Continuous Integration: Mailing Lists: User Mailing List Licens

Google 11.7k Jan 1, 2023
The dependency injection Dagger basics and the concepts are demonstrated in different branches

In this project we will look at the dependency injection Dagger basics and the concepts are demonstrated in different branches What is an Dependency?

Lloyd Dcosta 6 Dec 16, 2021
Painless Kotlin Dependency Injection

KOtlin DEpendency INjection Kodein-DI is a very simple and yet very useful dependency retrieval container. it is very easy to use and configure. Kodei

null 2.9k Jan 1, 2023
Koin - a pragmatic lightweight dependency injection framework for Kotlin

What is KOIN? - https://insert-koin.io A pragmatic lightweight dependency injection framework for Kotlin developers. Koin is a DSL, a light container

insert-koin.io 7.8k Jan 8, 2023
Simple Android Library, that provides easy way to start the Activities with arguments.

Warning: Library is not maintained anymore. If you want to take care of this library, propose it via Pull Request. It needs adjustmensts for newer ver

Marcin Moskała 429 Dec 15, 2022
DependencyProperty is a dependency resolution library by Delegated Property.

DependencyProperty is a dependency resolution library by Delegated Property. Overview DependencyProperty is simple in defining and

wada811 10 Dec 31, 2022
Bind Android views and callbacks to fields and methods.

Butter Knife Attention: This tool is now deprecated. Please switch to view binding. Existing versions will continue to work, obviously, but only criti

Jake Wharton 25.7k Jan 3, 2023
Bind Android views and callbacks to fields and methods.

Butter Knife Attention: This tool is now deprecated. Please switch to view binding. Existing versions will continue to work, obviously, but only criti

Jake Wharton 25.7k Mar 22, 2021
A fast dependency injector for Android and Java.

Dagger A fast dependency injector for Java and Android. Dagger is a compile-time framework for dependency injection. It uses no reflection or runtime

Google 16.9k Jan 5, 2023
A fast dependency injector for Android and Java.

Dagger 1 A fast dependency injector for Android and Java. Deprecated – Please upgrade to Dagger 2 Square's Dagger 1.x is deprecated in favor of Google

Square 7.3k Jan 5, 2023
Easier creation of Dagger ObjectGraph scopes with Retrofit and Butterknife niceties

Scopes ###What is Scopes? Have you ever tried to set up scoped ObjectGraphs with Dagger and failed miserably? Scopes is a compile time annotation proc

null 35 Dec 30, 2019
Gradle plugin to add clock trackings to your dagger components and subcomponents

⏰ Dagger Track A gradle plugin that automatically adds clock tracking for your components and subcomponents. Features DaggerTrack will tell you follow

Amanjeet Singh 60 Aug 16, 2022
DI can be simple. Forget about modules and components. Just use it!

PopKorn - Kotlin Multiplatform DI PopKorn is a simple, powerful and lightweight Kotlin Multiplatform Dependency Injector. It doesn't need any modules

Pau Corbella 145 Dec 25, 2022
Fast Android Development. Easy maintainance.

Fast Android Development. Easy maintenance. AndroidAnnotations is an Open Source framework that speeds up Android development. It takes care of the pl

null 11.1k Dec 31, 2022
Fast Android Development. Easy maintainance.

Fast Android Development. Easy maintenance. AndroidAnnotations is an Open Source framework that speeds up Android development. It takes care of the pl

null 11.1k Dec 31, 2022
Google Guice on Android, version 3.0 [RETIRED]

As of August 2016, RoboGuice is no longer supported. For nearly 5 years it was the #1 dependency injection framework on Android due to its ease-of-use

null 3.8k Dec 26, 2022