● Recyclerview一旦嵌套到NestedScrollView 中,Recyclerview的数据就会一次行加载完成,Recyclerview内部的复用会失效,如果数据量多的话,就会造成卡顿。解决办法:不要用NestedScrollView,可以给RecyclerView加header、footer来实现同样的效果。
● Fragment中以startActivityForResult的调用方式启动Activity时,不要使用getActivity().startActivityForResult方法,而是要直接使用startActivityForResult。
否则在Fragment中写的onActivityResult不会被调用。
● Android TextView文字中间添加删除线:
tv.getPaint().setFlags(Paint. STRIKE_THRU_TEXT_FLAG |Paint.ANTI_ALIAS_FLAG);
● Android 最新版本,不能存储文件到公共目录。
可以在Androidmainfest 里面的application添加
android:requestLegacyExternalStorage="true"
这样就可以继续使用原来的存储方式。
● 使用google的gson对Map对象进行json转换,像下面这样,如果对象值含特殊字符,则会变成unicode编码。比如url中的=。
String strEntity = new Gson().toJson(paramsMap);
如果想解决,可以这样解码:
strEntity = URLDecoder.decode(strEntity, "utf-8");
● recyclerView添加自定义分割线:可自定义分割线divider_line
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL);
dividerItemDecoration.setDrawable(ContextCompat.getDrawable(this, R.drawable.divider_line));
recyclerView.addItemDecoration(dividerItemDecoration);
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:left="8dp" android:right="8dp">
<shape android:shape="rectangle">
<solid android:color="#dddddd" />
<size android:height="1dp"/>
</shape>
</item>
</layer-list>
● Java对象和Json字符串的转换(Gson实现):
dependencies {
implementation 'com.google.code.gson:gson:2.8.4'
}
import com.google.gson.Gson;
UserBean bean = getUserBean();
String jsonStr = new Gson().toJson(bean);
bean = new Gson().fromJson(jsonStr, UserBean.class);
● 解决ScrollView嵌套RecyclerView,滑动卡顿的问题:
recyclerView.setHasFixedSize(true);
recyclerView.setNestedScrollingEnabled(false);
或者这样:
recyclerview.setLayoutManager(new LinearLayoutManager(getActivity()){
@Override
public boolean canScrollVertically() {
return false;
}
});
如果要解决ScrollView里嵌套的LinearLayout里,同时包含了RecyclerView和其他控件,想联动滑动,可以把ScrollView换为android.support.v4.widget.NestedScrollView。
● ListView几个有用的属性:
android:divider="@color/transparent" //设置Listview的各个item之间的分割线颜色为透明,也就是不显示分割线
android:listSelector="@android:color/transparent" //设置各个item被点击时的颜色变化,透明则为无变化
android:overScrollMode="never" //设置Listview下拉时顶部不出现半月形的阴影
● 优化程序性能时,可以在一段需要分析的代码前后分别加上这两行代码:
Debug.startMethodTracing("Test");
xxx中间是需要分析的代码xxx
Debug.stopMethodTracing();
这样程序这段运行之后,就会生成一个Test.trace文件,可以把这个文件导出:
adb pull storage/emulated/0/Android/data/应用包名/files/Test.trace .
然后用Android studio或者DDMS打开Test.trace,就可以看到该段代码各个处理耗费的时间。
● 调用下面的代码可收起虚拟键盘:
InputMethodManager im = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (null != im) {
im.hideSoftInputFromWindow(getCurrentFocus().getApplicationWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
● 当ScrollView里的元素想填满ScrollView时,使用"fill_parent"或者"match_parent"是不管用的,必需为ScrollView设置:android:fillViewport=“true”。
当ScrollView没有fillVeewport=“true”时, 里面的元素(比如LinearLayout)会按照wrap_content来计算(不论它是否设了"fill_parent"或者"match_parent")。
● RadioButton在动态调用setChecked()的时候可能会不生效。具体表现为值已经改过来了,但是选中状态并没有变。可以调用RadioGroup.clearCheck()后再调用RadioButton的setChecked()方法就好了。
但是更好的办法是用RadioGroup.check(RadioButton.getId())的方法设置选中的RadioButton。
● 项目中有次release版本解析json出错,原因如下:用Google的Gson库解析json字符串为指定的对象时,要在该对象的定义类的各个属性值前加上@SerializedName标注。不加可能出错。加上后的属性如下:
@SerializedName("day")
private int day;
● 限制屏幕方向时,android:screenOrientation属性不要写在自定义的style里,否则用android:theme给activity指定屏幕方向可能会失效(测试机型为android4.4)。在manifest文件具体的activity下配置此属性就正常了。
● 给TextView动态设置文本时,如果文本是int型的数字a,不能直接setText(a),因为这样a会被当作resourceId而报ResourceNotFoundException。
● IntentService是一个异步的Service,会在该Service里用Handler创建一个线程做处理,处理完成后
会停止该线程并终止该Service。
● 使用IntentService必须创建一个无参的构造方法,否则会报错。
无参构造方法示例如下:
public MyIntentService() {
super("MyIntentService");
}
● 创建IntentService的时候,不要重写onStartCommand()方法,重写可能导致出错。
要重写的是onHandleIntent()方法。
● 连续多次调用bindService()并不会多次创建和绑定Service,即不会多次调用该服务的onCreate()和onBind()方法。
● 如果Service已经取消了绑定,那么再次调用unBindService()时就会报错java.lang.IllegalArgumentException: Service not registered。因此调用unBindService()最好做判断,可以用一个flag做为绑定或者解绑定的标志。
● 连续多次调用startService()也不会多次调用该服务的onCreate()方法,但会连续调用多次该服务的onStartCommand()方法。
● ServiceConnection的onServiceDisconnected()方法正常情况下是不会被调用的。只有该Service被意外断开连接时会调用。
● BroadcaseReceiver的onReceive()方法里的处理不能时间太长,一般超过10s会发生ANR。
● 如果一个layout里包含了ImageButton, 在给这个layout设置点击事件时,如果ImageButton不同时设置点击事件,那么点击事件可能在ImageButton上失效。解决办法是给ImageButton设置属性android:clickable=“false”。这样点击事件就只由该layout处理了。
如果要给layout和ImageButton设置不同的点击事件,可以把ImageButton换成ImageView。
● 一般来说在工作线程中执行耗时任务,当任务完成时,会返回UI线程,一般是更新UI。这时有两种方法可以达到目的。
一种是handler.sendMessage。发一个消息,再根据消息,执行相关任务代码。
另一种是handler.post®。r是要执行的任务代码。意思就是说r的代码实际是在UI线程执行的。可以写更新UI的代码。(工作线程是不能更新UI的)
- 1 在子线程中利用post(Runnable r)更新UI,原理和sendMessage()类似.
- 2 所以“在子线程中利用post(Runnable r)更新UI”这个说法不是特别准确.
- 确切地说还是在子线程中发送了消息到主线程的消息队列从而更新了UI.
- 3 调用post(Runnable r)不会开启一个新的线程,UI的更新是在主线程中完成的!!!!!!!!!!
- 所以在post方法中勿做耗时操作.
● Activity的isFinishing()方法可以判断activity是不是正在结束,一般可以在onPause()中用,用来确定activity是被调用了finish()或者其它方法主动销毁而调用onPause(),还是返回后台而调用onPause()。
● 重写onKeyDown()方法时,可以返回true或者false。返回true表示“我已经处理完了,不再需要调用父类的onKeyDown()方法”,返回false表示“我还没处理完,会调用父类的onKeyDown()继续处理。”
● activity里弹出Dialog时,并不会调用onPause(),Dialog取消时也不会调用onResume()。只有activity被其它应用遮盖时才会调用onPause()。
● onUserLeaveHint() 用户手动离开当前activity,会调用该方法,比如用户主动切换任务,按back键,短按home进入桌面等。启动本应用的其它activity时也会调用此方法。
而系统自动切换应用时不会调用此方法,如来电,灭屏等。finish()方法运行后也不会调用此方法。
● 沉浸式状态栏:
//只透明状态栏
public static void hideStatusBar(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = activity.getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
}
//状态栏、导航栏都透明
public static void hideStatusBarNavigationBar(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = activity.getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
window.setNavigationBarColor(Color.TRANSPARENT);
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
activity.getWindow().addFlags( WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
activity.getWindow().addFlags( WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
}
● 使用onActivityResult(int requestCode, int resultCode, Intent data))时要注意,如果启动的activity返回时没有调用setResult(int resultCode), 则onActivityResult()里传入的resultCode为0。
● 如果某activity A的启动模式是singleTask或者SingleTop,而且已经位于栈顶,则再次启动它,生命周期为onPause-onNewIntent-onResume.
● 如果某activity A的启动模式是singleTask,且不位于栈顶,栈顶是B,则再次启动A的话,生命周期为:
1.A和B中间的 activity先执行onDestroy。
2.B执行onPause。
3.A执行onNewIntent-onRestart-onStart-onResume。
4.B执行onStop-onDestroy。
● List的addAll()方法不能传入null,否则会报空指针异常。因此在传参之前要判断非空。
● 用循环给一个List添加元素时,像这样的添加是不对的:
List<Element> mList = new ArrayList<>();
Element tmpElement = new Element();
for(i = 0; i < 10; i++) {
tmpElement.setId(i);
mList.add(tmpElement);
}
这样添加之后,mList 会有10个Element 元素,但是其id全都是9。因为每一次循环都会更新已添加到mList中的tmpElement的Id值。正确的做法可以在每次循环都new一个tmpElement然后添加。
● 项目中用到了android-async-http库,原本是以http的方式访问服务器,现在要支持https,做修改的时候,把代码做如下修改即可:
// private static AsyncHttpClient client = new AsyncHttpClient();
private static AsyncHttpClient client = new AsyncHttpClient(true, 80, 443);
这样修改表示客户端会信任所有的证书(不止是信任自己的服务器)。
● 修改项目包名时有个注意点:在 Studio 里面我们的 getPackageName 对应的是 applicationId , 而manifest 的那个package,在这里的作用其实是为了引用内部资源文件,以及保证 Activity 等源文件的路径正确而已,所以,如果只是为了修改程序包名,则只需要在 build.gradle 文件中修改 applicationId 就可以了。但是要注意如果用到了第三方sdk,比如用高德地图的sdk时用的还是旧的包名,那么要重新接入新的包名。
● .9图可实现随内容自动拉伸的效果,制作时,可以把png图片放到drawable文件夹下,然后把后缀改为.9.png,然后用Android studio打开,即可进行编辑。
通过编辑其上、左边界,可定义图片进行拉伸的部分,编辑其右、下边界,可定义内容显示的部分。
● NotificationManager.notify()和Service的startForeground()方法都可以显示一个notification,但是startForeground方法的意义在于可以把service变成前台服务,提升服务优先级。
● 给Android布局或者文本通过SetBackgroundResource()设置背景图时,经常出现图片被拉伸的情况。可以通过下面的方法解决:
drawable文件夹下新建一个xml文件,比如命名为xml_layout_bg.xml,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:gravity="center"
android:src="@drawable/layout_bg"
android:tileMode="disabled">
</bitmap>
其中layout_bg.png为背景图。然后调用setBackgroundResource(R.drawable.xml_layout_bg)设置背景即可。
● 监听屏幕亮灭变化时,可以注册监听三个系统广播:
Intent.ACTION_SCREEN_ON
Intent.ACTION_SCREEN_OFF
Intent.ACTION_USER_PRESENT
其中前两个需要在代码中动态注册才能监听,而Intent.ACTION_USER_PRESENT静态注册或者动态注册都能监听到。如果同时进行了静态注册和动态注册,则广播接收器会收到两次。
● 在xml文件里定义字符串的时候,尤其是字符串是数字的时候,避免这么写:
<item name="tv_hello" type="string">1234</item>
这么写的话,如果这样调用:tv.setText(getText(R.string.tv_hello)),那么实际会调用setText(@StringRes int resid)这个方法,也就是说1234会被当成资源ID来处理,就会报错。
正确的写法:
<string name="tv_hello">1234</string>
非得用上面那第一种写法的话,要加上format="string"防止报错。
<item name="tv_hello" type="string" format="string">1234</item>