首页 文章 精选 留言 我的

精选列表

搜索[android things],共10000篇文章
优秀的个人博客,低调大师

Android 输入金额限制,各种限制~

小菜最近因工作需要做一个支付金额对话框的小模块,技术很浅显,遇到几个小坑,分享给大家~ 需求 小菜遇到的坑之一: 其他页面中获取到的金额需要保存两位小数,本来我打算直接用 String 转为 double 类型,但是遇到保存精度问题(String=19.99 ->Double=19.98),所以借鉴BigDecimal 方式,如图: String->Double精度转换 小菜遇到的坑之二: 只可保留两位小数,即有两位小数后再输入不显示;若先输入一个长度,例如1234,移动光标,再在1234之间点小数点,只可有12.34或123.4或1234.而不可是1.234 小菜遇到的坑之三: 时时判断输入金额不可大于10000,自己用了一个很low的方法: 时时判断金额 直接上关键代码吧 (依旧很low,仅供借鉴) final EditText amountEt = ButterKnife.findById(view, R.id.pay_view_amount_tv); Double amountDouble = Double.parseDouble(amount); BigDecimal bignum = new BigDecimal(amountDouble); amountEt.setText(bignum.setScale(2, BigDecimal.ROUND_HALF_UP) + ""); amountEt.setFilters(new InputFilter[]{new InputFilter() { @Override public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { String sourceText = source.toString(); String destText = dest.toString(); //验证删除等按键 if (TextUtils.isEmpty(sourceText)) { return ""; } mPattern = Pattern.compile("([0-9]|\\.)*"); Matcher matcher = mPattern.matcher(source); // 已经输入小数点的情况下,只能输入数字 if (destText.contains(".")) { if (!matcher.matches()) { return ""; } else { if (".".equals(source)) { //只能输入一个小数点 return ""; } } double sumText = Double.parseDouble(destText + sourceText); if (sumText > 10000) { return dest.subSequence(dstart, dend); } //验证小数点精度,保证小数点后只能输入2位 int index = destText.indexOf("."); int length = dend - index; if (dest.toString() != null && dest.toString().length() > 0 && dest.toString().contains(".")) { String[] amoArr = (dest.toString()).split("\\."); int indexPoint = dest.toString().indexOf("."); if (dstart <= indexPoint) { if (dend > 0) { String temp = amoArr[0].substring(0, dend - 1) + sourceText + amoArr[0].substring(dend - 1, amoArr[0].length()); if (Double.parseDouble(temp) > 10000) { return ""; } } } else if (amoArr.length > 1 && amoArr[amoArr.length - 1].length() >= 2) { return ""; } } if (length > 10) { return dest.subSequence(dstart, dend); } } else { // 还没有输入小数点.的情况 if (source.equals(".") && dest.toString().length() == 0) { return "0."; } else { if (dest.toString() != null && dest.toString().length() > 0) { double sumDou = Double.parseDouble(dest.toString()); if (sumDou > 10000) { return ""; } } String[] amoArr = (dest.toString()).split("\\."); int indexPoint = dest.toString().indexOf("."); if (dstart <= indexPoint) { if (dest.toString() != null && dest.toString().length() > 0) { double sumDou = Double.parseDouble(dest.toString()); if (sumDou > 10000) { return dest.subSequence(dstart, dend); } } } else if (amoArr.length > 1 && amoArr[amoArr.length - 1].length() >= 2) { return ""; } else if (source.equals(".") && dest.toString().length() - dstart > 2) { return ""; } } } if ((destText + sourceText).length() > 10) { return dest.subSequence(dstart, dend); } //验证输入金额的大小 double sumText = Double.parseDouble(destText + sourceText); if (sumText > 10000) { return dest.subSequence(dstart, dend); } return dest.subSequence(dstart, dend) + sourceText; } }}); // 关闭赞赏提示对话框 ImageView imgClose = ButterKnife.findById(view, R.id.pay_view_close_iv); imgClose.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { materialDialog.dismiss(); } }); // 确定赞赏 TextView tvPaySure = ButterKnife.findById(view, R.id.pay_view_sure_tv); tvPaySure.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { amount = amountEt.getText().toString().trim(); if (!StringUtils.isBlank(amount)) { if (amount.contains(",")) { amount.replaceAll("\\,", ""); String[] amoArr = amount.split("\\,"); String tempAmoStr = ""; for (String i : amoArr) { tempAmoStr = tempAmoStr + i; } amount = tempAmoStr; } double tempAmo = Double.valueOf(amount); if (tempAmo <= 0.00) { ToastUtils.showShort(mContext, "请输入一定金额"); } else if (tempAmo > 0.00 && tempAmo <= 9999.99) { materialDialog.dismiss(); if (getAccountInfo() != null) { payCommon(); } else { startActivity(new Intent(mContext, LoginActivity.class)); } } else { ToastUtils.showShort(mContext, "不要超过一万"); } } else { ToastUtils.showShort(mContext, "请输入一定金额"); } } }); // 取消赞赏 TextView tvPayCancel = ButterKnife.findById(view, R.id.pay_view_cancel_tv); tvPayCancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { materialDialog.dismiss(); } }); 效果图

优秀的个人博客,低调大师

Android自定义注解(一)

为什么要写这个,因为前段时间看了一下AOP相关的一些内容,然后也是太久没写注解,看得有点那啥不顺畅,所以想对注解做个总结。 一.JAVA自带的注解 (1)Override 覆盖 (2)Deprecated 标记过期方法 (3)SuppressWarnings 屏蔽警告 二.自定义注解 1.定义 我这里写个demo自定义一个注解 @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) public @interface BindView { int value() default -1; } 可以看出注解用@interface来标志。 2.元注解 可以看出在上边的定义中,上面还有两个注解,这些被称为元注解,什么是元注解,简单来说就是描述注解的注解还有什么元数据的,元什么什么的,这个元其实不太好解释,我记得之前看过一个元数据的描述,英文是 data about data,这个元有这个about的那种感觉 元注解有4种 (1)@Retention 用来描述周期,Retention 有“保持时间”的意思,这个属性可以选三个值SOURCE表示只在源码中有用,编译就没用了。CLASS表示在编译中可用,运行就没用了。RUNTIME表示运行时可用。 这三种的区别解释起来很麻烦,总之一搬我们都是使用RUNTIME (2)@Target 用来描述作用域,Target有目标的意思,你这个注解要给哪个目标修饰,这个属性可以选以下的值CONSTRUCTOR用于描述构造器FIELD用于描述域LOCAL_VARIABLE用于描述局部变量METHOD用于描述方法PACKAGE用于描述包PARAMETER用于描述参数 这个就是说,你允许把注解写在什么地方。这个属性是可以多选的,比如@Target({ElementType.FIELD, ElementType.METHOD}) (3)@Inherited 描述是否可以为继承,默认是false (4)@Documented 描述是否会保存到 Javadoc 文档中 一般我们只会用到前面两个,所以后面两个我就不解释了。 3.注解的值 可以给注解设置值,比如说我上面的代码,就在注解里写了个 int value() default -1; 表示在使用注解时需要传一个整形的值 @BindView(R.id.tv) TextView textView; 我这传了个R.id.tv就是一个整形的值。只有一个值的时候,必须以** value()**来命名,然后调用时就直接传就行。我还是分情况来说吧。 (1)不需要传值的情况 @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) public @interface BindView { } 调用 @BindView TextView textView; (2)传一个值的情况 就是我上面写的代码 (3)传多个值的情况 @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) public @interface BindView { int age; String name; } 调用 @BindView(age = 18, name = "JackMa") TextView textView; 最后,这个default 表示设置默认值的意思。 三.调用注解 上面我们创建出了注解并定义好,然后我们需要调用这个注解,那怎么调用呢,一般我们调用一个类或接口都是new 出来,但是这东西怎么看都觉得new不出来吧,所以我们需要用反射来获取到注解的对象,然后进行调用 我不想去讲反射的内容,不然就没完了。就说个思路,需要用到哪个方法可以去查api。 注解在Java中就是Annotation懂吧,所以在反射中和Annotation相关的方法都是和注解相关的方法。 比如说获取注解,我就可以调用.getAnnotation(BindView.class) 再比如说我判断注解存在不,可以调用isAnnotationPresent() 总之你只要记住注解是Annotation,之后你不管是在反射中还是在哪里找和注解相关的方法,都先往Annotation这个名词相关的地方找准没错。 如果你不懂反射这里说再多也没有。 四.案例 其实说了这么多,到底哪里需要使用到注解呢,如果不使用到,讲它有啥用,我个人是目前接触到AOP涉及注解比较频繁,其它时候,比如说ButterKnife,Dagger,Retrofit等等这些主流的框架都会用到注解,包括java后台,我接触过spring会涉及到IOC啊AOP啊这些思想用java来实现也是用到注解比较多,所以可以来写个小demo试试。 不如就仿照ButterKnife吧,我之前没看过ButterKnife的源码啊,我就按照我学会的注解的知识和ButterKnife的调用方法来仿写个ButterKnife 1.首先定义注解 @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD}) public @interface BindView { int value() default -1; } 定义注解,要求传个资源进来,默认是-1 2.按照ButterKnife的调用的样子来写调用的地方 public class MainActivity extends AppCompatActivity { @BindView(R.id.tv) TextView textView; @BindView(R.id.btn) Button btn; String yyy = "aasdasdas"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); textView.setText("wwwwwwwwwwwwww"); btn.setText("btn"); } } 发现ButterKnife调用的地方使用这 ButterKnife.bind(this); 那我就推测findViewById就在这个ButterKnife类的bind方法中进行。 3.定义ButterKnife public class ButterKnife { public static void bind(Activity activity){ Class<?> cls = activity.getClass(); Field[] fields = cls.getDeclaredFields(); for (Field field : fields) { BindView bindView = field.getAnnotation(BindView.class); if (bindView != null) { int ids = bindView.value(); try { field.set(activity, activity.findViewById(ids)); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } } 我这里就用了反射来操作,调用bind方法后,先用cls.getDeclaredFields();获取所有的全局变量,然后再对每个变量用field.getAnnotation(BindView.class);来获取这个变量上面的注解,如果存在的话 int ids = bindView.value(); 来获取我们传入的资源,最后调用findViewById field.set(activity, activity.findViewById(ids)); 很简单吧,三个类这样就能实现了ButterKnife的效果 image.png 注意判空一定要写,即使你全部的变量都用了注解,但是如果你DeBug看看,你会发现,变量中不仅仅只有你定义的,还存在其他的。 其实上面都是瞎写的,ButterKnife的原理根本不是这样,虽然我没看过源码,但我听别人说过ButterKnife的实现并不是这样的,我这的demo只是仿照了这个功能,具体ButterKnife的原理以后如果有时间我会单独写。 通过上面的讲解就能简单的实现注解,我也顺便复习加总结了一遍。

优秀的个人博客,低调大师

android网络框架Retrofit 同步异步

http://blog.csdn.net/jiguangcanhen/article/details/39006197 同步的方式: 1)首先定义要接口。注解Get表示使用的Get请求方式,{user}代表要被替换的数据 public interface GitHubService { @GET("/users/{user}/repos") List<Repo> listRepos(@Path("user") String user); } 2)初始化RestAdapter,并利用动态代理来创建的接口对象。 RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("https://api.github.com") .build(); GitHubService service = restAdapter.create(GitHubService.class); 3)使用网络访问并返回 List<Repo> repos = service.listRepos("octocat"); 异步的方式: @POST("/users/new") void createUser(@Body User user, Callback<User> cb); 注:body注解,在进行请求前对象会被转换器进行相应的数据转换。 前两部和之前的相同,不同在于最后一个参数变成了CallBack对象。 controller.getLogin(mail, password,newCallback<UserDataModel>() { @Override publicvoidfailure(RetrofitError error) { //TODOAuto-generated method stub } @Override publicvoidsuccess(UserDataModel ldm, Response response) { //TODOAuto-generated method stub }); 可以看到当请求网络返回之后,会在failure中和success中进行回调,而且默认的数据转换器会把相应的json字符串转换为对象。(当然,我们也可以定义自己的数据转换器) 定义自己的数据转换器: publicclassMyConverterimplementsConverter { @Override publicObject fromBody(TypedInput body, Type type)throwsConversionException { StringBuffer result =newStringBuffer(); try{ InputStream is = body.in(); byte[] buffer =newbyte[1024]; while(is.read(buffer) != -1){ result.append(newString(buffer,"UTF-8")); } }catch(IOException e) { e.printStackTrace(); } returnresult; } @Override publicTypedOutputtoBody(Objectobject) { returnnull; } } 上面的自定义数据转换器,会在请求成功之后,返回给我们字符串,而不是相应的被gson转换过格式的字符串。 RestAdapter restAdapter =newRestAdapter.Builder() .setEndpoint(“url”) .setConverter(newMyConverter()) .build(); 在创建RestAdapter之后创建设置使用自己的数据转换器就可以了。 我们还可以灵活的进行其他的配置: 1)设置请求拦截器,会在请求发出前,进行拦截。 RequestInterceptor requestInterceptor = new RequestInterceptor() { @Override public void intercept(RequestFacade request) { request.addHeader("User-Agent", "Retrofit-Sample-App"); } }; RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("https://api.github.com") .setRequestInterceptor(requestInterceptor) .build(); 2)设置错误控制器 class MyErrorHandler implements ErrorHandler { @Override public Throwable handleError(RetrofitError cause) { Response r = cause.getResponse(); if (r != null && r.getStatus() == 401) { return new UnauthorizedException(cause); } return cause; } } RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("https://api.github.com") .setErrorHandler(new MyErrorHandler()) .build(); 3)设置log日志。 RestAdapter restAdapter = new RestAdapter.Builder() .setLogLevel(RestAdapter.LogLevel.FULL) .setEndpoint("https://api.github.com") .build(); 上面只是简单介绍了它的使用,其实它还有很多的功能,Get,Post,Put,Delete,Head……具体请参见官方网址。 版权声明:本文为博主原创文章,未经博主允许不得转载。 本文转自wanqi博客园博客,原文链接:http://www.cnblogs.com/wanqieddy/p/4933606.html如需转载请自行联系原作者

优秀的个人博客,低调大师

解决android SwipeRefreshLayout recyclerview 不能下拉

http://stackoverflow.com/questions/25178329/recyclerview-and-swiperefreshlayout 23down vote write the following code inaddOnScrollListenerof theRecyclerView Like this: recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener(){ @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { int topRowVerticalPosition = (recyclerView == null || recyclerView.getChildCount() == 0) ? 0 : recyclerView.getChildAt(0).getTop(); swipeRefreshLayout.setEnabled(topRowVerticalPosition >= 0); } @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } });

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册