Android-Tips
本項目會持續更新
github鏈接
內容是我自己平時學習與工作積累的代碼與準則,並沒有什麼原理剖析。如有錯誤歡迎指正,如有侵權,請聯繫我刪除。
Tips
- Android Tools命名空間原來是有大用處的。大致有三種主要功能:
xml中的錯誤處理
xml 預覽
資源壓縮
具體閱讀地址點我 - 如果你覺得在安裝Eclipse後還需要配置android開發環境很麻煩,你可以直接使用ADT Bundle,它是一個懶人套餐。反正我就是怎麼過來的。下載鏈接
- 使用Toast時,建議定義一個全局Toast對象。可以避免連續顯示Toast 時不能取消上一次 Toast 消息的情況。
- 靈活使用ViewStub Merge Include標籤優化佈局。
- 靜態變量不要直接或者間接引用Activity、Service等。這會使用Activity以及它所引用的所有對象無法釋放,若用戶操作時間一長,內存就會狂升。
- 在Activity.onPause()或 Activity.onStop()回調中,關閉當前 activity 正在執行的的動畫。
- ImageView Selector不生效的解決方案
1.ImageView要加上clickable=”true”,不然它的selector 是不會有效果。
2.ImageView selector的默認圖片item要放到最後。 - 自定義progressbar seekbar ui樣式。發現最後進度條的粗細和滑塊一樣大。請設置android:maxHeight&android:minHeight,這是指定進度條最大/小高度的(此高度並非SeekBar整個控件的高度)。
- 瞭解與開發原生Setting乾貨鏈接
- Android framework系統默認設置修改,主要是6.0以下版本乾貨鏈接
- 設置ScrollView始終顯示滾動條
android:scrollbars="vertical"
android:fadeScrollbars="false"
- ListView、GridView都要實現Item的點擊事件與長按事件。則Item長按監聽回調函數要return true,否則長按是會執行setOnItemClickListener。
- 禁止listview的item項獲得焦點,而讓item的子控件獲得焦點。
//設置item項的子控件能夠獲得焦點(默認爲false,即默認item項的子控件是不能獲得焦點的)
listView.setItemsCanFocus(true);
- 補充上點:沒有出現的獲得焦點高亮效果,可能有以下原因:
1.例如:ImageView默認不能獲得焦點,應該設置屬性爲:android:focusable=”true” (如果是ImageButton或Button等則不需要設置,他們默認是可以獲得焦點的)
2.沒有爲該ImageView設置自定義drawable圖片的的selector(該ImageView其實已經獲得焦點了,只是沒有看出來而已)。 - PopUpWindow都設置點擊外面消失了,怎麼還不消失。噢,還差一句。
mPopUpWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));
- 需要PopUpWindow在某個View某位置彈出。使用PopUpWindow.showAtLocation(View parent, int gravity, int x, int y)
PopUpWindow mPopTextSettingWindow ;
private void showPopupWindow(View targetView) {
//TODO do something
...
int[] location = new int[2];
targetView.getLocationOnScreen(location);
int w = mPopTextSettingWindow.getWidth();
int h = mPopTextSettingWindow.getHeight();
//targetView正上方彈出
mPopTextSettingWindow.showAtLocation(targetView, Gravity.NO_GRAVITY,
location[0] - w / 2 + targetView.getWidth() / 2, location[1] - h -10);
}
- 設置系統的觸摸提示音功能。
//打開關閉觸摸聲音
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.SOUND_EFFECTS_ENABLED, isBeepSound ? 0 : 1);
- 系統閃爍標籤blink,閃爍頻率500毫秒,不支持修改。BlinkLayout源碼位置:Layoutinflate中的一個private類型的內部類,繼承自FrameLayout。
<blink
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Blink Layout"></TextView>
</blink>
* 長按MenuItem會Toast該Item的Title。
* 設置系統壁紙。
WallpaperManager mWallManager = WallpaperManager.getInstance(getActivity());
mWallManager.suggestDesiredDimensions(wallpaperWidthPX,wallpaperHeightPX);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_WALLPAPER_CHANGED);
mWallManager.setBitmap(mBitmap);//還有setDrawable()等方法。
mContext.sendBroadcast(intent);
- 獲取系統壁紙。
WallpaperManager.getInstance(getContext()).getDrawable();
- 多個EditText控件,例如註冊登錄界面。需當前EditText按回車按鈕跳轉到指定EditText。
android:imeOptions="actionNext"
android:singleLine="true"
android:nextFocusForward="@+id/et_address"
- 動態監控數據庫某值的變化,可繼承下ContentObserver類。
/**
*
* @author RealMo
* VolumeObserver 主要音量變化(遙控)
*/
private class VolumeObserver extends ContentObserver {
public VolumeObserver(ContentResolver resolver) {
super(new Handler());
}
@Override
public void onChange(boolean selfChange) {
// TODO Auto-generated method stub
super.onChange(selfChange);
Log.d("realmo", "VolumeObserver===========");
isMute = false;
setMuteViewImage(isMute);
// 更新音量條進度
currentVolume = mAudiomanager
.getStreamVolume(AudioManager.STREAM_MUSIC); // 獲取當前值
//TODO do something
}
}
//init
VolumeObserver mVolObserver = new VolumeObserver(mContext.getContentResolver());
//監聽相應的數據庫內容
mContext.getContentResolver().registerContentObserver(
Uri.parse("content://mstar.tv.usersetting/soundsetting/Volume")
, true, mVolObserver);
- 終止Android中HandlerThread的方法。
mHandlerThread.getLooper().quit();
- 保存&刪除圖片並通知系統相冊刷新。
Intent intent= new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
// 最後通知圖庫更新
intent.setData(Uri.fromFile(file));
sendBroadcast(intent);
- 應用可以監聽home鍵,通過廣播。噢!還必須是動態廣播。而且是不能攔截Home鍵,除非改底層。
//廣播監聽Home,並不能攔截Home鍵
//register
registerReceiver(mHomeKeyEventReceiver, new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
//unregister
unregisterReceiver(mHomeKeyEventReceiver);
//init broadcastreceiver
private BroadcastReceiver mHomeKeyEventReceiver = new BroadcastReceiver() {
String SYSTEM_REASON = "reason";
String SYSTEM_HOME_KEY = "homekey";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
//TODO your task
}
}
};
- 設置系統語言。
//設置英語爲系統語言
Locale locale = new Locale("es", "es");
IActivityManager am = ActivityManagerNative.getDefault();
Configuration config = am.getConfiguration();
config.setLocale(locale);
am.updateConfiguration(config);
- 獲取當前系統語言。
Locale locale = getResources().getConfiguration().locale;
String language = locale.getLanguage();
- 實現WindowManager添加的view,點擊以外區域退出。添加WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH的flag。不過點擊外面,對應後面可見app也會有接收到該觸摸響應。所以,建議是全屏的view,再通過攔截觸摸事件等方式實現。
private WindowManager.LayoutParams mBarParams;
// init layout Params
mBarParams = new WindowManager.LayoutParams();
//重點添加此flag
mBarParams.flags = WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
//再對addView的View進行ontouch監聽
case MotionEvent.ACTION_OUTSIDE:{
//做退出的具體邏輯處理
}
- Java內存分配機制
- Preference(不是SharedPreferences)的xml屬性一定要給key屬性。否則不會記錄用戶更新的數據。
- Eclipse有時報64k方法問題,實際上遠沒到達64k方法數,我的解決方式:架包以外部形式引用。
- Eclipse編譯gc問題,我的解決方式:架包以外部形式引用;調整架包順序。
- EditText selectAllOnFocus屬性—獲得焦點即全選
- 當App不需要Launcher Activity(既沒有應用入口),AS不能直接run該App。需在AS Run/Debug Configuration -> Android Application -> General -> Activity -> select the option “Do not launch Activity”。
- Glide加載圖片,顯示的圖片仍是之前的圖片。原因:因爲Glide加載圖片會將圖片緩存到本地,如果url不變則直接讀取緩存不會再重新加載。
//解決方式1:返回不同的url。
//解決方式2:加上這2個設置。
Glide.with(this)
.diskCacheStrategy( DiskCacheStrategy.NONE )//禁用磁盤緩存
.skipMemoryCache( true )//跳過內存緩存
- handler.post運行線程並不是開啓一個新線程。點擊鏈接
//直接調用的Runnable的run方法,並不是strat(),所以僅僅是當做一個有run()的普通類使用而已,並不是開啓了一個新的線程。
private static void handleCallback(Message message) {
message.callback.run();
}
Activity與Fragment的生命週期,估計各位都很熟悉。但View的生命週期呢?見下圖:
view.performClick()觸摸該View點擊事件。
- activity.moveTaskToBack(true);按Back鍵回桌面,但不銷燬該Activity。
- ANR異常保存在/data/anr/traces.txt。
- ViewPager切換動畫。
“`
//設置viewpager切換動畫
ViewPager.setPageTransformer(true,new MyTrans());
//實現viewPager的切換動畫
class MyTrans implements ViewPager.PageTransformer{
/**
* 根據偏移百分比,計算每個View的偏移比
*
* @param page 當前Fragment的View
* @param position view的偏移百分比
*/
@Override
public void transformPage(View page, float position) {
//TODO do your animation
}
}
* 動態加載Fragment的佈局按鈕不能生效onClick屬性。
* 判斷viewpager能否繼續左滑,繼而觸發某些事件。
//判斷viewpager是否能繼續左滑。(即已到最右的一頁,判斷準則有無慣性滑動)—若有內容的滑動是有慣性滑動狀態。(當然排除極端無聊的用戶)
/**
* 1.有內容的滑動的狀態值變化:
* 1--->2---->0
*
* 2.無內容的滑動的狀態值變化:
* 1--->0
*
*/
boolean isLeftScroll;
@Override
public void onPageScrollStateChanged(int state) {
//根據state進行判斷
switch (state){
//手指滑動---狀態值:1
case ViewPager.SCROLL_STATE_DRAGGING:{
}break;
//停止狀態----狀態值:0
case ViewPager.SCROLL_STATE_IDLE:{
//如果是最後一頁(繼續左滑是沒有慣性滑動的),且沒有慣性滑動時,跳轉其他界面
if(!isLeftScroll &&viewPager.getCurrentItem()==(viewPager.getAdapter().getCount()-1)){
Intent intent = new Intent(this,CityChoiceActivity.class);
startActivity(intent);
finish();
}
isLeftScroll =false;
}break;
//慣性滑動--狀態值:2
case ViewPager.SCROLL_STATE_SETTLING:{
isLeftScroll=true;
}break;
}
}
* 只用於應用內的廣播,用LocalBroadcastManager本地廣播。效率高,安全性更好。
* 避免使用隱式 Intent 廣播敏感信息,信息可能被其他註冊了對應BroadcastReceiver 的 App 接收。
* 不要在 Activity#onDestroy()內執行釋放資源的工作,例如一些工作線程的銷燬和停止,因爲onDestroy()執行的時機可能較晚。可根據實際需要,在Activity#onPause()/onStop()中結合 isFinishing()的判斷來執行。
* Android5.0 以後安全性要求較高的應用 應該使 用 window.setFlag(LayoutParam.FLAG_SECURE) 禁止截圖&錄屏。
* SharedPreference提交數據時,儘量使用Editor.apply() (異步),而非Editor.commit() (同步)。
* Canvas的drawText繪製文本是不會自動換行的。而StaticLayout是android中處理文字換行的一個工具類,StaticLayout已經實現了文本繪製換行處理。
* 如果使用Context.startActivity啓動外部應用,最好做一下異常預防,因爲尋找不到對應的應用時,會拋出異常。
* 別在用View分隔控件了。Space是Android 4.0中新增的一個控件,它實際上可以用來分隔不同的控件,其中形成一個空白的區域.這是一個輕量級的視圖組件,它可以跳過Draw,對於需要佔位符的任何場景來說都是很棒的。
* ValueAnimator.reverse() 這個方法可以很順利地取消正在運行的動畫。
* 自定義ViewGroup神器-ViewDragHelper,主要處理拖拽和設置子View的位置。
* 不要用intent傳遞大量的數據,這樣有可能導致ANR或者報TransactionTooLargeException異常。
* 獲取控件在屏幕的絕對座標位置
int[] viewLocation = new int[2];
View.getLocationOnScreen(viewLocation);
* 我們知道首次加載界面在oncreate甚至onresume中View.getWidth和View.getHeight獲得一個view的高度和寬度是0。若想獲取控件的準確寬高等信息。常見通過View.post()。不過,我更喜歡通過監聽OnGlobalLayoutListener。當然,如果你的需求只是加載界面獲取一次控件的寬高信息。View.post()無疑更簡潔。但若控件大小或者位置有改變,監聽OnGlobalLayoutListener顯然更強大。它是ViewTreeObserver的內部類,當一個視圖樹的佈局發生改變時,可以被ViewTreeObserver監聽到,這是一個註冊監聽視圖樹的觀察者(observer),在視圖樹的全局事件改變時得到通知。
//Only use once
private int viewHeight = 0;
private int[] viewLocation = new int[2];
view.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// getting view height & width & screen postion
viewHeight = view.getHeight();
view.getLocationOnScreen(viewLocation);
// removeOnGlobalLayoutListener
view.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
}
});
//Get in real time
onresume(){
//TODO addOnGlobalLayoutListener
....
}
onpause(){
//TODO removeOnGlobalLayoutListener
...
}
* 有時候我們希望程序拋出異常時能把異常信息保存到制定文件夾的文件裏,getStackTraceString就能夠將異常信息轉換成字符串的形式。
try {
//TODO
} catch (Exception e) {
String exceptionStr = Log.getStackTraceString(e);
}
* 我常用SystemClock.sleep(long ms)模擬網絡延遲,並且不會拋出InterruptedException。
* Activity的recreate():一個Activity又一次創建自己一個新實例的方法。調用該方法目標Activity會又一次走一遍自己的生命週期。
* Android平臺不建議使用枚舉,Android官方的性能優化相關課程提過存在性能問題。[大神胡凱傳送門](http://hukai.me/)
* Android進程保活招式大全[傳送門](https://juejin.im/entry/586bcd07570c350068b1fba2)
* Java8愉快且方便的處理時間的類:LocalDate、LocalTime、LocalDateTime。相比Date來說,它們更安全、更精確也更明確。
* 爲了減輕應用程序主進程的內存壓力,對於耗內存比較多的界面(比如視頻播放界面、flash播放界面等),可以在AndroidManifest.xml文件中對應的Activity標籤下調用“android:process=".processname"”單開一個進程,但在退出這個界面的時候一定要在該界面的onDestory方法中調用System的kill方法來殺掉該進程。
* 在res/values/arrays.xml文件中定義的單個數組的元素個數不宜過大,過大會導致加載數據時非常慢,有時候你需要使用數組資源時數據有可能還沒加載完成。
* 可以通過爲application、activity自定義主題的方式來關掉多點觸摸功能,只需要在自定義的主題下添加這兩個標籤:
false
false
* 我個人比較喜歡關於Android矢量圖的學習文章,是外文的。[乾貨鏈接](https://www.androiddesignpatterns.com/2016/11/introduction-to-icon-animation-techniques.html)
* 使用 Canvas.drawBitmapMesh實現仿真水波紋效果,網上搜一大把。
* Android Studio使用自己Framework架包。因爲原生有些API的限制或反射等問題。需要使用到自己Framework架包。如果只是直接導入架包到項目,依舊編譯不通過。需以下步驟:
//1.架包的依賴方式爲編譯時使用。
//2.project的build.gradle增加
allprojects {
repositories {
google()
jcenter()
}
//add this
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs << “-Xlint:unchecked” << “-Xlint:deprecation”
options.compilerArgs.add(‘-Xbootclasspath/p:app/libs/framework-full.jar’) //寫架包的絕對路徑或相對路徑
}
}
}
//3.app的build.gradle增加
defaultConfig {
…
multiDexEnabled true
}
//4.顯示依舊報錯,但編譯可以通過。
* View類中的getDrawingCache()等一系列方法可以用於獲取View顯示的Bitmap對象。
* TouchSlop,系統所能識別出的被認爲是最小的滑動距離,ViewConfiguration.get(context).getScaledTouchSlop()。常用於自定義View。
* Context的作用域</br>
![](https://github.com/RealMoMo/Android-Tips/blob/master/img/context.png)
* 修改Toast字體大小。
Toast toast = Toast.makeText(IndexActivity.this, "這個是一個測試", Toast.LENGTH_SHORT);
// 修改Toast字體大小
LinearLayout linearLayout = (LinearLayout) toast.getView();
TextView messageTextView = (TextView) linearLayout.getChildAt(0);
messageTextView.setTextSize(25);
// 顯示Toast
toast.show();
* Android Studio3.0生成apk名字配置。
//最簡單打包後應用名稱(還可以根據debug release等各版本設置對應apk名字)
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = “customName.apk”
}
}
* 截屏
public static Bitmap screenShot(int width, int height) {
Class
* Android推薦的數據結構:</br>
ArrayMap<K,V> 替代 HashMap<K,V> </br>
ArraySet<K,V> 替代 HashSet<K,V> </br>
SparseArray<V> 替代 HashMap<Integer,V> </br>
SparseBooleanArray 替代 HashMap<Integer,Boolean> </br>
SparseIntArray 替代 HashMap<Integer,Integer> </br>
SparseLongArray 替代 HashMap<Integer,Long> </br>
LongSparseArray<V> 替代 HashMap<Long,V> </br>
* UncaughtExceptionHandler接口,利用此接口可以對未捕獲的異常善後。
* ValueAnimator.reverse() 這個方法可以很順利地取消正在運行的動畫。
* ViewParent.requestDisallowInterceptTouchEvent()——Android系統觸摸事件機制大多時候能夠默認處理,不過有時候你需要使用這個方法來剝奪父級控件的控制權。
* 設置佈局動畫屬性android:animateLayoutChanges="true",需要更炫的可以自定義動畫添加android:layoutAnimation="@anim/your_animation"。
<!--Button點擊事件只是對TextView.setVisibility-->
<!--開啓佈局默認動畫-->
<LinearLayout
android:animateLayoutChanges="true"
android:layout_width="match_parent"
android:layout_height="200dp">
<TextView
android:text="666"
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:text="with Animation"
android:onClick="one"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="200dp">
<TextView
android:text="666"
android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:text="none Animation"
android:onClick="two"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
![](https://github.com/RealMoMo/Android-Tips/blob/master/img/animateLayoutChanges.gif)
* 深入理解 Java 垃圾回收機制 -> [鏈接](http://www.importnew.com/16173.html)
* Quick App 快應用[官方文檔鏈接](https://www.quickapp.cn/)
* TextView通過代碼設置Drawable沒顯示圖片?請添加以下代碼
Drawable drawable = drawable = getResources().getDrawable(R.drawable.wifi_active);
//important
drawable.setBounds(0,0,drawable.getMinimumWidth(),drawable.getMinimumHeight());
//該方法源碼已說明The Drawables must already have had {@link Drawable#setBounds} called.
tvWiFi.setCompoundDrawables(null,drawable,null,null);
* 初級入門JNI開發的[專題](https://www.jianshu.com/c/a25bf14495d7)
* 底層支持多用戶,需設置的系統屬性
//method 1:
setprop fw.max_users 8
setprop fw.show_multiuserui true
//method 2:
//配置多用戶:
// /frameworks/base/core/res/res/values/config.xml
//修改其中的config_multiuserMaximumUsers的值爲4 (看要支持幾個用戶)
//修改之後,設置中能看到用戶這個菜單,而不是本來就有的賬戶。
* setBackgroundResource(0) 可以移除 View 的背景色
* 如果想把一個view保存爲Bitmap,正常情況下用第一種方法就可以了,但是如果是ScrollView,則必須採用第二種方法。
//方法一:
public Bitmap createViewBitmap(View v) {
Bitmap bitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
v.draw(canvas);
return bitmap;
}
//方法二:
/**
* 截取scrollview的屏幕
* @param scrollView
* @return
*/
public static Bitmap getBitmapByView(ScrollView scrollView) {
int h = 0;
Bitmap bitmap = null;
// 獲取scrollview實際高度
for (int i = 0; i < scrollView.getChildCount(); i++) {
h += scrollView.getChildAt(i).getHeight();
scrollView.getChildAt(i).setBackgroundColor(
Color.parseColor(“#ffffff”));
}
// 創建對應大小的bitmap
bitmap = Bitmap.createBitmap(scrollView.getWidth(), h,
Bitmap.Config.RGB_565);
final Canvas canvas = new Canvas(bitmap);
scrollView.draw(canvas);
return bitmap;
}
* Android6.0之後getResources().getColor()方法被廢棄了,大家可以用ContextCompat.getColor(context, R.color.color_name)替換,ContextCompat是v4包裏的,請放心使用,另外還有getDrawable()等方法。
* 實現Android一鍵鎖屏 [傳送門](http://www.cnblogs.com/chenyg32/p/3719714.html)
* 另一種通過廣播方式,觸發鎖屏並且不會熄屏。測試環境原生Android5.0可以,6.0以上不可以。
adb shell am broadcast -a com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD –ei ‘seq’ 1
//seq 具體值看實際情況通常是1
* 展示時間用TextClock控件,計時用Chronometer控件。(往往很容易忽略Date&Time的原生控件)
* 入門瞭解與學習InstantApp系列 [鏈接](https://segmentfault.com/a/1190000011648067)
* Deep Links和App Links的對比
</br>![](https://github.com/RealMoMo/Android-Tips/blob/master/img/deeplines_applinks.jpg)
* 對Constraint Layout執行漂亮的動畫用[ConstraintSet](https://juejin.im/entry/58b2fd59570c350069704265?utm_source=gold-miner&utm_medium=readme&utm_campaign=github)
* 修改WifiP2p設備名稱(本人對此的具體應用環境:修改無線投屏名稱)
public void setDeviceName(String devName) {
WifiP2pManager manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
WifiP2pManager.Channel channel = manager.initialize(this, getMainLooper(), null);
try {
Class[] paramTypes = new Class[3];
paramTypes[0] = WifiP2pManager.Channel.class;
paramTypes[1] = String.class;
paramTypes[2] = WifiP2pManager.ActionListener.class;
Method setDeviceName = manager.getClass().getMethod(
"setDeviceName", paramTypes);
setDeviceName.setAccessible(true);
Object arglist[] = new Object[3];
arglist[0] = channel;
arglist[1] = devName;
arglist[2] = new WifiP2pManager.ActionListener() {
@Override
public void onSuccess() {
}
@Override
public void onFailure(int reason) {
}
};
setDeviceName.invoke(manager, arglist);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
“`
* CameraView適配建議
* 監聽時間的廣播需動態註冊
* Intent.ACTION_DATE_CHANGED不廣播的原因:已經廣播過的日期改變,就不會再廣播了,比如時間設置了2012-04-20 23:59, 到了2012-04-21 00:00的時候有該廣播,但再把時間調回到2012-04-20 23:59甚至是更久以前,是不會有該廣播了,除非把時間調到未來,也就是還沒有廣播的時間,如2012-04-21 23:59,纔會繼續有該廣播。
* CoordinatorLayout的Behavior,原生自帶的有:BottomSheetBehavior,HeaderBehavior,HeaderScrollingViewBehavior,ViewOffsetBehavior。更復雜的需求,需
* View滑動方式:1.layout方法 2.offsetLeftAndRight & offsetTopAndBottom方法 3.LayoutParams 4.Animation 5.scrolltTo || scrollBy 6.Scroller 7.ViewDragHelper
Development tools
- Git
- adb
- 如何錄製Demo運行的gif。用GifCam、FFmpeg都可以視頻轉gif。
- Genymotion不解釋
- 代碼對比:Beyond compare
- 壓縮圖片資源利器:TinyPNG
- CMD神器:cmder
- 顏色吸管
- 在線換算dp px sp等單位 Android Pixel Calculator
- IDE自定義主題 Color-themes
- 騰訊文檔
- 可視化插值器interpolator
- Android SVG to VectorDrawable