Holdr


Source link: https://github.com/evant/holdr

[Deprecated]

The Android Data Binding Library does everything holdr does and more. I will still be maintaing this project and fixing any bugs, but I will not be adding any new features.

Holdr

What is Holdr?

Holdr generates classes based on your layouts to help you interact with them in a type-safe way. It removes the boilerplate of doing TextView myTextView = findViewById(R.id.my_text_view) all the time.

Doesn't Butter Knife/ AndroidAnnotaions/ RoboGuice already do that?

This is a different approach to solving the same problem, the important difference is your layout dictates what is generated instead of annotations on your classes. This means that it's much less likely for your code and layouts to get out of sync.

This approach also means zero reflection (and no proguard issues) and works equally as well in library projects.

Usage

Simply apply the gradle plugin and your done!

buildscript {

  repositories {

mavenCentral()
  
}

  dependencies {

classpath 'com.android.tools.build:gradle:1.0.0'

classpath 'me.tatarka.holdr:gradle-plugin:1.5.2'
  
}
 
}
  repositories {

  mavenCentral() 
}
  apply plugin: 'com.android.application' apply plugin: 'me.tatarka.holdr'

alternativly, you can use the new gradle 2.1+ syntax

plugins {

id "me.tatarka.holdr" version "1.5.2" 
}

Say you have a layout file hand.xml.

<!-- hand.xml --> <?xml version="1.0" encoding="utf-8"?>  <LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:orientation="vertical"

android:layout_width="match_parent"
  android:layout_height="match_parent">

<TextView

android:id="@+id/text"

android:layout_width="match_parent"

android:layout_height="wrap_content"

tools:text="Hello, Holdr!"/> </LinearLayout>

Holdr will create a class for you named your.application.id.holdr.Holdr_Hand. This class is basically a view holder that you can instantiate anywhere you have a view.

In an Activity

public class MyActivity extends Activity {

  private Holdr_Hand holdr;

@Override
  protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.hand);

holdr = new Holdr_Hand(findViewById(android.R.id.content));

holdr.text.setText("Hello, Holdr!");

  
}
 
}

In a Fragment

public class MyFragment extends Fragment {

  private Holdr_Hand holdr;

 @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

return inflater.inflate(R.layout.hand, container, false);

  
}

 @Override
  public void onViewCreated(View view, Bundle savedInstanceState) {

super.onViewCreated(view, savedInstanceState);

holdr = new Holdr_Hand(view);

holdr.text.setText("Hello, Holdr!");

  
}

 @Override
  public void onDestroyView() {

super.onDestroyView();

holdr = null;
  
}
 
}

In an Adapter

public class MyAdapter extends BaseAdapter {

  // other methods

 @Override
  public View getView(int position, View convertView, ViewGroup parent) {

Holdr_Hand holdr;

if (convertView == null) {

 holdr = new Holdr_Hand(inflater.inflate(R.layout.hand, parent, false));

 holdr.getView().setTag(holdr);

}
 else {

 holdr = (Holdr_Hand) convertView.getTag();

}

holdr.text.setText(getItem(position));

return holdr.getView();

  
}
 
}

In a Custom View

public class MyCustomView extends LinearLayout {

  Holdr_Hand holdr;

 // other methods

 private void init() {

holdr = new Holdr_Hand(inflate(getContext(), R.layout.hand, this));

holdr.text.setText("Hello, Holdr!");

  
}
 
}

Multiple layouts

You may have multiple instances of a layout (in layout and layout-land for example). In that case Holdr will merge the id's across them. If an id appears in one and not the other, a @Nullable annotation will be generated to warn you of this.

If the type of the view doesn't match, Holdr will take the most conservative route and use type View. If instead, they share a common superclass and you want to use that, you can use the app:holdr_class to override the view type so that they match.

<!-- layout/hand.xml --> <TextView
  android:id="@+id/text"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  tools:text="Hello, Holdr!"/>  <!-- layout-land/hand.xml --> <com.example.MyCustomTextView
  android:id="@+id/text"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  tools:text="Hello, Holdr!"
  app:holdr_class="TextView"/>

Callback Listeners

You can also specify listeners for your Activity/Fragment/Whatever to handle to make working with callbacks a bit nicer. For example, if you had the layout file hand.xml,

<!-- hand.xml --> <?xml version="1.0" encoding="utf-8"?>  <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
 android:layout_width="match_parent"
android:layout_height="match_parent">
 <Button

 android:id="@+id/my_button"

 android:layout_width="match_parent"

 android:layout_height="wrap_content"

 android:text="Hello, Holdr!"

 app:holdr_onClick="true"/> </LinearLayout>

The generated Holdr_Hand class will also have a listener interface for you to implement.

public class MyActivity extends Activity implements Holdr_Hand.Listener {

private Holdr_Hand holdr;

@Override
protected void onCreate(Bundle savedInstanceState) {

 super.onCreate(savedInstanceState);

 setContentView(R.layout.hand);

 holdr = new Holdr_Hand(findViewById(android.R.id.content));

 holdr.setListener(this);

}

@Override
public void onMyButtonClick(Button myButton) {

 // Handle button click.

}
 
}

Here is a list of all the listeners you can handle:

  • holdr_onTouch
  • holdr_onClick
  • holdr_onLongClick
  • holdr_onFocusChange
  • holdr_onCheckedChanged
  • holdr_onEditorAction
  • holdr_onItemClick
  • holdr_onItemLongClick

You can also specify a custom method name by doing app:holdr_onClick="myCustomMethodName" instead. You can also specify the same name on multiple views and they will share a listener (provided the listeners are of the same type).

Custom Superclass

Want to use a Holdr in a place where you need a specific subclass? ( RecyclerView.ViewHolder for example). Just use the attribute app:holdr_superclass="com.example.MySuperclass and it will subclass that instead of Holdr. The only requirement is that the superclass must contain a constructor that takes a View.

Controlling What's Generated

If you don't like the idea of a whole bunch of code being generated for all your layouts (It's really not much, I promise!), you can add holdr.defaultInclude false to your build.gradle and then you can manually opt-in for each of your layouts.

The easiest way to opt-in is to add app:holdr_include="all" to the root view of that layout.

By default, every view with an id gets added to the generated class. You can use the attributes holdr_include and holdr_ignore to get more granular control. Both take either the value "view" to act on just the view it's used on or "all" to act on that view and all it's children. For example,

<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"  xmlns:app="http://schemas.android.com/apk/res-auto"  xmlns:tools="http://schemas.android.com/tools"  android:id="@+id/container"  android:orientation="vertical"  android:layout_width="match_parent"  android:layout_height="match_parent"  app:holdr_ignore="all">
<TextView

android:id="@+id/text1"

android:layout_width="match_parent"

android:layout_height="wrap_content"

tools:text="Hello, Holdr!"

app:holdr_include="view"/>  `
  <TextView

android:id="@+id/text2"

android:layout_width="match_parent"

android:layout_height="wrap_content"

tools:text="Hello, Holdr!"/> </LinearLayout>

would include only text1 in the generated class.

Note: The current implementation only allows you to nest these attributes 2 levels deep (ignore inside include inside ignore won't work). I don't think there is a use case complex enough to warrant this, but it may be fixed in a later version if there is a need.

Finally, if you don't like the field name generated for a specific id, you can set it yourself by using app:holdr_field_name="myBetterFieldName" on a view.

Android Studio Plugin

Tired of having to build your project after every layout change? With the intellij plugin the Holdr classes will be auto-generated as soon as you save!

Go to Settings -> Plugins -> Browse Repositories... and search for "Holdr".

The plugin will also allow you to do a refactor-rename on holdr fields and use goto-source (Ctrl-click or Ctrl-B) to go directly to the view in the layout.

(Requires Android Studio 0.6.0+ or Intellij 14)

If instead you feel like living on the edge, you can build install the plugin manually.

  1. Clone the repo
  2. Change studio.path in gradle.properties to point to your Android Studio/Intellij instalation directory
  3. Run ./gradlew intellij-plugin:build --configure-on-demand
  4. Go to Settings -> Plugins -> Install plugin from disk... and install the jar in ./intellij-plugin/build/libs/

Resources

With Carpaccio, your views became smarter, instead of calling functions on views, now your views can call functions! You no longer need to extend a view to set a custom behavior.

This Android project samples some Material Design-ish transitions for list items and floating action buttons. It uses the the shared element concept introduced in Android 5.0.

This library implements a color picker and a color preference for use in Android applications.

Batch uninstall Android apps using this very convenient script. Just supply a package name (or part of it) and the script will take care of the uninstallation.

Inspired by cwac-adapter, RecyclerAdapterWrapper allows you to add more functionalities into an existing RecyclerView.Adapter. The wrapper delegates all behaviors to the wrapped object, you just need to override the specific behaviors you need.

A major bug in Play Services could be the reason GCM messages that you send aren't reaching your users. Pacemaker helps patch this bug by doing for Play Services what it should be doing on its own.

Topics


2D Engines   3D Engines   9-Patch   Action Bars   Activities   ADB   Advertisements   Analytics   Animations   ANR   AOP   API   APK   APT   Architecture   Audio   Autocomplete   Background Processing   Backward Compatibility   Badges   Bar Codes   Benchmarking   Bitmaps   Bluetooth   Blur Effects   Bread Crumbs   BRMS   Browser Extensions   Build Systems   Bundles   Buttons   Caching   Camera   Canvas   Cards   Carousels   Changelog   Checkboxes   Cloud Storages   Color Analysis   Color Pickers   Colors   Comet/Push   Compass Sensors   Conferences   Content Providers   Continuous Integration   Crash Reports   Credit Cards   Credits   CSV   Curl/Flip   Data Binding   Data Generators   Data Structures   Database   Database Browsers   Date &   Debugging   Decompilers   Deep Links   Dependency Injections   Design   Design Patterns   Dex   Dialogs   Distributed Computing   Distribution Platforms   Download Managers   Drawables   Emoji   Emulators   EPUB   Equalizers &   Event Buses   Exception Handling   Face Recognition   Feedback &   File System   File/Directory   Fingerprint   Floating Action   Fonts   Forms   Fragments   FRP   FSM   Functional Programming   Gamepads   Games   Geocaching   Gestures   GIF   Glow Pad   Gradle Plugins   Graphics   Grid Views   Highlighting   HTML   HTTP Mocking   Icons   IDE   IDE Plugins   Image Croppers   Image Loaders   Image Pickers   Image Processing   Image Views   Instrumentation   Intents   Job Schedulers   JSON   Keyboard   Kotlin   Layouts   Library Demos   List View   List Views   Localization   Location   Lock Patterns   Logcat   Logging   Mails   Maps   Markdown   Mathematics   Maven Plugins   MBaaS   Media   Menus   Messaging   MIME   Mobile Web   Native Image   Navigation   NDK   Networking   NFC   NoSQL   Number Pickers   OAuth   Object Mocking   OCR Engines   OpenGL   ORM   Other Pickers   Parallax List   Parcelables   Particle Systems   Password Inputs   PDF   Permissions   Physics Engines   Platforms   Plugin Frameworks   Preferences   Progress Indicators   ProGuard   Properties   Protocol Buffer   Pull To   Purchases   Push/Pull   QR Codes   Quick Return   Radio Buttons   Range Bars   Ratings   Recycler Views   Resources   REST   Ripple Effects   RSS   Screenshots   Scripting   Scroll Views   SDK   Search Inputs   Security   Sensors   Services   Showcase Views   Signatures   Sliding Panels   Snackbars   SOAP   Social Networks   Spannable   Spinners   Splash Screens   SSH   Static Analysis   Status Bars   Styling   SVG   System   Tags   Task Managers   TDD &   Template Engines   Testing   Testing Tools   Text Formatting   Text Views   Text Watchers   Text-to   Toasts   Toolkits For   Tools   Tooltips   Trainings   TV   Twitter   Updaters   USB   User Stories   Utils   Validation   Video   View Adapters   View Pagers   Views   Watch Face   Wearable Data   Wearables   Weather   Web Tools   Web Views   WebRTC   WebSockets   Wheel Widgets   Wi-Fi   Widgets   Windows   Wizards   XML   XMPP   YAML   ZIP Codes