开发中遇到的一些操蛋问题
1. view.inflate 和 LayoutInflater 区别和联系
基本没区别,
view.inflate里边调用的是Layoutinflater,但是参数又不一样的地方,
view.inflate只能选择要不要挂载到父view只上,如果挂载那么layoutparms也随时设置,如果不载,layoutparms就不设置,
Layoutinflater多一个boolean参数可以自己设置,需要不需要设置layoutparms,
除了这点区别外,都一样用,基本可以不用考虑这点区别,一百年用不到一次.
2. TabLayout中的操蛋问题
tabMode 当条目超过屏幕宽度是,是否让他可以滚动,或者直接缩小填充
tabGravity 当条目不足屏幕宽度时,是否让他居中,或者直接扩大填充
这两个是配合着使用的,但是貌似又相互独立,TMD到时候自己看着办吧........
3.ListView始终定位底部
listView.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
4.web httpurlconnection接受客户端请求消息
- 客户端代码
如果使用urlconnection的话,传递参数,需要获取输出流,放入参数
这是"post"请求,如果是"get",需要自己拼串了.
OutputStream outputStream =httpURLConnection.getOutputStream();
outputStream.write("type=download".getBytes());
outputStream.flush(); - 服务器代码
需要使用servletoutputstream 来发送数据 ,用outputstream不可以,有问题,会导致数据不完整,不知道为啥
5.文件持久化存储的坑
- 以下三个获取存储路径的方式,你可以忘得一干二净,因为你第三方应用只能读不能写,这些都系统的,看看就行了,想存自己的东西,没门儿......
Environment---> getDataDirectory() getDownloadCacheDirectory() getRootDirectory () - 想要存自己的东西,就用一下方式,对应两种,一个外置存储 一个内置存储,当app卸载是,他们也跟着卸载
Context.getExternalFilesDir() Context.getFilesDir(); 放长时间保存的数据
Context.getExternalCacheDir() Context.getCacheDir(); 放临时保存的数据
因为有一对儿,不可能都用,所以在使用的时候要判断一下外置存储是否存在,然后选择用哪一个,存在就用外置,不存在,就用内置. - 如果要保存一些下载的内容,就不要放在以上目录下,就放到SD下就好.
getExternalStorageDirectory()
这个路径是根据手机设置来改变的,如果手机默认存储位置是内置,则指向的内置,如果默认存储是外置sd,则指向外置sd
getExternalStoragePublicDirectory (String type) 这个是根据需要获取一个目录
参数有DIRECTORY_MUSIC , DIRECTORY_PODCASTS, DIRECTORY_RINGTONES, DIRECTORY_ALARMS, DIRECTORY_NOTIFICATIONS, DIRECTORY_PICTURES,
DIRECTORY_MOVIES, DIRECTORY_DOWNLOADS, DIRECTORY_DCIM
到时候根据自己需要,去查吧....
6.简单的mxl布局优化
- merge的使用
根布局,简单的FramLayout就用merge,
如果是自定义布局,根布局是Framlayout同上,如果是Linerlayout之类的,就要在自定义view中自己设定一下属性:
例如--> setOrientation(LinearLayout.HORIZONTAL);
注意事项: 在自定义布局中 使用merge ,inflate一个view时,要必须指定父布局,必须添加到父布局true
即---> inflate(int, ViewGroup, true)
不能在ViewStub中使用merge标签。最直观的一个原因就是ViewStub的inflate方法中根本没有attachToRoot的设置
作为根布局的merge,如果我们想设置自己设置背景什么的,可以这样
简要说明:因为Window窗体(比如Activity)加载时会自动添加PhoneWindow$DecorView和FrameLayout(id/content)两层布局
//setContentView(R.layout.layout_showset);
这个就不要了,我们自己去拿decorview然后拿到Framelayout,再找到我们的根布局,然后自己设置属性.
FrameLayout frameLayout = (FrameLayout)this.getWindow().getDecorView().findViewById(android.R.id.content);
frameLayout.setBackgroundResource(R.drawable.bg_repeated_main);
LayoutInflater.from(this).inflate(R.layout.layout_showset, frameLayout, true);
- ViewStub的使用
简要说明:其实就是一个轻量级的页面,我们通常使用它来做预加载处理,来改善页面加载速度和提高流畅性,ViewStub本身不会占用层级,它最终会被它指定的层级取代。
给ViewStub设置资源,可以在xml中(android:layout="@layout/ layout_main"),也可以在代码中,如下:
mViewStub = (ViewStub)findViewById(R.id.viewstub);
mViewStub.setLayoutResource(R.layout.layout_main);
- 注意事项:
--> ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,
就不能够再通过ViewStub来控制它了。所以它不适用于需要按需显示隐藏的情况。
--> ViewStub只能用来Inflate一个布局文件,而不是某个具体的View,
当然也可以把View写在某个布局文件中。如果想操作一个具体的view,还是使用visibility属性吧。
--> VIewStub中不能嵌套merge标签.
- include的使用
这个用来布局重用的,自己看着用吧,就不多说了......
提醒一点:
如果你给include设置了id,那么加入的布局里的跟布局,就不能设置了,否则会获取失败,报错崩溃.
7.Decimal 的使用
- BigDecimal
BigDecimal BigDecimal(double d); //不允许使用,精度不能保证,
---->这个构造方法 坑比较大,报各种异常,反正就是崩溃,千万别用
BigDecimal BigDecimal(String s); //常用,推荐使用
static BigDecimal valueOf(double d); //常用,推荐使用 - DecimalFormat
// 格式化:保留2为小数
DecimalFormat df = new DecimalFormat("#.##");
// 四舍五入,默认五舍六入
df.setRoundingMode(RoundingMode.HALF_UP);
例如 : new DecimalFormat( " 0.00"); 就是小数点后两位
符号 | 描述 |
---|---|
0 | 如果不存在就显示0 |
# | 如果不存在就不显示 |
. | 分割符 |
8.自定义view的大坑逼
-
系统帮我们测量的高度和宽度都是MATCH_PARNET,当我们设置明确的宽度和高度时,系统帮我们测量的结果就是我们设置的结果,当我们设置为WRAP_CONTENT,或者MATCH_PARENT系统帮我们测量的结果就是MATCH_PARENT的长度。
所以,当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法”:
重写之前先了解MeasureSpec的specMode,一共三种类型:
EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
UNSPECIFIED:表示子布局想要多大就多大,很少使用
所以当我们设置为warp_content时,尽量自己测量一下宽度,不然就是match_parent了
代码例子如下:
这是xml布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:custom="http://schemas.android.com/apk/res/com.example.customview01"
android:layout_width="match_parent"
android:layout_height="match_parent" ><com.example.customview01.view.CustomTitleView android:layout_width="wrap_content" android:layout_height="wrap_content" custom:titleText="3712" android:padding="10dp" custom:titleTextColor="#ff0000" android:layout_centerInParent="true" custom:titleTextSize="40sp" /> </RelativeLayout> 这是自定义view代码,测量宽高: @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width; int height ; if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { mPaint.setTextSize(mTitleTextSize); mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds); float textWidth = mBounds.width(); int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight()); width = desired; } if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { mPaint.setTextSize(mTitleTextSize); mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds); float textHeight = mBounds.height(); int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom()); height = desired; } setMeasuredDimension(width, height); }
-
实例化view测量的问题
先抛出我的问题:View rootView = View.inflate(this, R.layout.pop_layout, null);我实例化一个xml布局,但是我获取不到他的宽高,这个正常,以为没有设置lp,但是我设置了lp,也获取不到,这就是问题.
解决方法:
View rootView = View.inflate(this, R.layout.pop_layout, null);
// rootView.measure(0,0); 在这里重新测量就好,也可以用下边的方法测量
rootView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); 这也是测量测量完跟布局大小后,还要测量一下子view的布局, rootView.layout(0, 0, rootView.getMeasuredWidth(), rootView.getMeasuredHeight()); 我这里是要讲xml转化成一个bitmap,用了两种方式, 方式1: rootView.setDrawingCacheEnabled(true); rootView.buildDrawingCache(); Bitmap bitmap = rootView.getDrawingCache(); 方式2: int width = rootView.getMeasuredWidth(); int height = rootView.getMeasuredHeight(); Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); rootView.draw(canvas); 最后给imageview这是bitmap显示图片 image.setImageBitmap(bitmap);
9. Handler.post() 和 view.post()的区别
- Handler.post(),需要自己创建Handler,view.post()内部默认已经能够帮我们获取了当前线程(即UI线程)的handler,然后又帮我们post到handler中,这里因为不像前一种方法new了一个新的线程,所以不要做复杂的逻辑计算,容易阻塞,但是简单的想偷个懒还是可以的.
默认情况下,如果new Handler()的时候,没有传入某个线程的Looper对象(或传入null),系统就会默认绑定到创建Handler()对象的线程中。
10.service中弹toast的坑
- 首先要明确一点就是: ** 所有更新UI的操作,都必须在UI线程中进行 **
如果直接在service中弹toast,那么就会提示,handler没有初始化,或者looper不正确
所以我们要创建一个handler,同事给其设置一个looper(这个looper是主线程的looper)
代码如下:
Handler handler = new Handler(getMainLooper()); //获取UIlooper
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "wifi---->", Toast.LENGTH_SHORT).show();
}});
11. MediaRecorder中的坑比事
- 在设置录音功能时,顺需要对,也就是说,这是录音来源后,紧接着要设置录音输出的格式,再设置录音的编码格式
12. Dialog的背景风格
<style name="ModalDialog" parent="@android:style/Theme.Dialog">
<item name="android:windowFrame">@null</item> <!-- 设置窗体边框 -->
<item name="android:windowIsFloating">true</item> <!-- 窗体是否浮现在activity之上 -->
<item name="android:windowIsTranslucent">false</item> <!-- 窗体是否半透明 -->
<item name="android:windowFullscreen">true</item> <!-- 窗体是否全屏 -->
<item name="android:windowNoTitle">true</item> <!-- 窗体有无标题-->
<item name="android:background">@null</item> <!-- 背景 -->
<item name="android:windowBackground">@android:color/transparent</item> <!-- window背景 -->
<item name="android:backgroundDimEnabled">false</item> <!-- 背景是否模糊显示 -->
<item name="android:windowContentOverlay">@null</item> <!-- 窗体内容背景 -->
<item name="windowOverscan">false</item> <!-- 是否要求窗体铺满整屏幕-->
</style>
13. 通过api拿到资源id
方法1:
int id = Context.getResources().getIdentifier("activity_main","layout",paramContext.getPackageName());
方法2:
Field field = R.id.class.getField("edit2");
int id = field.getInt("edit2");
14. 权重weight
当设置了wrap_content时,权重,最小要能包裹能容,也就是说即使权重小,但是也要先放下全部内容,所以大小还是会变
当设置了fill_parent(match_parent)时,权重,最大只能是填充父窗体,也就是说,就算内容再多,也只能到父窗体那么大
如果设置为0dp,那就是严格按照权重比例来区分了
15.path颜色设置问题
1 .在我做自定义画板view的时候,需要重新给画笔设置颜色,但是颜色会覆盖之前已经画好的东西,问题就是,如果 要改变颜色,就要重新new 一个新的path出来,总之每次的都不能一样,可以保存起来,颜色一样的再复用.
2 . 另外paint画笔的设置,风格很重要,,一个是fill 填充,一个是stroke描边这个要区别开
16.Dagger2中的问题
dagger是针对类与类之间调用,导致耦合性提高,而提供通过依赖注入的方式解耦的一个框架.(我不喜欢用)
module : 用来告知dagger 该依赖(要注入的对象) 的构造方法,这里需要注意的问题是,如果构造方法有多个参数,那么需要一层一层的去通过@provides 来告知,不可以一次性告知,例如:
//这是需要注入对象的构造方法
@Injectpublic LoginPresenter(ILoginActivity iLoginActivity, IM im) {
this.iLoginActivity = iLoginActivity; this.im = im;
}
//这是module告知的方式
private final ILoginActivity iLoginActivity;
public LoginActivityModule(ILoginActivity iLoginActivity) {
this.iLoginActivity = iLoginActivity;
}
@Provides
ILoginActivity provideIloginActivity() {
return iLoginActivity;
}
@Provides
LoginPresenter provideLoginPresenter(ILoginActivity iLoginActivity, IM im) {
return new LoginPresenter(iLoginActivity, im);
}
- dagger中module 和 component的工作流程是,component负责连接 宿主 和 依赖 ,当 宿主 中注入 依赖 时,dagger就会从 宿主 注册的component中寻找 依赖 的 被注册的 构造法方法,然后进行实例化,最后就完成了注入
- 对于在Component中添加 dependencies 依赖,这样的话,本个Component会继承dependencies里的所有实例化对象,这种情况一般用在继承AppComponent,而AppComponent则实例化了一些全局性的变量
- 而对于Component中的 modules参数,里边则是告知dagger,需要实例化哪些类,对应的module中要给出构造函数的实例化方法
17.java文件路径问题
在写一个客户端通过URL地址下载服务器图片的额时候,怎么都加载不出来图片,后来发现,原来忘了写 http:// ,当时想省事直接从ip地址开始写的.
另外,发现一个好玩的东西,java服务器只需要把图片放到项目的webcontent目录下,即可,例如我在 webcontent 目录下,新建了一个image文件夹,把所有的图片都放进去了,然后我客户端的路径就可以这样写:
path = "http://123.56.104.149:8080/DrawingAndGuessingServer/image/1.jpg";
Glide.with(this).load(new URL(path)).into(image); 这里用的glide图片加载框架
这样,直接就把图片加载到imageview中了,,而不是我之前想的那样还要写什么输入流输出流,唉:-(,,TMD,想多了.,原来这么简单!
18.项目中AppTheme报错问题
No resource found that matches the given name 'Theme.AppCompat.Light'.
查看 res/values/styles.xml 下的报错点。
<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
把这个改成
<style name="AppBaseTheme" parent="android:Theme.Light">
路径: res/values-11/styles.xml
<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
把这个改成
<style name="AppBaseTheme" parent="android:Theme.Holo.Light">
路径: res/values-14/styles.xml
<style name="AppBaseTheme" parent="Theme.AppCompat.Light.DarkActionBar">
把这个换成
<style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
19.Dialog中dismiss和hide的区别
dismiss和hide方法都可以隐藏对话框,在需要的时候也可以用show方法调用显示。但是,这两者是有区别的。
dismiss方法会释放对话框所占的资源,而hide方法不会。activity退出前必须调用dismiss方法关闭对话框。
如果对话框上有progressbar,你会发现,调用dismiss方法后,再调用show方法,出来的对话框,上面的progressbar不再会转动,而调用hide方法的则没有问题。
所以,最正确的调用方法是,在activity的onDestory方法里调用dismiss方法,其他地方都用hide方法隐藏对话框。
20.app退出后台,重新进入后,页面重新载入问题
问题具体描述: 打开app,进入一个页面,然后点击home,退到后台,这时候,再次点击app图标进入app,应该打开上次的页面,而不是重新载入.
问题解决: 我的app入口是,splashactivity,,我把splashactivity的启动模式设置成singleTask了,,所以导致每次点击app图标进入,会重新载入,其实不是重新载入了,而是重新走splashactivity了,如果我们有这个需求,可以这样写,每次点击app图标,就会重新走这里,,如果没有,想点击app图标,回到上次的页面,我们就把启动模式换掉就可以了.
21.app异常强制退出后,自动重启问题
在自己的Activity堆栈管理类中,finish掉虽有的activity就可以了
没有试过,他妈因为测不出来bug了,反正就是好了
22.微信分享,不显示缩略图bug
是因为分享的简介中存在 微信认为的 敏感词汇:元 红包 领取,目前知道的就这几个,也许有别的,微信也没有文档,自己看着办吧.
23.android图标文件夹 规范(原则是不低于规范尺寸,单位:px)
hdpi文件夹 —— 192x192
xhdpi文件夹 —— 256x256
xxhdpi文件夹 —— 384x384
xxxhdpi文件夹 —— 512x512
注:分辨率适配目录参考
480*800 drawable-hdpi
540*960 drawable-sw360dp-hdpi
720*1280 drawable-sw360dp-xhdpi
1080*1920 drawable-sw360dp-xxhdpi
1440*2560 drawable-sw360dp-xxxhdpi