{"id":19260649,"url":"https://github.com/evant/holdr","last_synced_at":"2026-03-06T01:01:36.111Z","repository":{"id":19094584,"uuid":"22322639","full_name":"evant/holdr","owner":"evant","description":"[Deprecated] Because typing findViewById() in Android is such a pain.","archived":false,"fork":false,"pushed_at":"2020-06-14T22:58:16.000Z","size":1983,"stargazers_count":207,"open_issues_count":10,"forks_count":10,"subscribers_count":14,"default_branch":"main","last_synced_at":"2025-04-21T16:42:47.361Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/evant.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-07-27T21:24:18.000Z","updated_at":"2024-10-04T16:15:09.000Z","dependencies_parsed_at":"2022-08-05T02:15:30.987Z","dependency_job_id":null,"html_url":"https://github.com/evant/holdr","commit_stats":null,"previous_names":["evant/socket"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/evant/holdr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fholdr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fholdr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fholdr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fholdr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evant","download_url":"https://codeload.github.com/evant/holdr/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evant%2Fholdr/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30156844,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-05T22:39:40.138Z","status":"ssl_error","status_checked_at":"2026-03-05T22:39:24.771Z","response_time":93,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T19:22:15.714Z","updated_at":"2026-03-06T01:01:36.035Z","avatar_url":"https://github.com/evant.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"## [Deprecated]\n[View Binding](https://developer.android.com/topic/libraries/view-binding) does everything holdr does but is a first-party solution. I will still be maintaing this project and fixing any bugs, but I will not be adding any new features.\n\nHoldr\n======\n\n## What is Holdr?\n\nHoldr generates classes based on your layouts to help you interact with them in\na type-safe way. It removes the boilerplate of doing \n`TextView myTextView = findViewById(R.id.my_text_view)` all the time.\n\n## Doesn't [Butter Knife](http://jakewharton.github.io/butterknife/)/[AndroidAnnotaions](http://androidannotations.org/)/[RoboGuice](https://github.com/roboguice/roboguice) already do that?\n\nThis is a different approach to solving the same problem, the important\ndifference is your layout dictates what is generated instead of annotations on\nyour classes. This means that it's much less likely for your code and layouts to\nget out of sync.\n\nThis approach also means zero reflection (and no proguard issues) and works \nequally as well in library projects.\n\n## Usage\n\nSimply apply the gradle plugin and your done!\n\n```groovy\nbuildscript {\n    repositories {\n        mavenCentral()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:1.0.0'\n        classpath 'me.tatarka.holdr:gradle-plugin:1.5.2'\n    }\n}\n\nrepositories {\n    mavenCentral()\n}\n\napply plugin: 'com.android.application'\napply plugin: 'me.tatarka.holdr'\n```\nalternativly, you can use the new gradle 2.1+ syntax\n```groovy\nplugins {\n  id \"me.tatarka.holdr\" version \"1.5.2\"\n}\n```\n\nSay you have a layout file `hand.xml`.\n\n```xml\n\u003c!-- hand.xml --\u003e\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\n\u003cLinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\" \n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\u003e\n\n    \u003cTextView\n        android:id=\"@+id/text\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        tools:text=\"Hello, Holdr!\"/\u003e\n\u003c/LinearLayout\u003e\n```\n\nHoldr will create a class for you named `your.application.id.holdr.Holdr_Hand`.\nThis class is basically a view holder that you can instantiate anywhere you have\na view.\n\n### In an Activity\n\n```java\npublic class MyActivity extends Activity {\n    private Holdr_Hand holdr;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.hand);\n        holdr = new Holdr_Hand(findViewById(android.R.id.content));\n        holdr.text.setText(\"Hello, Holdr!\");\n    }\n}\n```\n\n### In a Fragment\n\n```java\npublic class MyFragment extends Fragment {\n    private Holdr_Hand holdr;\n    \n    @Override\n    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.hand, container, false);\n    }\n    \n    @Override\n    public void onViewCreated(View view, Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        holdr = new Holdr_Hand(view);\n        holdr.text.setText(\"Hello, Holdr!\");\n    }\n    \n    @Override\n    public void onDestroyView() {\n        super.onDestroyView();\n        holdr = null;\n    }\n}\n```\n\n### In an Adapter\n\n```java\npublic class MyAdapter extends BaseAdapter {\n    // other methods\n    \n    @Override\n    public View getView(int position, View convertView, ViewGroup parent) {\n        Holdr_Hand holdr;\n        if (convertView == null) {\n            holdr = new Holdr_Hand(inflater.inflate(R.layout.hand, parent, false));\n            holdr.getView().setTag(holdr);\n        } else {\n            holdr = (Holdr_Hand) convertView.getTag();\n        }\n        holdr.text.setText(getItem(position));\n        return holdr.getView();\n    }\n}\n```\n\n### In a Custom View\n\n```java\npublic class MyCustomView extends LinearLayout {\n    Holdr_Hand holdr;\n    \n    // other methods\n    \n    private void init() {\n        holdr = new Holdr_Hand(inflate(getContext(), R.layout.hand, this));\n        holdr.text.setText(\"Hello, Holdr!\");\n    }\n}\n```\n\n### Multiple layouts\n\nYou may have multiple instances of a layout (in `layout` and `layout-land` for\nexample). In that case Holdr will merge the id's across them. If an id appears\nin one and not the other, a `@Nullable` annotation will be generated to warn you\nof this.\n\nIf the type of the view doesn't match, Holdr will take the most\nconservative route and use type `View`. If instead, they share a common\nsuperclass and you want to use that, you can use the `app:holdr_class` to\noverride the view type so that they match.\n\n```xml\n\u003c!-- layout/hand.xml --\u003e\n\u003cTextView\n    android:id=\"@+id/text\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    tools:text=\"Hello, Holdr!\"/\u003e\n\n\u003c!-- layout-land/hand.xml --\u003e\n\u003ccom.example.MyCustomTextView\n    android:id=\"@+id/text\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    tools:text=\"Hello, Holdr!\"\n    app:holdr_class=\"TextView\"/\u003e\n```\n\n### Callback Listeners\n\nYou can also specify listeners for your Activity/Fragment/Whatever to handle\nto make working with callbacks a bit nicer. For example, if you had the layout\nfile `hand.xml`,\n\n  ```xml\n\u003c!-- hand.xml --\u003e\n\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\n\u003cLinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\" \n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\u003e\n\n    \u003cButton\n        android:id=\"@+id/my_button\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"Hello, Holdr!\"\n        app:holdr_onClick=\"true\"/\u003e\n\u003c/LinearLayout\u003e\n  ```\n\nThe generated `Holdr_Hand` class will also have a listener interface for you to\nimplement.\n\n  ```java\npublic class MyActivity extends Activity implements Holdr_Hand.Listener {\n    private Holdr_Hand holdr;\n    \n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.hand);\n        holdr = new Holdr_Hand(findViewById(android.R.id.content));\n        holdr.setListener(this);\n    }\n    \n    @Override\n    public void onMyButtonClick(Button myButton) {\n        // Handle button click.\n    }\n}\n```\n\nHere is a list of all the listeners you can handle:\n- `holdr_onTouch`\n- `holdr_onClick`\n- `holdr_onLongClick`\n- `holdr_onFocusChange`\n- `holdr_onCheckedChanged`\n- `holdr_onEditorAction`\n- `holdr_onItemClick`\n- `holdr_onItemLongClick`\n\nYou can also specify a custom method name by doing\n`app:holdr_onClick=\"myCustomMethodName\"` instead. You can also specify the same\nname on multiple views and they will share a listener (provided the listeners\nare of the same type).\n\n### Custom Superclass\n\nWant to use a `Holdr` in a place where you need a specific subclass?\n(`RecyclerView.ViewHolder` for example).  Just use the attribute\n`app:holdr_superclass=\"com.example.MySuperclass` and it will subclass that\ninstead of `Holdr`. The only requirement is that the superclass must contain a\nconstructor that takes a `View`.\n\n### Controlling What's Generated\n\nIf you don't like the idea of a whole bunch of code being generated for all your\nlayouts (It's really not much, I promise!), you can add `holdr.defaultInclude\nfalse` to your `build.gradle` and then you can manually opt-in for each of your\nlayouts.\n\nThe easiest way to opt-in is to add `app:holdr_include=\"all\"` to the root\nview of that layout.\n\nBy default, every view with an id gets added to the generated class. You can use\nthe attributes `holdr_include` and `holdr_ignore` to get more granular\ncontrol. Both take either the value `\"view\"` to act on just the view it's used\non or `\"all\"` to act on that view and all it's children. For example,\n\n   ```xml\n\u003cLinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/container\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    app:holdr_ignore=\"all\"\u003e\n\n    \u003cTextView\n        android:id=\"@+id/text1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        tools:text=\"Hello, Holdr!\"\n        app:holdr_include=\"view\"/\u003e\n    `   \n    \u003cTextView\n        android:id=\"@+id/text2\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        tools:text=\"Hello, Holdr!\"/\u003e\n\u003c/LinearLayout\u003e\n   ```\n\nwould include only `text1` in the generated class.\n\nNote: The current implementation only allows you to nest these attributes 2\nlevels deep (ignore inside include inside ignore won't work). I don't think\nthere is a use case complex enough to warrant this, but it may be fixed in a\nlater version if there is a need.\n\nFinally, if you don't like the field name generated for a specific id, you can\nset it yourself by using `app:holdr_field_name=\"myBetterFieldName\"` on a view.\n\n### Android Studio Plugin\n\nTired 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!\n\nGo to `Settings -\u003e Plugins -\u003e Browse Repositories...` and search for \"Holdr\".\n\nThe 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.\n\n(Requires Android Studio `0.6.0+` or Intellij 14)\n\nIf instead you feel like living on the edge, you can build install the plugin manually.\n\n1. Clone the repo\n2. Change `studio.path` in `gradle.properties` to point to your Android Studio/Intellij instalation directory\n3. Run `./gradlew intellij-plugin:build --configure-on-demand`\n4. Go to `Settings -\u003e Plugins -\u003e Install plugin from disk...` and install the jar in `./intellij-plugin/build/libs/`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevant%2Fholdr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevant%2Fholdr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevant%2Fholdr/lists"}