A comprehensive tutorial for Android Data Binding

Overview

精通 Android Data Binding

Build Status


官方虽然已经给出了教程 - Data Binding Guide (中文版 - Data Binding(数据绑定)用户指南) ,但是实践之后发现槽点实在太多,于是就有了这个教程,针对每个知识点给出更详实的例子同时也总结了遇到的一些坑,希望对你有所帮助:)

我现在转行做纯前端开发了,写了几个月 React/Vue 之后发现,DataBinding 真是一个伟大的 MVVM 框架,它缩小了 Native 开发和前端开发之间的距离,技术会过时,理念恒久远。

准备

新建一个 Project,建议使用新版本的 Gradle 插件(至少要保证插件版本不低于 1.5.0):

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

然后修改对应模块(Module)的 build.gradle

dataBinding {
    enabled true
}

基础

工程创建完成后,我们通过一个最简单的例子来说明 Data Binding 的基本用法。

布局文件

使用 Data Binding 之后,xml 的布局文件就不再用于单纯地展示 UI 元素,还需要定义 UI 元素用到的变量。所以,它的根节点不再是一个 ViewGroup,而是变成了 layout,并且新增了一个节点 data

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
    </data>
    <!--原先的根节点(Root Element)-->
    <LinearLayout>
    ....
    </LinearLayout>
</layout>

要实现 MVVM 的 ViewModel 就需要把数据(Model)与 UI(View) 进行绑定,data 节点的作用就像一个桥梁,搭建了 View 和 Model 之间的通路。

我们先在 xml 布局文件的 data 节点中声明一个 variable,这个变量会为 UI 元素提供数据(例如 TextViewandroid:text),然后在 Java 代码中把『后台』数据与这个 variable 进行绑定。

下面我们使用 Data Binding 创建一个展示用户信息的表格。

数据对象

添加一个 POJO 类 - User,非常简单,两个属性以及他们的 getter 和 setter。

public class User {
    private final String firstName;
    private final String lastName;

    public User(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }
}

稍后,我们会新建一个 User 类型的变量,然后把它跟布局文件中声明的变量进行绑定。

定义 Variable

回到布局文件,在 data 节点中声明一个 User 类型的变量 user

<data>
	<variable name="user" type="com.liangfeizc.databindingsamples.basic.User" />
</data>

其中 type 属性就是我们在 Java 文件中定义的 User 类。

当然,data 节点也支持 import,所以上面的代码可以换一种形式来写。

<data>
    <import type="com.liangfeizc.databindingsamples.basic.User" />
    <variable name="user" type="User" />
</data>

然后我们刚才在 build.gradle 中添加的那个插件 - com.android.databinding 会根据 xml 文件的名称 Generate 一个继承自 ViewDataBinding 的类。 当然,IDE 中看不到这个文件,需要手动去 build 目录下找。

例如,这里 xml 的文件名叫 activity_basic.xml,那么生成的类就是 ActivityBasicBinding

注意

java.lang.* 包中的类会被自动导入,可以直接使用,例如要定义一个 String 类型的变量:

<variable name="firstName" type="String" />

绑定 Variable

修改 BasicActivityonCreate 方法,用 DatabindingUtil.setContentView() 来替换掉 setContentView(),然后创建一个 user 对象,通过 binding.setUser(user)variable 进行绑定。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityBasicBinding binding = DataBindingUtil.setContentView(
            this, R.layout.activity_basic);
    User user = new User("fei", "Liang");
    binding.setUser(user);
}

除了使用框架自动生成的 ActivityBasicBinding,我们也可以通过如下方式自定义类名。

<data class="com.example.CustomBinding">
</data>

注意

ActivityBasicBinding 类是自动生成的,所有的 set 方法也是根据 variable 名称生成的。例如,我们定义了两个变量。

<data>
    <variable name="firstName" type="String" />
    <variable name="lastName" type="String" />
</data>

那么就会生成对应的两个 set 方法。

setFirstName(String firstName);
setLastName(String lastName);

使用 Variable

数据与 Variable 绑定之后,xml 的 UI 元素就可以直接使用了。

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@{user.lastName}" />

至此,一个简单的数据绑定就完成了,可参考完整代码

高级用法

使用类方法

首先定义一个静态方法

public class MyStringUtils {
    public static String capitalize(final String word) {
        if (word.length() > 1) {
            return String.valueOf(word.charAt(0)).toUpperCase() + word.substring(1);
        }
        return word;
    }
}

然后在 xml 的 data 节点中导入:

<import type="com.liangfeizc.databindingsamples.utils.MyStringUtils" />

使用方法与 Java 语法一样:

<TextView
	android:layout_width="wrap_content"
	android:layout_height="wrap_content"
	android:text="@{MyStringUtils.capitalize(user.firstName)}" />

类型别名

如果我们在 data 节点了导入了两个同名的类怎么办?

<import type="com.example.home.data.User" />
<import type="com.examle.detail.data.User" />
<variable name="user" type="User" />

这样一来出现了两个 User 类,那 user 变量要用哪一个呢?不用担心,import 还有一个 alias 属性。

<import type="com.example.home.data.User" />
<import type="com.examle.detail.data.User" alias="DetailUser" />
<variable name="user" type="DetailUser" />

Null Coalescing 运算符

android:text="@{user.displayName ?? user.lastName}"

就等价于

android:text="@{user.displayName != null ? user.displayName : user.lastName}"

属性值

通过 @{} 可以直接把 Java 中定义的属性值赋值给 xml 属性。

<TextView
   android:text="@{user.lastName}"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:visibility="@{user.isAdult ? View.VISIBLE : View.GONE}"/>

使用资源数据

这个例子,官方教程有错误,可以参考Android Data Binder 的一个bug完整代码在此

<TextView
    android:padding="@{large? (int)@dimen/largePadding : (int)@dimen/smallPadding}"
    android:background="@android:color/black"
    android:textColor="@android:color/white"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/hello_world" />

Observable Binding

本来这一节的标题应该叫双向绑定,但是很遗憾,现在的 Data Binding 暂时支持单向绑定,还没有达到 Angular.js 的威力。

要实现 Observable Binding,首先得有一个 implement 了接口 android.databinding.Observable 的类,为了方便,Android 原生提供了已经封装好的一个类 - BaseObservable,并且实现了监听器的注册机制。

我们可以直接继承 BaseObservable

public class ObservableUser extends BaseObservable {
    private String firstName;
    private String lastName;

    @Bindable
    public String getFirstName() {
        return firstName;
    }

    @Bindable
    public String getLastName() {
        return lastName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
        notifyPropertyChanged(BR.firstName);
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
        notifyPropertyChanged(BR.lastName);
    }
}

BR 是编译阶段生成的一个类,功能与 R.java 类似,用 @Bindable 标记过 getter 方法会在 BR 中生成一个 entry

通过代码可以看出,当数据发生变化时还是需要手动发出通知。 通过调用 notifyPropertyChanged(BR.firstName) 可以通知系统 BR.firstName 这个 entry 的数据已经发生变化,需要更新 UI。

除此之外,还有一种更细粒度的绑定方式,可以具体到成员变量,这种方式无需继承 BaseObservable,一个简单的 POJO 就可以实现。

public class PlainUser {
    public final ObservableField<String> firstName = new ObservableField<>();
    public final ObservableField<String> lastName = new ObservableField<>();
    public final ObservableInt age = new ObservableInt();
}

系统为我们提供了所有的 primitive type 所对应的 Observable类,例如 ObservableIntObservableFloatObservableBoolean 等等,还有一个 ObservableField 对应着 reference type

剩下的数据绑定与前面介绍的方式一样,具体可参考ObservableActivity

带 ID 的 View

Data Binding 有效降低了代码的冗余性,甚至完全没有必要再去获取一个 View 实例,但是情况不是绝对的,万一我们真的就需要了呢?不用担心,只要给 View 定义一个 ID,Data Binding 就会为我们生成一个对应的 final 变量。

<TextView
    android:id="@+id/firstName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

上面代码中定义了一个 ID 为 firstName* 的 TextView,那么它对应的变量就是

public final TextView firstName;

具体代码可参考 ViewWithIDsActivity.java

ViewStubs

xml 中的 ViewStub 经过 binding 之后会转换成 ViewStubProxy, 具体代码可参考 ViewStubActivity.java

简单用代码说明一下,xml 文件与之前的代码一样,根节点改为 layout,在 LinearLayout 中添加一个 ViewStub,添加 ID

<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <LinearLayout
        ...>
        <ViewStub
            android:id="@+id/view_stub"
            android:layout="@layout/view_stub"
            ... />
    </LinearLayout>
</layout>

在 Java 代码中获取 binding 实例,为 ViewStubProy 注册 ViewStub.OnInflateListener 事件:

binding = DataBindingUtil.setContentView(this, R.layout.activity_view_stub);
binding.viewStub.setOnInflateListener(new ViewStub.OnInflateListener() {
	@Override
	public void onInflate(ViewStub stub, View inflated) {
		ViewStubBinding binding = DataBindingUtil.bind(inflated);
		User user = new User("fee", "lang");
		binding.setUser(user);
	}
});

Dynamic Variables

完整代码可以参考 dynamic

RecyclerView 为例,AdapterDataBinding 需要动态生成,因此我们可以在 onCreateViewHolder 的时候创建这个 DataBinding,然后在 onBindViewHolder 中获取这个 DataBinding

public static class BindingHolder extends RecyclerView.ViewHolder {
    private ViewDataBinding binding;

    public BindingHolder(View itemView) {
        super(itemView);
    }

    public ViewDataBinding getBinding() {
        return binding;
    }

    public void setBinding(ViewDataBinding binding) {
        this.binding = binding;
    }
}

@Override
public BindingHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    ViewDataBinding binding = DataBindingUtil.inflate(
            LayoutInflater.from(viewGroup.getContext()),
            R.layout.list_item,
            viewGroup,
            false);
    BindingHolder holder = new BindingHolder(binding.getRoot());
    holder.setBinding(binding);
    return holder;
}

@Override
public void onBindViewHolder(BindingHolder holder, int position) {
    User user = users.get(position);
    holder.getBinding().setVariable(BR.user, user);
    holder.getBinding().executePendingBindings();
}

注意此处 DataBindingUtil 的用法:

ViewDataBinding binding = DataBindingUtil.inflate(
	LayoutInflater.from(viewGroup.getContext()),
	R.layout.list_item,
	viewGroup,
	false);

还有另外一种比较简洁的方式,直接在构造 Holder 时把 View 与自动生成的 XXXBinding 进行绑定。

public class UserAdapter extends RecyclerView.Adapter<UserAdapter.UserHolder> {
    private static final int USER_COUNT = 10;

    @NonNull
    private List<User> mUsers;

    public UserAdapter() {
        mUsers = new ArrayList<>(10);
        for (int i = 0; i < USER_COUNT; i ++) {
            User user = new User(RandomNames.nextFirstName(), RandomNames.nextLastName());
            mUsers.add(user);
        }
    }

    public static class UserHolder extends RecyclerView.ViewHolder {
        private UserItemBinding mBinding;

        public UserHolder(View itemView) {
            super(itemView);
            mBinding = DataBindingUtil.bind(itemView);
        }

        public void bind(@NonNull User user) {
            mBinding.setUser(user);
        }
    }

    @Override
    public UserHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View itemView = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.user_item, viewGroup, false);
        return new UserHolder(itemView);
    }

    @Override
    public void onBindViewHolder(UserHolder holder, int position) {
        holder.bind(mUsers.get(position));
    }

    @Override
    public int getItemCount() {
        return mUsers.size();
    }
}

Attribute setters

有了 Data Binding,即使属性没有在 declare-styleable 中定义,我们也可以通过 xml 进行赋值操作。 为了演示这个功能,我自定义了一个 View - NameCard,属性资源 R.styleable.NameCard 中只定义了一个 age 属性,其中 firstNamelastName 只有对应的两个 setter 方法。

只要有 setter 方法就可以像下面代码一样赋值:

<com.liangfeizc.databindingsamples.attributesetters.UserView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="@dimen/largePadding"
    app:onClickListener="@{activity.clickListener}"
    app:firstName="@{@string/firstName}"
    app:lastName="@{@string/lastName}"
    app:age="27" />

onClickListener 也是同样道理,只不过我们是在 Activity 中定义了一个 Listener

转换器 (Converters)

非常重要

使用 Converter 一定要保证它不会影响到其他的属性,例如这个 @BindingConversion- convertColorToString 就会影响到android:visibility, 因为他们都是都符合从 int 到 int 的转换。

在 xml 中为属性赋值时,如果变量的类型与属性不一致,通过 DataBinding 可以进行转换。

例如,下面代码中如果要为属性 android:background 赋值一个 int 型的 color 变量:

<View
    android:background="@{isError.get() ? @color/red : @color/white}"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:layout_height="@{height}" />

只需要定义一个标记了 @BindingConversion 的静态方法即可(方法的定义位置可以随意):

@BindingConversion
public static ColorDrawable convertColorToDrawable(int color) {
    return new ColorDrawable(color);
}

具体代码可参考 ConversionsActivity.java

include

用法可以参考代码 IncludeActivity.java

如果在非根节点的 ViewGroup 中使用 include 会导致 crash,已经在 StackOverflow 上提了一个问题Android Data Binding makes app crash when using include tag in a non-root ViewGroup,直されたそうですけど。

Comments
  • 这个是系统自己生成的吗?

    这个是系统自己生成的吗?

    我想问一下这个是系统自己生成的吗? ContractBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_custom_binding); 因为自己写的话是这样,这个类应该是系统生成的吧?需要手动设置名称吗? ViewDataBinding viewDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_custom_binding);

    opened by rehan91 2
  • 多重 package name 的问题

    多重 package name 的问题

    您好,想请问下。 如果我的 debug BuildType 会在 Package Name 的最后加上 .debug 后缀。 或是不同 Flavor 会在 Package Name 后面加上其他的后缀,像是付费版和免费版的区别 这样子是否还能使用 DataBinding? 如果可行定义 Variable 要如何定义呢?

    type="com.liangfeizc.databindingsamples.basic.User"  
    

    像是 type 这边似乎只能写死某一 Package?

    opened by YuanLiou 2
  • onClick 如何传多个参数

    onClick 如何传多个参数

    public class MyHandlers {
        public void onClickFriend(View view) { ... }
        public void onClickEnemy(View view) { ... }
    }
    
     <TextView android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:text="@{user.lastName}"
               android:onClick="@{user.isFriend ? handlers.onClickFriend : handlers.onClickEnemy}"/>
    

    你好,在对一个View设置点击事件时,onClick 只把当前的View作为传递参数,如果要传多个参数,请问要怎么写?

    opened by pandaApe 2
  • 请说明RoboBinding的侵入性太强?

    请说明RoboBinding的侵入性太强?

    你提到“其实在此之前,已经有些第三方的框架(RoboAndroid) 可以支持 MVVM 模型,无耐由于框架的侵入性太强,导致一直没有流行起来。”。 我是RoboBinding的贡献者之一,我无意看到你的这个页面。你能解释你说的侵入性太强吗?或者说,Android Data Binding比RoboBinding侵入性低吗?你如果能说说你的看法,我很感谢。

    opened by weicheng113 2
  • 如何绑定dimension数据?

    如何绑定dimension数据?

    例如 android:layout_height="@{myView.height}"

    这样直接写时编译报错:

    Error:Execution failed for task ':app:compileDebugJavaWithJavac'. java.lang.RuntimeException: Found data binding errors. ***/ data binding error ***msg:Cannot find the setter for attribute 'android:layout_height' with parameter type float. file:../example.xml loc:29:45 - 29:63 ***\ data binding error ***

    求指点

    opened by ydcool 2
  • 自定义view的绑定

    自定义view的绑定

    您好,请问类似这种的 <com.cn.custom.TableView android:id="@+id/item1" android:layout_width="wrap_content" android:layout_height="wrap_content" /> 因为TableView的业务非常复杂,所以绑定的数据需要在tableView的layout文件中。这样的话又如何跟这个id对应起来呢

    opened by 751811032 1
  • No resource type specified (at 'text' with value '@{user.firstName}').

    No resource type specified (at 'text' with value '@{user.firstName}').

    下载并编译,发生错误: D:\me\project_others\MasteringAndroidDataBinding-master\app\src\main\res\layout\view_stub.xml Error:(14, 27) No resource type specified (at 'text' with value '@{user.firstName}'). Error:(20, 27) No resource type specified (at 'text' with value '@{user.lastName}').

    android studio : 1.5 classpath 'com.android.tools.build:gradle:1.5.0' classpath "com.android.databinding:dataBinder:1.0-rc1"

    opened by seazon 1
  • Add a Gitter chat badge to README.md

    Add a Gitter chat badge to README.md

    LyndonChin/MasteringAndroidDataBinding now has a Chat Room on Gitter

    @LyndonChin has just created a chat room. You can visit it here: https://gitter.im/LyndonChin/MasteringAndroidDataBinding.

    This pull-request adds this badge to your README.md:

    Gitter

    If my aim is a little off, please let me know.

    Happy chatting.

    PS: Click here if you would prefer not to receive automatic pull-requests from Gitter in future.

    opened by gitter-badger 0
  • 请问 DataBing 是否兼容Kotlin?

    请问 DataBing 是否兼容Kotlin?

    apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt'

    编译可以通过但是没有生成代码,是否是上面的配置造成的?

    opened by goodluckforme 1
  • 测试 AvatarView 代码时发现问题

    测试 AvatarView 代码时发现问题

    在 AvatarView.java 的 getDrawableFrom() 方法中发现执行到以下代码会出错: bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight(),Bitmap.Config.ARGB_8888); 这个代码在运行时会抛出异常: java.lang.IllegalArgumentException: width and height must be > 0

    opened by taowu750 1
  • NameCard 类和 activity_attrribute_setters.xml 文件有误

    NameCard 类和 activity_attrribute_setters.xml 文件有误

    在 activity_attribute_setters.xml 文件中,这样使用了 NameCard 类: <com.liangfeizc.databinding.view.NameCard android:layout_width="match_parent" android:layout_height="200dp" android:layout_marginEnd="@dimen/largePadding" android:layout_marginLeft="@dimen/largePadding" android:layout_marginRight="@dimen/largePadding" android:layout_marginStart="@dimen/largePadding" android:gravity="center" app:age="27" app:firstName="@{@string/firstName}" app:lastName="@{@string/lastName}"/> 经过我的测试发现,只有 app:age 属性能够使用,app:firstName 属性和 app:lastName 属性会报错。

    我将 style.xml 中的 NameCard style 改为如下形式就可以正常使用了:

    opened by taowu750 0
  • something I found

    something I found

    1. Build with Android studio 3.0, and update gradle version. This would be a good idea for building to complete.
    2. // public static ColorDrawable convertColorToDrawable(int color) {, is supported by default, so do not need it.
    3. Thank you very much, that really make me clear.
    opened by JasperMorrison 0
  • 关于事件绑定

    关于事件绑定

    opened by imyyq-star 1
Owner
Fei Liang
微信公众号「老梁写代码」
Fei Liang
Tired of manually setup test data of Kotlin data classes or POJOs? Instantiator creates Instances of any class for you so that you can focus on writing tests instead of spending time and effort to setup test data

Instantiator Tired of manually setup test data of Kotlin data classes or POJOs? Instantiator creates Instances of any class for you so that you can fo

Hannes Dorfmann 54 Dec 30, 2022
RxJava binding APIs for Android's UI widgets.

RxBinding RxJava binding APIs for Android UI widgets from the platform and support libraries. Download Platform bindings: implementation 'com.jakewhar

Jake Wharton 9.7k Jan 6, 2023
Android library that manages your app's cached data with ease.

Teller Android library that makes your apps faster. Teller facilitates the downloading, saving, and reading of the cached data of your app. Keep your

Levi Bostian 14 Apr 2, 2022
Starter-Android-Library - Starter Android Library is an Android Project with Modular Architecture.

Starter-Android-Library - Starter Android Library is an Android Project with Modular Architecture.

OpenBytes 1 Feb 18, 2022
SL4A brings scripting languages to Android by allowing you to edit and execute scripts and interactive interpreters directly on the Android device.

#Scripting Layer for Android (SL4A) SL4A brings scripting languages to Android by allowing you to edit and execute scripts and interactive interpreter

Damon Kohler 2.3k Dec 23, 2022
****. Use the native and support library variants instead - https://developer.android.com/guide/topics/ui/look-and-feel/fonts-in-xml.html. An android library that makes it easy to add custom fonts to edittexts and textviews

Add to your project Add this line to your dependencies in build.gradle compile 'in.workarounds.typography:typography:0.0.8' Using the views There are

Workarounds 43 Nov 6, 2021
ZXing ("Zebra Crossing") barcode scanning library for Java, Android

Project in Maintenance Mode Only The project is in maintenance mode, meaning, changes are driven by contributed patches. Only bug fixes and minor enha

ZXing Project 30.5k Dec 27, 2022
A gradle plugin for getting java lambda support in java 6, 7 and android

Gradle Retrolambda Plugin This plugin will automatically build your java or android project with retrolambda, giving you lambda goodness on java 6 or

Evan Tatarka 5.3k Jan 5, 2023
A Job Queue specifically written for Android to easily schedule jobs (tasks) that run in the background, improving UX and application stability.

Development in this repository is stopped. Future development continues on https://github.com/yigit/android-priority-jobqueue ========================

Path Mobile Inc Pte. Ltd. 2.4k Dec 9, 2022
An android library for displaying fps from the choreographer and percentage of time with two or more frames dropped

DEPRECATED TinyDancer is deprecated. No more development will be taking place. Check out the Google Android developer documentation for UI performance

Friendly Robot 1.9k Jan 3, 2023
Memory safer implementation of android.os.Handler

Android Weak Handler Memory safer implementation of android.os.Handler Problem Original implementation of Handler always keeps hard reference to handl

Badoo Tech 1.5k Jan 5, 2023
Android Library to help you with your runtime Permissions.

PermissionHelper Android Library to help you with your runtime Permissions. Demo Android M Watch it in action. Pre M Watch it in action. Nexus 6 (M) N

Kosh Sergani 1.2k Dec 14, 2022
Android validation library which helps developer boil down the tedious work to three easy steps.

AwesomeValidation Introduction Implement validation for Android within only 3 steps. Developers should focus on their awesome code, and let the librar

Jing Li 1.1k Dec 17, 2022
📄The reliable, generic, fast and flexible logging framework for Android

logback-android v2.0.0 Overview logback-android brings the power of logback to Android. This library provides a highly configurable logging framework

Tony Trinh 1.1k Jan 8, 2023
Android framework for node.js applications

Introduction Anode is an embryonic framework for running node.js applications on Android. There are two main parts to this: a port of node.js to the A

Paddy Byers 586 Dec 9, 2022
It makes a preview from an url, grabbing all the information such as title, relevant texts and images. This a version for Android of my web link preview https://github.com/LeonardoCardoso/Link-Preview

LeoCardz Link Preview for Android It makes a preview from an url, grabbing all the information such as title, relevant texts and images. Visual Exampl

Leonardo Cardoso 420 Nov 19, 2022
AndroidPermissions 4.2 0.0 Java Android M was added to check Permission. but Permission check processing is so dirty.

Android Permissions Checker Android M was added to check Permission. but Permission check processing is so dirty. This Project is to be simple, Checki

Steve SeongUg Jung 340 Nov 11, 2022
A plug and play ;) android library for displaying a "rate this app" dialog

Easy Rating Dialog This lib provides a simple way to display an alert dialog for rating app. Default conditions to show: User opened the app more than

Fernando Martínez 111 Dec 30, 2022
Tool for Android app development

RateMeMaybe Asks the user if (s)he wants to open the Play Store to rate your application when certain requirements are met (see below). This can and s

Nicolai Spohrer 98 Dec 30, 2022