-
关于 Handler 的灵魂三问
转载请注明出处:https://juejin.im/post/5c9896ca6fb9a070f30b0e18
…
-
自定义一个水波球状控件
转载请注明出处:https://juejin.im/post/5a8e773751882524713df4e3
…
-
基于MVP,集成了RxJava+Retrofit+TabLayout+ButterKnife的天气类App的实现
转载请注明出处:https://juejin.im/post/5ad986656fb9a07a9a106726
…
-
反编译,改应用名,再打包、签名。原来是这样
转载请注明出处:https://juejin.im/post/5ab8ab8e6fb9a028ce7b9741
…
-
Amigo 学习(二)类和资源是怎么热更的?
转载请注明出处:https://www.jianshu.com/p/813e36b321f8
…
-
Amigo学习(一)解决使用中遇到的问题
写在开头
…
-
2017总结:觉悟与起点
在这一年算是重新审视了自己,知道了自己该怎么走,走向哪里。所以这一年也是一个新的起点。从这一年开始希望自己变成自己希望的那样。 …
-
Android 热修复框架原理学习、对比及应用
写在开头
…
-
如何搭建个人网站
写在开头
…
-
Android代码模拟生成服务器返回JSON格式数据
####S: 在服务器端开发同学还没有写好接口的时候,或服务器端开发同学给出的接口不能让你满意的时候,你就可以通过以下两种方式来自己实现接口。 ####T: 这里列举了两种实现方式,分别是Google的Gson解析工具包和Alibaba的FastJson解析工具包。 ####A:
- 方式一: Google的gson.jar中的com.google.gson.Gson.toJson(Object src) 在gson的api中,提供了两个重要的方法:toJson()和fromJson()方法。其中,toJson()方法用来实现将Java对象转换为相应的JSON数据,fromJson()方法则用来实现将JSON数据转换为相应的Java对象。
public String getJsonStr() { List<Person> list = new ArrayList<Person>(); Person mPerson1 = new Person(01, "tom", 22);//id,name,age Person mPerson2 = new Person(02, "rose", 24); Person mPerson3 = new Person(03, "jack", 26); list.add(mPerson1); list.add(mPerson2); list.add(mPerson3); Gson mGson = new Gson(); String jsonStr = mGson.toJson(list); return jsonStr; }
- 方式二:
Alibaba的fastjson.jar中的com.alibaba.fastjson.JSON.toJSONString(Objectobject)
Fastjson是一个Java语言编写的高性能功能完善的JSON库。fastjson采用独创的算法,将parse的速度提升到极致,超过所有json库,包括曾经号称最快的jackson。并且还超越了google的二进制协议protocol buf。Fastjson完全支持http://json.org的标准,也是官方网站收录的参考实现之一。支持各种JDK类型。包括基本类型、JavaBean、Collection、Map、Enum、泛型等。支持JDK 5、JDK 6、Android、阿里云手机等环境。
####R: 这里偷个懒,就不图了,使用Log打印一下jsonStr就可以看到json格式的数据了。。
Map<String, Object> maps = new HashMap<String, Object>(); List<Map<String, Object>> arrayList = new ArrayList<Map<String, Object>>(); Map<String ,Object> params1 = new HashMap<String, Object>(); Map<String ,Object> params2 = new HashMap<String, Object>(); params1.put("id", 01); params1.put("name", "tom"); params1.put("url", "http://www.baidu.com"); params2.put("id", 02); params2.put("name", "jack"); params2.put("url", "http://www.google.com"); arrayList.add(params1); arrayList.add(params2); maps.put("desc", "json"); maps.put("age", "29"); maps.put("users", arrayList); String jsonStr = JSON.toJSONString(maps);
-
使用EditText遇到的问题及解决方案
####S: 在开发中,产品给的要求是,在填写地址的输入框内只能有两行内容,输入框在横屏的Dialog上,软键盘半屏显示且点击软键盘的右下角按钮实现actionDone功能。 ####T: 上面的场景可能有点复杂,先一个个问题来解决。
- dialog横屏下,软键盘半屏显示。
- 软键盘右下角按钮为完成,即点击关闭软键盘,而不是换行。
- 只显示两行内容。
- dialog横屏下,软键盘半屏显示。 imeOptions=”flagNoExtractUi” 设置前
设置后
- 软键盘右下角按钮为完成,即点击关闭软键盘,而不是换行。 imeOptions=”actionDone|flagNoExtractUi” inputType=”text”
- 只显示两行内容。
xml中
java中
android:inputType=”text|textCapSentences”
mEditText.setHorizontallyScrolling(false); mEditText.setMaxLines(2);
如有不理解或是写的不对的地方,欢迎留言指出。 如果能帮你解决困难,是我的荣幸!同时也作备忘。 感谢! …android:maxLines=“1” android:inputType="text"
-
S-T-A-R-法则
- STAR法则是情境(situation)、任务(task)、行动(action)、结果(result)四项的缩写。STAR法则是一种常常被面试官使用的工具,用来收集面试者与工作相关的具体信息和能力。
-
Android开发中用Fiddler抓包,更改后台接口数据
1.什么是Fiddler
- Fiddler是一个使用 C# 编写的 http 抓包工具。它使用灵活,功能强大,支持众多的 http 调试任务,是 web、移动应用的开发调试利器。
- 同 Httpwatch、Firebug 这些抓包工具一样,Fiddler 够记录客户端和服务器之间的所有 http 请求,可以针对特定的 http 请求,分析请求数据、设置断点等。
- 但 Fiddler 更为强大的是,它还可以修改请求的数据,甚至可以实现请求自动重定向,从而修改服务器返回的数据。
- Fiddler 使用也十分方便。在打开 Fiddler 的时候,它就自动设置好了浏览器的代理,通过改写 http 代理,让数据从它那通过,来监控并且截取到数据。当关闭 Fiddler 的时候,它又自动帮你把代理还原。
- 下载地址:https://www.telerik.com/download/fiddler
2.走进Fiddler
- 前面介绍了Fiddler是web、移动应用的开发调试利器。所以,打开Fiddler请求网页,左边的接口列表区域就会显示你所请求的每个接口。
- 点击左侧列表中的某个请求,在右侧的Inspectors功能菜单下就可以看到该接口非常详细的请求、返回数据。
- 如果只想要看到自己app请求的接口信息,则可以使用Fiters进行过滤。 Zone:指定只显示内网(Intranet)或互联网(Internet)的内容 Host:指定显示某个域名下的会话 这里以jianshu.com为例。
- 如果想修改服务器返回的接口数据,则可以使用AutoResponder功能。
3.改变接口返回的数据*
- AutoResponder 允许你拦截指定规则的请求,并返回本地资源或 Fiddler 资源,从而代替服务器响应。通常我们在开发App项目的初期,如果出现App端前期工作已经做完了,但服务器端接口联调通过但数据不够完善。这时我们就可以通过Fiddler来修改服务器返回的接口数据了。当然Fiddler还有很多用处,比如某个App在某种情况下限制你进入,那么可以尝试用Fiddler修改接口数据。
- 配置
这里默认端口号是8888,重启Fiddler。然后要求手机和电脑连接到同一网络,Windows系统可以通过cmd-ipconfig查看到ip地址。假设电脑的IP是192.168.1.1,将手机中wifi设置为如下图所示
接着打开手机浏览器请求http://192.168.1.1:8888,在打开的页面中点击“FiddlerRoot certificate”。
然后在AutoResponder 项中勾选以下两个。第一个复选框的作用是开启或禁用自动重定向功能。 第二个复选框的作用是不理会那些没满足我们处理条件的请求。
配置完成,现在开始对接口的数据进行修改替换。从左边选择一个你想要修改返回数据的接口,点击Add Rule就会自动显示在右边区域,直接按住左边不放拖过来也行。
- 接着添加一个你希望返回的json数据文件,用于替换掉服务器接口返回的数据。用Notepad++创建一个uesrinfo.txt文件作为接口返回数据。
点击Find a file,选中userinfo.txt。到此,大功告成!
- 最后,打开App,请求接口,看下Android Studio中返回的数据是否发生了改变。
欢迎加入Android交流群155495090 感谢! 文中部分内容来自:http://www.hangge.com/blog/cache/detail_1697.html …
-
GreenDAO使用及升级
GreenDAO 3.2.0: 1、在工程的build.gradle中做如下配置:
2、在app的build.gradle中做如下配置buildscript { dependencies { classpath 'org.greenrobot:greendao-gradle-plugin:3.0.0' } }
3、创建Model类,然后,Build - Make Module ‘app’apply plugin: 'org.greenrobot.greendao' android { greendao{ schemaVersion 1 // 当前数据库版本号,升级数据库则+1。 daoPackage 'com.example.greendao.gen' // 生成数据库文件的具体包 targetGenDir 'src/main/java' // 生成数据库文件的目录 } } dependencies { compile 'org.greenrobot:greendao:3.2.0' // GreenDao在github上的依赖地址 }
4、GreenDAO的使用 ok,上面的是准备工作,接下来才是使用,即得到数据库对象进行增、删、改、查。然后根据自己的代码习惯,做封装。具体实现这里不做叙述,如果有问题欢迎留言。 推荐一篇介绍得很详细的文章,链接地址。 5、GreenDAO升级 这个也是我写这篇文章的原因,在完成上面的1-4步后,数据库增删改查都没有问题,愉快地commit and push,愉快地拿着工资吃着火锅唱着歌。 直到某一天,你在你的Model类即userinfo中加入“test”字段,你很愉快地加上了字段,在build中使greendao - schemaVersion +1,并运行……@Entity(nameInDb = "userinfo") public class UserInfo implements Serializable { @Id(autoincrement = true) private Long _id; @Property(nameInDb = "username") private String username; @Property(nameInDb = "age") private int age; ...... }
由于你加了新的字段,表发生了变化,做数据库操作时抛出异常,找不到test字段。那么应该以怎么样的姿势新增字段和升级数据库呢? 然后各种查资料搜索,找到了以下代码,完美解决数据库升级问题。其原理也是创建临时数据库来做数据迁移。
然后只需要继承DaoMaster.OpenHelper重写onUpgrade方法import android.database.Cursor; import android.text.TextUtils; import android.util.Log; import org.greenrobot.greendao.AbstractDao; import org.greenrobot.greendao.database.Database; import org.greenrobot.greendao.internal.DaoConfig; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class MigrationHelper { private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS"; private static MigrationHelper instance; public static MigrationHelper getInstance() { if (instance == null) { instance = new MigrationHelper(); } return instance; } public void migrate(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) { generateTempTables(db, daoClasses); DaoMaster.dropAllTables(db, true); DaoMaster.createAllTables(db, false); restoreData(db, daoClasses); } /** * 生成临时列表 * @param db * @param daoClasses */ private void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) { for (int i = 0; i < daoClasses.length; i++) { DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]); String divider = ""; String tableName = daoConfig.tablename; String tempTableName = daoConfig.tablename.concat("_TEMP"); ArrayList<String> properties = new ArrayList<>(); StringBuilder createTableStringBuilder = new StringBuilder(); createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" ("); for (int j = 0; j < daoConfig.properties.length; j++) { String columnName = daoConfig.properties[j].columnName; if (getColumns(db, tableName).contains(columnName)) { properties.add(columnName); String type = null; try { type = getTypeByClass(daoConfig.properties[j].type); } catch (Exception exception) { exception.printStackTrace(); } createTableStringBuilder.append(divider).append(columnName).append(" ").append(type); if (daoConfig.properties[j].primaryKey) { createTableStringBuilder.append(" PRIMARY KEY"); } divider = ","; } } createTableStringBuilder.append(");"); db.execSQL(createTableStringBuilder.toString()); StringBuilder insertTableStringBuilder = new StringBuilder(); insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" ("); insertTableStringBuilder.append(TextUtils.join(",", properties)); insertTableStringBuilder.append(") SELECT "); insertTableStringBuilder.append(TextUtils.join(",", properties)); insertTableStringBuilder.append(" FROM ").append(tableName).append(";"); db.execSQL(insertTableStringBuilder.toString()); } } /** * 存储新的数据库表 以及数据 * @param db * @param daoClasses */ private void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) { for (int i = 0; i < daoClasses.length; i++) { DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]); String tableName = daoConfig.tablename; String tempTableName = daoConfig.tablename.concat("_TEMP"); ArrayList<String> properties = new ArrayList(); for (int j = 0; j < daoConfig.properties.length; j++) { String columnName = daoConfig.properties[j].columnName; if (getColumns(db, tempTableName).contains(columnName)) { properties.add(columnName); } } StringBuilder insertTableStringBuilder = new StringBuilder(); insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" ("); insertTableStringBuilder.append(TextUtils.join(",", properties)); insertTableStringBuilder.append(") SELECT "); insertTableStringBuilder.append(TextUtils.join(",", properties)); insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";"); StringBuilder dropTableStringBuilder = new StringBuilder(); dropTableStringBuilder.append("DROP TABLE ").append(tempTableName); db.execSQL(insertTableStringBuilder.toString()); db.execSQL(dropTableStringBuilder.toString()); } } private String getTypeByClass(Class<?> type) throws Exception { if (type.equals(String.class)) { return "TEXT"; } if (type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class)) { return "INTEGER"; } if (type.equals(Boolean.class)) { return "BOOLEAN"; } Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString())); exception.printStackTrace(); throw exception; } private List<String> getColumns(Database db, String tableName) { List<String> columns = new ArrayList<>(); Cursor cursor = null; try { cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null); if (cursor != null) { columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames())); } } catch (Exception e) { Log.v(tableName, e.getMessage(), e); e.printStackTrace(); } finally { if (cursor != null) cursor.close(); } return columns; } }
最后在初始化DaoMaster处调用。 …public class SQLiteOpenHelper extends DaoMaster.OpenHelper { public SQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) { super(context, name, factory); } @Override public void onUpgrade(Database db, int oldVersion, int newVersion) { MigrationHelper.getInstance().migrate(db, UserInfoDao.class); } }