Android知識(shí)積累

Q:為什么整理知識(shí)忆家,以及copy其它的文章灯变?
A:因?yàn)橹笆詹亓撕枚嗪馨舻奈恼峦舶牵袅撕镁煤蟠蜷_失效了墓拜,也是為了鞏固一下知識(shí),android知識(shí)比較雜亂信认,需要定期整理罪郊。

1.讀取dp數(shù)據(jù)益愈,返回px

getResources().getDimensionPixelOffset(R.dimen.xxx);

2.ListView與ScrollView滑動(dòng)沖突解決

重寫onMeasure

image

3.沉浸式原理

  1. 隱藏狀態(tài)欄户誓,即全屏饼灿。

  2. 新建出一個(gè)狀態(tài)欄代替。

decorView是一個(gè)FrameLayout帝美,內(nèi)部是一個(gè)LinearLayout(本身只有一個(gè)赔退,內(nèi)部是我們的布局,哈哈证舟,廢話!)窗骑。隱藏狀態(tài)欄時(shí)(設(shè)置為透明)女责,LinearLayout會(huì)上移,所以添加新的狀態(tài)欄時(shí)(新建一個(gè)View占空間)创译,需要進(jìn)行margin/Padding處理(高度為getStatusBarHeight(activity))抵知,或者設(shè)置LinearLayout的最外層布局屬性android:fitsSystemWindows="true"。


1
2
3

view.getRootView()獲取到的是decorView,即根ViewGroup刷喜。decorView不包括狀態(tài)欄和導(dǎo)航欄残制,它們屬于SystemUI,當(dāng)它們設(shè)置為透明或隱藏時(shí)掖疮,decorView高度會(huì)填充它們的位置初茶。這也是沉浸式的原理
getWindow().getDecorView()獲取到的也是decorView!


額外說一下浊闪,android.R.id.content指的是上圖中的ContentView(綠色框)恼布,切記!切記搁宾!別搞混了~~~~
findViewById(android.R.id.content)


4.Android5.0中的colorPrimary折汞、colorPrimaryDark、colorAccent

image

在5.0以上手機(jī)上直接設(shè)置colorPrimaryDark顏色盖腿,即可修改狀態(tài)欄顏色爽待;直接設(shè)置colorPrimary顏色,即可修改標(biāo)題欄顏色翩腐;直接設(shè)置colorAccent顏色鸟款,即可修改默認(rèn)的內(nèi)容顏色。

5.padding和margin區(qū)別(與H5不一樣)

image

6.webView的padding設(shè)置有先天bug栗菜!

無論怎么設(shè)置padding都是不好使的欠雌,可以在web頁面中設(shè)置padding,也可以在Android的webview加載頁面時(shí)(原理一樣)疙筹,這樣做富俄,如下:


view.loadUrl(String.format(Locale.CHINA, "javascript:document.body.style.paddingTop='%fpx'; void 0", DensityUtil.px2dp(webView.getPaddingTop())));

7.RecyclerView中使用SnapHelper


SnapHelper snapHelper =new PagerSnapHelper();

snapHelper.attachToRecyclerView(recyclerView);

效果圖:

image

8.performClick

performClick 是使用代碼主動(dòng)去調(diào)用控件的點(diǎn)擊事件(模擬人手去觸摸控件)


boolean android.view.View.performClick()

Call this view's OnClickListener, if it is defined.

Returns:

True there was an assigned OnClickListener that was called, false otherwise is returned.



@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_my);

btn1 = (Button) findViewById(R.id.button1);

tv1 = (TextView) findViewById(R.id.textView1);

btn1.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

tv1.setText("已經(jīng)被點(diǎn)擊過了");

}

});

// 模擬點(diǎn)擊事件

btn1.performClick();

}

9.代碼中設(shè)置Intent模式

intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                Intent.FLAG_ACTIVITY_CLEAR_TOP |
                Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);

FLAG_ACTIVITY_NEW_TASK和Intent.FLAG_ACTIVITY_CLEAR_TOP一起使用的作用等同于singleTask。
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS的意思是不在最近啟動(dòng)的列表中顯示而咆。

10.禁止截屏和錄屏

設(shè)置Activity的屬性:可防止系統(tǒng)截屏

this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);

11.設(shè)置application的allowBackup或者label沖突

  <application
        android:name=".MyApplication"
        android:allowBackup="false"
        android:hardwareAccelerated="false"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/appName"
        android:supportsRtl="true"
        android:theme="@style/NoTitle"
        tools:replace="android:label,android:allowBackup">

沖突是由于該應(yīng)用manifest中android:allowBackup和module或jar包中沖突導(dǎo)致霍比,解決方法是使用tools:replace標(biāo)注來替換,多個(gè)屬性之間用“,”來分隔暴备。

12.SurfaceView與TextureView的區(qū)別

SurfaceView有獨(dú)立的Surface悠瞬,通過“挖洞”原理顯示它。以致它在執(zhí)行旋轉(zhuǎn)時(shí)涯捻,畫面不會(huì)跟隨旋轉(zhuǎn)浅妆;同時(shí)設(shè)置透明度或者執(zhí)行透明值動(dòng)畫時(shí),顯示有問題障癌。Android N以上的SurfaceView在視頻進(jìn)行縮放旋轉(zhuǎn)時(shí)會(huì)同步變化凌外,不會(huì)看到黑色邊,官方推薦使用SurfaceView涛浙。TextureView作為普通View在View hierarchy中管理與繪制康辑,更適用于小窗播放視頻功能摄欲。但TextureView需要硬件加速層,使得TextureView比SurfaceView和GLSurfaceView更耗性能疮薇。

原鏈接:https://cloud.tencent.com/developer/article/1034235

13.讀取視頻文件資源

AssetFileDescriptor afd1 = getResources().openRawResourceFd(R.raw.big_buck_bunny_720p_20mb);
try {
  mMediaPlayer.setDataSource(afd1.getFileDescriptor(), afd1.getStartOffset(), afd1.getLength());
} catch (IOException e) {
  e.printStackTrace();
}

14.TextView設(shè)置刪除線/下劃線/加粗

txt1 = ((TextView) findViewById(R.id.txt1));  
txt2 = ((TextView) findViewById(R.id.txt2));  
txt3 = ((TextView) findViewById(R.id.txt3));  
//添加刪除線  
txt1.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);  
//在代碼中設(shè)置加粗  
txt2.getPaint().setFlags(Paint.FAKE_BOLD_TEXT_FLAG);  
//添加下劃線  
txt3.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);  

15.禁用截屏胸墙、錄屏

在onCreate中加入如下代碼:

this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, 
WindowManager.LayoutParams.FLAG_SECURE);

16.對于Application,Service按咒,Activity三者的Context的應(yīng)用場景

context.png

其中: NO1表示 Application 和 Service 需要?jiǎng)?chuàng)建一個(gè)新的 task 任務(wù)隊(duì)列迟隅,才可以啟動(dòng)一個(gè) Activity。即intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
而對于 Dialog 而言胖齐,只有在 Activity 中才能創(chuàng)建玻淑。

17.內(nèi)存泄漏總結(jié)

根本原因是:長生命周期的對象持有短生命周期對象的引用就很可能發(fā)生內(nèi)存泄漏,盡管短生命周期對象已經(jīng)不再需要呀伙,但是因?yàn)殚L生命周期持有它的引用而導(dǎo)致不能被回收补履。

可以這么理解,長生命周期A含有短生命周期B的引用剿另,此時(shí)需要回收B的內(nèi)存箫锤,但是因?yàn)锳(B),導(dǎo)致內(nèi)存無法回收雨女。

具體例子如下:

public class AppManager {
  private static AppManager instance;
  private Context context;
  private AppManager(Context context) {
    this.context = context;
  }
  public static AppManager getInstance(Context context) {
    if (instance == null) {
      instance = new AppManager(context);
    }
    return instance;
  }
}

1谚攒、如果此時(shí)傳入的是 Application 的 Context,因?yàn)?Application 的生命周期就是整個(gè)應(yīng)用的生命周期氛堕,所以這將沒有任何問題馏臭。

2、如果此時(shí)傳入的是 Activity 的 Context讼稚,當(dāng)這個(gè) Context 所對應(yīng)的 Activity 退出時(shí)括儒,由于該 Context 的引用被單例對象所持有,其生命周期等于整個(gè)應(yīng)用程序的生命周期锐想,所以當(dāng)前 Activity 退出時(shí)它的內(nèi)存并不會(huì)被回收帮寻,這就造成泄漏了。

場景

  1. 類的靜態(tài)變量持有大數(shù)據(jù)對象
    靜態(tài)變量長期維持到大數(shù)據(jù)對象的引用赠摇,阻止垃圾回收固逗。

  2. 非靜態(tài)內(nèi)部類的靜態(tài)實(shí)例
    非靜態(tài)內(nèi)部類會(huì)維持一個(gè)到外部類實(shí)例的引用,如果非靜態(tài)內(nèi)部類的實(shí)例是靜態(tài)的藕帜,就會(huì)間接長期維持著外部類的引用烫罩,阻止被回收掉。

  3. 資源對象未關(guān)閉
    資源性對象如Cursor洽故、File贝攒、Socket,應(yīng)該在使用后及時(shí)關(guān)閉收津。未在finally中關(guān)閉饿这,會(huì)導(dǎo)致異常情況下資源對象未被釋放的隱患。

  4. 注冊對象未反注冊
    未反注冊會(huì)導(dǎo)致觀察者列表里維持著對象的引用撞秋,阻止垃圾回收长捧。

  5. Handler臨時(shí)性內(nèi)存泄露
    Handler通過發(fā)送Message與主線程交互,Message發(fā)出之后是存儲(chǔ)在MessageQueue中的吻贿,有些Message也不是馬上就被處理的串结。在Message中存在一個(gè) target,是Handler的一個(gè)引用舅列,如果Message在Queue中存在的時(shí)間越長肌割,就會(huì)導(dǎo)致Handler無法被回收。如果Handler是非靜態(tài)的帐要,則會(huì)導(dǎo)致Activity或者Service不會(huì)被回收把敞。
    由于AsyncTask內(nèi)部也是Handler機(jī)制,同樣存在內(nèi)存泄漏的風(fēng)險(xiǎn)榨惠。
    此種內(nèi)存泄露奋早,一般是臨時(shí)性的。

18.RxJava的些許問題

  • doOnNext

    public Observable<TestBean> getInfor() {
        Observable observable = retrofitService.getInfor()
  //              .observeOn(Schedulers.io())
                .doOnNext(new Consumer<TestBean>() {
                    @Override
                    public void accept(@NonNull TestBean testBean) throws Exception {
                        Log.d("LKK", "doOnNext=========" + Thread.currentThread().getName());
                    }
                })
                .compose(this.toMain());
        return observable;
    }

doOnNext是在onNext()之前運(yùn)行的赠橙,并且默認(rèn)在io線程運(yùn)行耽装。
注意:observeOn必須指定在doOnNext之前才起作用。

1.png

  • doOnSubscribe

我們知道observeOn()可以多次調(diào)用期揪,實(shí)現(xiàn)線程的多次切換掉奄。但是subscribeOn()只是第一次的設(shè)置起作用。

l.jpg

從圖中可以看出凤薛,subscribeOn() 和 observeOn() 都做了線程切換的工作(圖中的 "schedule..." 部位)姓建。不同的是, subscribeOn() 的線程切換發(fā)生在 OnSubscribe 中枉侧,即在它通知上一級(jí) OnSubscribe 時(shí)引瀑,這時(shí)事件還沒有開始發(fā)送,因此 subscribeOn() 的線程控制可以從事件發(fā)出的開端就造成影響榨馁;而 observeOn() 的線程切換則發(fā)生在它內(nèi)建的 Subscriber 中憨栽,即發(fā)生在它即將給下一級(jí) Subscriber 發(fā)送事件時(shí),因此 observeOn() 控制的是它后面的線程翼虫。

這個(gè)時(shí)候要想subscribeOn起作用屑柔,需要用到Observable.doOnSubscribe() 。它和 Subscriber.onStart()同樣是在subscribe()調(diào)用后而且在事件發(fā)送前執(zhí)行珍剑,但區(qū)別在于它可以指定線程掸宛。默認(rèn)情況下, doOnSubscribe() 執(zhí)行在subscribe() 發(fā)生的線程招拙;而如果在 doOnSubscribe() 之后有 subscribeOn() 的話唧瘾,它將執(zhí)行后面離它最近的 subscribeOn() 所指定的線程措译。

19.如何避免后臺(tái)進(jìn)程被殺死

  • 調(diào)用startForegound,讓你的Service所在的線程成為前臺(tái)進(jìn)程
  • Service的onDestroy里面重新啟動(dòng)自己
  • Service的onStartCommond返回START_STICKYSTART_REDELIVER_INTENT
@Override  
   public int onStartCommand(Intent intent, int flags, int startId) {  
        ... ...
       return START_REDELIVER_INTENT;  
   }  

值得注意的是在onStartCommand中返回值饰序,常用的返回值有:START_NOT_STICKY领虹、START_SICKYSTART_REDELIVER_INTENT,這三個(gè)都是靜態(tài)常理值。

START_NOT_STICKY:表示當(dāng)Service運(yùn)行的進(jìn)程被Android系統(tǒng)強(qiáng)制殺掉之后求豫,不會(huì)重新創(chuàng)建該Service塌衰,如果想重新實(shí)例化該Service,就必須重新調(diào)用startService來啟動(dòng)蝠嘉。

使用場景:表示當(dāng)Service在執(zhí)行工作中被中斷幾次無關(guān)緊要或者對Android內(nèi)存緊張的情況下需要被殺掉且不會(huì)立即重新創(chuàng)建這種行為也可接受的話最疆,這是可以在onStartCommand返回值中設(shè)置該值。如在Service中定時(shí)從服務(wù)器中獲取最新數(shù)據(jù)

START_STICKY:表示Service運(yùn)行的進(jìn)程被Android系統(tǒng)強(qiáng)制殺掉之后蚤告,Android系統(tǒng)會(huì)將該Service依然設(shè)置為started狀態(tài)(即運(yùn)行狀態(tài))努酸,但是不再保存onStartCommand方法傳入的intent對象,然后Android系統(tǒng)會(huì)嘗試再次重新創(chuàng)建該Service罩缴,并執(zhí)行onStartCommand回調(diào)方法蚊逢,這時(shí)onStartCommand回調(diào)方法的Intent參數(shù)為null,也就是onStartCommand方法雖然會(huì)執(zhí)行但是獲取不到intent信息箫章。

使用場景:如果你的Service可以在任意時(shí)刻運(yùn)行或結(jié)束都沒什么問題烙荷,而且不需要intent信息,那么就可以在onStartCommand方法中返回START_STICKY檬寂,比如一個(gè)用來播放背景音樂功能的Service就適合返回該值终抽。

START_REDELIVER_INTENT:表示Service運(yùn)行的進(jìn)程被Android系統(tǒng)強(qiáng)制殺掉之后,與返回START_STICKY的情況類似桶至,Android系統(tǒng)會(huì)將再次重新創(chuàng)建該Service昼伴,并執(zhí)行onStartCommand回調(diào)方法,但是不同的是镣屹,Android系統(tǒng)會(huì)再次將Service在被殺掉之前最后一次傳入onStartCommand方法中的Intent再次保留下來并再次傳入到重新創(chuàng)建后的Service的onStartCommand方法中圃郊,這樣我們就能讀取到intent參數(shù)。

使用場景:如果我們的Service需要依賴具體的Intent才能運(yùn)行(需要從Intent中讀取相關(guān)數(shù)據(jù)信息等)女蜈,并且在強(qiáng)制銷毀后有必要重新創(chuàng)建運(yùn)行持舆,那么這樣的Service就適合返回START_REDELIVER_INTENT。

20.App蔽苯眩活

參考:https://blog.csdn.net/AndrExpert/article/details/75045678

币菰ⅲ活手段

當(dāng)前業(yè)界的Android進(jìn)程保活手段主要分為黑覆山、白竹伸、灰三種,其大致的實(shí)現(xiàn)思路如下:

黑色贝乜恚活:不同的app進(jìn)程勋篓,用廣播相互喚醒(包括利用系統(tǒng)提供的廣播進(jìn)行喚醒)
白色卑上恚活:啟動(dòng)前臺(tái)Service
灰色保活:利用系統(tǒng)的漏洞啟動(dòng)前臺(tái)Service

白色逼┫活與灰色卑颐铮活

①白色保活

  • 提升service優(yōu)先級(jí)

AndroidManifest.xml文件中對于intent-filter可以通過android:priority = “1000”這個(gè)屬性設(shè)置最高優(yōu)先級(jí)孤荣,1000是最高值,如果數(shù)字越小則優(yōu)先級(jí)越低须揣,同時(shí)適用于廣播盐股。

  • 服務(wù)設(shè)置為前臺(tái)進(jìn)程

白色保活手段非常簡單耻卡,就是調(diào)用系統(tǒng)api啟動(dòng)一個(gè)前臺(tái)的Service進(jìn)程疯汁,這樣會(huì)在系統(tǒng)的通知欄生成一個(gè)Notification,用來讓用戶知道有這樣一個(gè)app在運(yùn)行著卵酪,哪怕當(dāng)前的app退到了后臺(tái)幌蚊。就像QQ音樂那樣。

image.png
public ForeService extends Service{
    public void onCreate(){
        super.onCreate();
        //創(chuàng)建NOtification對象
        Notification notificatin=new Notification(R.drawable.icon,"前臺(tái)service",System.currentTImeMillis());
        Intent intent=new Intent(this,MainActivity.class);
        PendingIntent pending=PendingIntent.getActivity(this,0,intent,0);
        //為通知設(shè)置布局和數(shù)據(jù)
        notification.setLastestEventInfo(this,"","",pending);
        //將service設(shè)置為前臺(tái)service
        startForeground(1,notification);
    }
}

② 灰色崩?ǎ活

這種币缍梗活手段是應(yīng)用范圍最廣泛。它是利用系統(tǒng)的漏洞來啟動(dòng)一個(gè)前臺(tái)的Service進(jìn)程瘸羡,與普通的啟動(dòng)方式區(qū)別在于漩仙,它不會(huì)在系統(tǒng)通知欄處出現(xiàn)一個(gè)Notification,看起來就如同運(yùn)行著一個(gè)后臺(tái)Service進(jìn)程一樣犹赖。這樣做帶來的好處就是队他,用戶無法察覺到你運(yùn)行著一個(gè)前臺(tái)進(jìn)程(因?yàn)榭床坏絅otification),但你的進(jìn)程優(yōu)先級(jí)又是高于普通后臺(tái)進(jìn)程的。這樣在低內(nèi)存時(shí)被kill的幾率會(huì)低一些峻村。

方式按系統(tǒng)分為:

  • API<18 : 啟動(dòng)前臺(tái)service麸折,直接傳入一個(gè) new Notification()
  • API>18 : 同時(shí)啟動(dòng)兩個(gè)NOTICE_ID相同的前臺(tái)service,然后將后啟動(dòng)的service進(jìn)行stop操作粘昨。(對API大于18而言垢啼,startForeground()方法需要彈出一個(gè)可見通知,如果你覺得不爽雾棺,可以開啟另一個(gè)Service將通知欄移除)
/**前臺(tái)Service膊夹,使用startForeground 
 * 這個(gè)Service盡量要輕,不要占用過多的系統(tǒng)資源捌浩,否則 
 * 系統(tǒng)在資源緊張時(shí)放刨,照樣會(huì)將其殺死 
 */  
public class DaemonService extends Service {  
    private static final String TAG = "DaemonService";  
    public static final int NOTICE_ID = 100;  
  
    @Nullable  
    @Override  
    public IBinder onBind(Intent intent) {  
        return null;  
    }  

    @Override  
    public void onCreate() {  
        super.onCreate();  
        if(Contants.DEBUG)  
            Log.d(TAG,"DaemonService---->onCreate被調(diào)用,啟動(dòng)前臺(tái)service");  
        //如果API大于18尸饺,需要彈出一個(gè)可見通知  
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){  
            Notification.Builder builder = new Notification.Builder(this);  
            builder.setSmallIcon(R.mipmap.ic_launcher);  
            builder.setContentTitle("KeepAppAlive");  
            builder.setContentText("DaemonService is runing...");  
            startForeground(NOTICE_ID,builder.build());  
            // 如果覺得常駐通知欄體驗(yàn)不好  
            // 可以通過啟動(dòng)CancelNoticeService进统,將通知移除助币,oom_adj值不變  
            Intent intent = new Intent(this,CancelNoticeService.class);  
            startService(intent);  
        }else{  
            startForeground(NOTICE_ID,new Notification());  
        }  
    }  
  
  
    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {  
        // 如果Service被終止  
        // 當(dāng)資源允許情況下,重啟service  
        return START_STICKY;  
    }  
  
  
    @Override  
    public void onDestroy() {  
        super.onDestroy();  
        // 如果Service被殺死螟碎,干掉通知  
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){  
            NotificationManager mManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);  
            mManager.cancel(NOTICE_ID);  
        }  
        if(Contants.DEBUG)  
            Log.d(TAG,"DaemonService---->onDestroy眉菱,前臺(tái)service被殺死");  
        // 重啟自己  
        Intent intent = new Intent(getApplicationContext(),DaemonService.class);  
        startService(intent);  
    }  
}  
/** 移除前臺(tái)Service通知欄標(biāo)志,這個(gè)Service選擇性使用 
 * 
 * Created by jianddongguo on 2017/7/7. 
 * http://blog.csdn.net/andrexpert 
 */  
    
public class CancelNoticeService extends Service {  
    @Nullable  
    @Override  
    public IBinder onBind(Intent intent) {  
        return null;  
    }  
    
    @Override  
    public void onCreate() {  
        super.onCreate();  
    }  
    
    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {  
        if(Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2){  
            Notification.Builder builder = new Notification.Builder(this);  
            builder.setSmallIcon(R.mipmap.ic_launcher);  
            startForeground(DaemonService.NOTICE_ID,builder.build());  
            // 開啟一條線程掉分,去移除DaemonService彈出的通知  
            new Thread(new Runnable() {  
                @Override  
                public void run() {  
                    // 延遲1s  
                    SystemClock.sleep(1000);  
                    // 取消CancelNoticeService的前臺(tái)  
                    stopForeground(true);  
                    // 移除DaemonService彈出的通知  
                    NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);  
                    manager.cancel(DaemonService.NOTICE_ID);  
                    // 任務(wù)完成俭缓,終止自己  
                    stopSelf();  
                }  
            }).start();  
        }  
        return super.onStartCommand(intent, flags, startId);  
    }  
    
    @Override  
    public void onDestroy() {  
        super.onDestroy();  
    }  
}  
  • onDestroy方法里重啟service
  • 1像素

鎖屏?xí)r生成一個(gè)1像素的Activity在前臺(tái)運(yùn)行,保證不被系統(tǒng)殺死酥郭,解鎖時(shí)銷毀這個(gè)Activity

  • 雙進(jìn)程守護(hù)

顧名思義华坦,啟動(dòng)兩個(gè)Service互相監(jiān)聽,保證其中一個(gè)被殺死時(shí)不从,另一個(gè)將其拉起惜姐。

  • 播放音樂

Service在后臺(tái)播放一個(gè)無聲音樂,能夠保證不被系統(tǒng)殺死椿息。

當(dāng)然歹袁,后兩種方案需要設(shè)置onStartCommand的返回值為START_STICKYSTART_REDELIVER_INTENT

需要注意的是:
serviceonCreate只會(huì)執(zhí)行一次寝优,onBind也只會(huì)執(zhí)行一次条舔,onStartCommand可以執(zhí)行多次。
也就是說多次創(chuàng)建service乏矾,不管是再次調(diào)用bindService還是startService逞刷,onCreateonBind只會(huì)執(zhí)行一次,多次調(diào)用startService會(huì)多次執(zhí)行onstartCommand妻熊。

21.LruCache 替代 SoftReference (軟引用)

SoftReference 只有當(dāng)系統(tǒng)內(nèi)存不足時(shí)夸浅,GC清理時(shí)才會(huì)回收SoftReference標(biāo)注的引用。它并不能及時(shí)的清理已經(jīng)無用的引用對象扔役,回收是不可控的帆喇。

LruCache(Least Recently Used),最近最少使用算法亿胸。
當(dāng)成一個(gè) Map 用就可以了坯钦,只不過實(shí)現(xiàn)了 LRU 緩存策略。

private static final float ONE_MIB = 1024 * 1024;
// 7MB
private static final int CACHE_SIZE = (int) (7 * ONE_MIB);
private LruCache<String, Bitmap> bitmapCache;
this.bitmapCache = new LruCache<String, Bitmap>(CACHE_SIZE) {
    protected int sizeOf(String key, Bitmap value) {
        return value.getByteCount();
    }

    @Override
    protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
        ...
    }
};

注意
1.需要提供一個(gè)緩存容量作為構(gòu)造參數(shù)侈玄。
2.覆寫 sizeOf 方法 婉刀,自定義設(shè)計(jì)一條數(shù)據(jù)放進(jìn)來的容量計(jì)算,如果不覆寫就無法預(yù)知數(shù)據(jù)的容量序仙,不能保證緩存容量限定在最大容量以內(nèi)突颊。

因?yàn)?code>getByteCount要求的API版本較高,因此對于使用較低版本的開發(fā)者,getRowBytes() * getHeight()律秃。

LruCache原理

內(nèi)部由一個(gè)LinkedHashMap存儲(chǔ)緩存數(shù)據(jù)爬橡,而LinkedHashMap的特性是最新訪問的數(shù)據(jù)排在后面

例如:

public static final void main(String[] args) {
        LinkedHashMap<Integer, Integer> map = new LinkedHashMap<>(0, 0.75f, true);
        map.put(0, 0);
        map.put(1, 1);
        map.put(2, 2);
        map.put(3, 3);
        map.put(4, 4);
        map.put(5, 5);
        map.put(6, 6);
        map.get(1);
        map.get(2);

        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());

        }
    }

輸出結(jié)果:

0 0
3 3
4 4
5 5
6 6
1 1
2 2
image.png

即:當(dāng)LruCache空間滿了的時(shí)候棒动,去除LinkedHashMap的第一組數(shù)據(jù)(最舊的糙申,使用最少的),并將新的數(shù)據(jù)填加在最后(最新的)船惨。
map中的第一個(gè)元素就是最近最少使用的那個(gè)元素柜裸。

原文章:http://www.reibang.com/p/31ca573a59e0

22.ViewPager左右禁止滑動(dòng)

/**
 * 禁止左右滑動(dòng)
 * Created by LiuKuo at 2018/5/22
 */

public class CustomeViewPager extends ViewPager {
    /**
     * true:可以滑動(dòng);false:不能滑動(dòng)
     */
    private boolean isScoll;

    public CustomeViewPager(Context context) {
        this(context, null);
    }

    public CustomeViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return isScoll && super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return isScoll && super.onTouchEvent(ev);
    }

    public void setScoll(boolean scoll) {
        isScoll = scoll;
    }
}

23.OkHttp寫法

法1:

OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS)
       .readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS)
       .writeTimeout(DEFAULT_WRITE_TIME_OUT, TimeUnit.SECONDS)
       .addInterceptor(interceptor);
OkHttpClient client = bulider.build();

法2:

OkHttpClient client = new OkHttpClient().newBuilder()
       .connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS)
       .readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS)
       .writeTimeout(DEFAULT_WRITE_TIME_OUT, TimeUnit.SECONDS)
       .addInterceptor(interceptor)
       .build();

24.更換主題

@Override
    public View onCreateView(LayoutInflater inflater,
            @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        final Context contextThemeWrapper = new ContextThemeWrapper(
                getActivity(), isDay ? R.style.day : R.style.night);
        LayoutInflater localInflater = inflater
                .cloneInContext(contextThemeWrapper);
        View v = localInflater.inflate(R.layout.fragment_layout, container,
                false);
        return v;
    }

25.app包和v4包中的fragment的區(qū)別

1粱锐、app包中的fragment是在3.0之后才有的粘室,支持的版本太高。
2卜范、v4包中的Fragment可以兼容到1.6的版本。

所以鹿榜,日常使用時(shí)海雪,一般使用V4包中的fragment

補(bǔ)充:
學(xué)習(xí)Glide源碼時(shí)电湘,其中發(fā)現(xiàn).with()的源碼中延曙,

  • Activityandroid.app.Fragment歸為一類處理概作,他們都是3.0之后的。
  • FragmentActivityandroid.support.v4.app.Fragment歸一類處理湾宙,他們可以支持到1.6版本。

Fragment是Android 3.0以后的東西冈绊,為了在低版本中使用Fragment就要用到android-support-v4.jar兼容包,而FragmentActivity就是這個(gè)兼容包里面的侠鳄,它提供了操作Fragment的一些方法,其功能跟3.0及以后的版本的Activity的功能一樣死宣。

26.Android 5.0新增跳轉(zhuǎn)動(dòng)畫

1.gif.gif
Pair<View, String> p1 = Pair.create((View)holder.imgBg, "img_view_1");
Pair<View, String> p2 = Pair.create((View)holder.tvTitle, "title_1");
Pair<View, String> p3 = Pair.create((View)holder.tvBottom, "tv_bottom");
ActivityOptionsCompat options = ActivityOptionsCompat.
         makeSceneTransitionAnimation(Activity_2.this, p1,p2,p3);
startActivity(intent,options.toBundle());

xml布局

    <ImageView
        android:id="@+id/img_bg"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:src="@mipmap/skid_right_1"
        android:transitionName="img_view_1" />
    <ImageView
        android:id="@+id/img_bg"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent"
        android:scaleType="centerCrop"
        android:transitionName="img_view_1" />

27.RecyclerView的getViewForPosition和getChildAt區(qū)別

  • getViewForPosition(RecyclerView的方法)
    獲取的是RecyclerView順序的子元素伟恶。
  • getChildAt (ViewGroup的方法)
    獲取的是子View疊加出現(xiàn)的順序。

例如毅该,一個(gè)疊加顯示的RecyclerView(最上層顯示第1個(gè)子View)博秫,它的getViewForPosition(0)返回的是最上層的View,而getChildAt(0)返回的是最下層的子View眶掌,它只與顯示的層級(jí)有關(guān)挡育,和RecyclerView的順序無關(guān)。

28.伸縮效果的EditText

    <android.support.design.widget.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <EditText
            android:id="@+id/age"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="年齡"
            android:maxLines="1" />
    </android.support.design.widget.TextInputLayout>

29.startActivityForResult的使用

說起來丟人朴爬,真丟人即寒,這個(gè)我竟然搞混了!!蒿叠!不記下來不行

Activity1.class

Intent intent = new Intent(Activity1.this, Activity2.class);
startActivityForResult(intent, 1);

//返回接收處理
   @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        
    }

Activity2.class

Intent i = new Intent();
setResult(1, i);
finish();

說一下搞混的內(nèi)容:

  • 1.Activity2中的Intent明垢,不需要設(shè)置具體的Class。
  • 2.setResult語句不會(huì)直接返回市咽!不會(huì)返回痊银!不會(huì)返回,我竟然記成了它會(huì)直接返回 :( 施绎,需要調(diào)用finish()手動(dòng)關(guān)閉當(dāng)前頁面溯革,然后會(huì)回調(diào)onActivityResult

30.PorterDuff.Mode

官方給出的是兩個(gè)w,h相同的Bitmap疊加的效果谷醉,而不是一個(gè)Bitamp中致稀,兩個(gè)圖形的疊加效果,正確的為:


image.png

黃色的圓先畫俱尼,藍(lán)色的方塊后畫抖单。

https://blog.csdn.net/u013085697/article/details/52096703

31.Fragment通信

  • Fragment與Activity間通信

①Activity向Fragment發(fā)送信息(通過setArguments(Bundle)

Activity.class

FragmentTransaction transaction = mManager.beginTransaction();
RightFragment fragment = new RightFragment();
//創(chuàng)建Bundle對象
Bundle bundle = new Bundle();
//向Bundle輸入數(shù)據(jù)
bundle.putInt("data", 100);
//對fragment設(shè)置Bundle參數(shù)
fragment.setArguments(bundle);
transaction.replace(R.id.fl_content, fragment);
transaction.commit();

Fragment.class

Bundle bundle = getArguments();

當(dāng)然也可以通過接口的方式實(shí)現(xiàn)。

②Fragment向Activity發(fā)送信息

Fragment.class

//強(qiáng)制轉(zhuǎn)換為當(dāng)前Activity對象后遇八,直接調(diào)用它的方法
((MainActivity)getActivity()).test(String sss);

Activity.class

public void test(String s){
    Toast.makeText(this,s,Toast.LENGTH_LONG).show();
}

這種方式簡單粗暴矛绘,你也可以自己定義接口,如下:
Interface.class

public interface Listener {  
    void setText(String s);  
}  

Activity.class

public class MainActivity extends AppCompatActivity implements Listener {
    ... ...
    @Override
    public void setText(String s){
        Toast.makeText(this,s,Toast.LENGTH_LONG).show();
    }
}

Fragment.class

((Listener)getActivity()).setText(String sss);
  • Fragment與Fragment間通信

Fragment之間是不能直接通信的刃永,需要Activity來協(xié)助货矮。
Fragment1 -> Activity ->Fragment2

比如一個(gè)Activity有兩個(gè)Fragment,點(diǎn)擊左側(cè)Fragment1的按鈕斯够,右側(cè)Fragment2會(huì)變色囚玫。
Fragment1.class

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        ((MainActivity)getActivity()).setColor(red);
    }
}

MainActivity.class

public void setColor(int color){
    FragmentManager fm = getSupportFragmentManager();
    fragment2 = fm.findFragmentByTag("fragment2");
    fragment2.setColorChange(color);
}

Fragment2.class

private void setColorChange(int color){
    layout.setBackgroundColor(color);
}

32.GreenDao的使用

在工程的build.gradle中添加

dependencies {
     ... ...
     classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
}

在項(xiàng)目的build.gradle中添加

apply plugin: 'org.greenrobot.greendao'

android {
  ... ...
  greendao {
     //版本號(hào),升級(jí)時(shí)可配置
     schemaVersion 1
     //dao的包名读规,包名默認(rèn)是entity所在的包
     daoPackage 'com.example.common.dao'
     //生成數(shù)據(jù)庫文件的目錄
     targetGenDir 'src/main/java'
  }
}

dependencies {
  ... ...
  api 'org.greenrobot:greendao:3.2.2'
}

BaseApplication.class

public class BaseApplication extends Application {
    private static DaoSession mDaoSession;

    @Override
    public void onCreate() {
        super.onCreate();
        initGreenDao();
    }

    private void initGreenDao() {
        DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(this, "lk.db", null);
        SQLiteDatabase sqLiteDatabase = devOpenHelper.getWritableDatabase();
        DaoMaster daoMaster = new DaoMaster(sqLiteDatabase);
        mDaoSession = daoMaster.newSession();
    }

    public static DaoSession getDaoSession() {
        return mDaoSession;
    }
}

注意:如果不先創(chuàng)建相關(guān)Bean類的情況下抓督,是找不到DaoMaster相關(guān)的!J鳌本昏!

工具類

public class GdUserUtil {

    private static GdUserDao getDao() {
        DaoSession session = BaseApplication.getDaoSession();
        GdUserDao dao = session.getGdUserDao();
        return dao;
    }

    public static List<GdUser> queryAllData() {
        return getDao().loadAll();
    }

    public static List<GdUser> queryData(String name) {
        return getDao().queryBuilder().where(GdUserDao.Properties.Name.eq(name)).list();
    }

    public static void insertData(GdUser user) {
        getDao().insert(user);
    }

    public static void removeData(GdUser user) {
        getDao().delete(user);
    }

    public static void removeData(Long key) {
        getDao().deleteByKey(key);
    }

    public static void updateData(GdUser user) {
        getDao().update(user);
    }
}

報(bào)錯(cuò):android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: GD_USER._id
GdUser.class

@Entity
public class GdUser {
    @Id(autoincrement = true)
    private long id;
    private String name;
    private String age;
}

錯(cuò)誤原因就是。枪汪。涌穆。別打我:) 。雀久。宿稀。 id的類型必須設(shè)置為Long,大寫的L赖捌,是包裝類祝沸,不是基本數(shù)據(jù)類型矮烹,一定要注意。

報(bào)錯(cuò)
Re-download dependencies and sync project (requires network)
Stop Gradle build processes (requires restart)

官方給出的答案是:支持的最小gradle是2.3.2罩锐。
Please update your Android Gradle Plugin to 2.3.2 (com.android.tools.build:gradle:2.3.2). Version 2.2.x is not supported.

33. Handler內(nèi)存溢出問題


在Handler消息隊(duì)列 還有未處理的消息 / 正在處理消息時(shí)奉狈,此時(shí)若需銷毀外部類MainActivity,但由于上述引用關(guān)系涩惑,垃圾回收器(GC)無法回收MainActivity仁期,從而造成內(nèi)存泄漏。

解決方法:

private static class MyHandler extends Handler{
        // 定義 弱引用實(shí)例
        private WeakReference<Activity> reference;
        // 在構(gòu)造方法中傳入需持有的Activity實(shí)例
        public FHandler(Activity activity) {
            // 使用WeakReference弱引用持有Activity實(shí)例
            reference = new WeakReference<Activity>(activity); 
        }
        // 通過復(fù)寫handlerMessage() 從而確定更新UI的操作
        @Override
        public void handleMessage(Message msg) {
            Activity activity = reference.get();
            if(activity != null){
                ... ...
            }
        }
 }

注意handler.postDelayed()無法防止內(nèi)存溢出竭恬,最好使用sendMessage這種形式跛蛋。

PS:當(dāng)可能出現(xiàn)Handler內(nèi)存溢出時(shí),AS會(huì)提示痊硕。赊级。。

34.new Handler()和new Handler(Looper.getMainLooper())區(qū)別

如果你不帶參數(shù)的實(shí)例化:Handler handler = new Handler();會(huì)默認(rèn)用當(dāng)前線程的Looper對象岔绸。

一般而言理逊,如果你的Handler是要用來刷新UI的,那么就需要在主線程下運(yùn)行盒揉。

情況:

  • 刷新UI晋被,handler要用到主線程的Looper對象。那么在主線程Handler handler=new Handler();如果在其他非主線程也要滿足這個(gè)功能的話预烙,要Handler handler=new Handler(Looper.getMainLooper());

  • 不用刷新UI,只是處理消息道媚。當(dāng)前消息如果是主線程的話扁掸,Handler handler=new Handler();;非主線程的話最域,Looper.prepare(); Handler handler=new Handler();Looper.loop()或者Handler handler=new Handle(Looper.getMainLooper());

若是實(shí)例化的時(shí)候調(diào)用Looper.getMainLooper()就表示放到主線程中去處理谴分;若有不是的話,UI 線程默認(rèn)執(zhí)行過Loop.prepare()Loop.loop()镀脂,其他線程需要手動(dòng)調(diào)用這兩個(gè)牺蹄。否則會(huì)報(bào)錯(cuò)。

35.ImageView.ScaleType設(shè)置圖解

  1. android:scaleType=“center”
    保持原圖的大小薄翅,顯示在ImageView的中心沙兰。當(dāng)原圖的size大于ImageView的size時(shí),多出來的部分被截掉翘魄。
  2. android:scaleType=“center_inside”
    以原圖正常顯示為目的鼎天,如果原圖大小大于ImageView的size,就按照比例縮小原圖的寬高暑竟,居中顯示在ImageView中斋射。如果原圖size小于ImageView的size,則不做處理居中顯示圖片。
  3. android:scaleType=“center_crop”
    以原圖填滿ImageView為目的罗岖,如果原圖size大于ImageView的size涧至,則與center_inside一樣,按比例縮小桑包,直到寬或高等于ImageView的size南蓬,其余部分裁剪,居中填充滿顯示在ImageView上捡多。如果原圖size小于ImageView的size蓖康,則按比例拉升原圖的寬和高,直到寬或高等于ImageView的size垒手,其余部分裁剪蒜焊,填充滿ImageView居中顯示。
  4. android:scaleType=“matrix”
    不改變原圖的大小科贬,從ImageView的左上角開始繪制泳梆,超出部分做剪切處理。
  5. androd:scaleType=“fit_xy”
    把圖片按照指定的大小在ImageView中顯示榜掌,拉伸顯示圖片优妙,不保持原比例,填滿ImageView.
  6. android:scaleType=“fit_start”
    把原圖按照比例放大縮小到ImageView的高度憎账,顯示在ImageView的start(前部/上部)套硼。
  7. android:sacleType=“fit_center”
    把原圖按照比例放大縮小到ImageView的高度,顯示在ImageView的center(中部/居中顯示)胞皱。
  8. android:scaleType=“fit_end”
    把原圖按照比例放大縮小到ImageView的高度邪意,顯示在ImageVIew的end(后部/尾部/底部)

https://blog.csdn.net/larryl2003/article/details/6919513
https://blog.csdn.net/u012702547/article/details/50586946

36.getRawX和getX區(qū)別

37.WindowManager添加控件顯示懸浮框時(shí)遇到的問題

  • 1.默認(rèn)控件顯示的位置是正中間,這是因?yàn)橹虚g的坐標(biāo)為(0反砌,0)雾鬼。
  • 2.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;不設(shè)置的話,懸浮框始終獲取焦點(diǎn)宴树,此時(shí)無法操作策菜,桌面都回不到了。
  • 3.作touch設(shè)置時(shí)酒贬,要使用down和move的getRawX/Y的差值+lp.x/y又憨,不能直接使用getRawX/Y,因?yàn)榇藭r(shí)屏幕的左上角不是原點(diǎn)锭吨。

38.View的位置坐標(biāo)

View 提供了如下 5 種方法獲取 View 的坐標(biāo):

  • View.getTop()竟块、View.getLeft()、View.getBottom()耐齐、View.getRight();
  • View.getX()浪秘、View.getY();
  • View.getTranslationX()蒋情、View.getTranslationY();
  • View.getLocationOnScreen(int[] position);
  • View.getLocationInWindow(int[] position);
1. View.getTop()、View.getLeft()耸携、View.getBottom()棵癣、View.getRight()

需要注意的是,這四個(gè)方法獲取的坐標(biāo)表示的是View原始狀態(tài)時(shí)相對于父容器的坐標(biāo)夺衍,對View的平移操作不會(huì)改變這四個(gè)方法的返回值1芬辍!沟沙!

2. View.getX()河劝、View.getY()

getX()與getY()方法獲取的是View左上角相對于父容器的坐標(biāo),當(dāng)View沒有發(fā)生平移操作時(shí)矛紫,getX()==getLeft()赎瞎、getY==getTop()

3. View.getTranslationX()颊咬、View.getTranslationY()

translationXtranslationY是View左上角相對于父容器的偏移量:translationX = getX() - getLeft(),當(dāng)View未發(fā)生平移操作時(shí)务甥,translationXtranslationY都為0。

4. getLocationOnScreen

獲取View相對于整個(gè)屏幕的坐標(biāo)喳篇。

5. getLocationInWindow

獲取View相對于Window的坐標(biāo)(忽略狀態(tài)欄及ActionBar)敞临。


其中,getLocationInWindow是以B為原點(diǎn)的C的坐標(biāo)
其中麸澜,getLocationOnScreen是以A為原點(diǎn)的C的坐標(biāo)

getLocationOnScreen挺尿、getLocationInWindow區(qū)別

39.Activity的構(gòu)造方法

正如《Android Activity的啟動(dòng)和跳轉(zhuǎn)》一文所說,在Android APP中啟動(dòng)一個(gè)Activity都是通過startActivity()或startActivityForResult()來實(shí)現(xiàn)炊邦,并不會(huì)直接在APP代碼中new一個(gè)Activity對象來使用编矾,直接new出來的Activity對象是無法使用的。一般來說我們在實(shí)現(xiàn)一個(gè)Activity類時(shí)會(huì)將初始化的一些操作放到onCreate()中執(zhí)行铣耘,并不會(huì)實(shí)現(xiàn)其構(gòu)造方法洽沟。但是這并不是說Activity類沒有構(gòu)造方法以故,或者構(gòu)造方法不會(huì)被調(diào)用蜗细。

事實(shí)上,調(diào)用startActivity()或startActivityForResult()之后怒详,Android框架中的代碼會(huì)完成Activity對象的創(chuàng)建炉媒。在創(chuàng)建Activity對象時(shí)仍然會(huì)執(zhí)行Activity類的構(gòu)造方法。

在android.app.Instrumentation類中有一個(gè)newActivity方法昆烁。Android框架正是通過此方法來創(chuàng)建一個(gè)Activity對象的吊骤。其代碼如下。

public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
    return (Activity)cl.loadClass(className).newInstance();
}

可以看到静尼,這里通過ClassLoader的loadClass()方法來加載指定的Activity類白粉,得到對應(yīng)的Class對象传泊,然后再調(diào)用Class對象的newInstance()方法創(chuàng)建Activity對象。

由于Class對象的newInstance()方法在創(chuàng)建對象時(shí)會(huì)調(diào)用該類的無參構(gòu)造方法鸭巴,因此眷细,如果確實(shí)需要在Activity構(gòu)造的時(shí)候執(zhí)行一些操作,可以在這個(gè)Activity類中增加一個(gè)無參的構(gòu)造方法鹃祖,這個(gè)構(gòu)造方法會(huì)在newInstance()時(shí)被自動(dòng)調(diào)用溪椎。

這里有兩點(diǎn)需要注意:

  1. 一個(gè)Activity類中只有無參的構(gòu)造方法會(huì)被執(zhí)行,定義有參數(shù)的構(gòu)造方法是沒有意義的恬口。
  2. 一個(gè)Activity類中如果沒有無參構(gòu)造方法校读,或者無參構(gòu)造方法不是public的,則在執(zhí)行newInstance()的時(shí)候會(huì)產(chǎn)生異常祖能。

40.scrollTo 和scrollBy 相關(guān)問題

  • 每一個(gè)View中歉秫,系統(tǒng)都提供了scrollToscrollBy兩種方式來改變一個(gè)View的位置芯杀。這兩個(gè)方法的區(qū)別非常好理解端考,與英文中To與By的區(qū)別類似,scrollTo(x, y)標(biāo)識(shí)移動(dòng)到一個(gè)具體的坐標(biāo)點(diǎn)(x, y)揭厚,而scrollBy(dx, dy)表示移動(dòng)的增量為dx却特、dy。

但是筛圆,當(dāng)我們拖動(dòng)View的時(shí)候裂明,你會(huì)發(fā)現(xiàn)View并沒有移動(dòng)!難道是我們方法寫錯(cuò)了嗎太援?其實(shí)闽晦,方法并沒有寫錯(cuò),View也確實(shí)移動(dòng)了提岔,只是它移動(dòng)的并不是我們想要移動(dòng)的東西仙蛉。scrollToscrollBy方法移動(dòng)的是View的content碱蒙,即讓View的內(nèi)容移動(dòng)荠瘪,如果在ViewGroup中使用scrollToscrollBy方法赛惩,那么移動(dòng)的將是所有子View哀墓,但如果在View中使用,那么移動(dòng)的將是View的內(nèi)容喷兼,例如TextView篮绰,content就是它的文本;ImageView季惯,content就是它的drawable對象吠各。
相信通過上面的分析臀突,應(yīng)該知道為什么不能再View中使用這兩個(gè)方法來拖動(dòng)這個(gè)View了。那么我們就該View所有的ViewGroup中來使用scrollBy方法贾漏,移動(dòng)它的子View惧辈,代碼如下所示:
((View) getParent()).scrollBy(-offsetX,-offsetY);

注意:滾動(dòng)的正負(fù)號(hào)?拇伞:谐荨!@场(向上滾動(dòng)-offsetY边翁,向左滾動(dòng)-offsetX)

41.底部彈窗

1.PopupWindow實(shí)現(xiàn)底部彈窗
2.dialog實(shí)現(xiàn)底部彈窗
3.dialogFragment實(shí)現(xiàn)底部彈窗
4.BottomSheetDialog實(shí)現(xiàn)底部彈窗

http://www.reibang.com/p/8292fdbc4c2b

42.Activity動(dòng)畫

  1. 使用 style 的方式定義 Activity 的切換動(dòng)畫
  2. 使用 overridePendingTransition 方法實(shí)現(xiàn) Activity 跳轉(zhuǎn)動(dòng)畫
  3. 使用 ActivityOptions 切換動(dòng)畫實(shí)現(xiàn) Activity 跳轉(zhuǎn)動(dòng)畫(部分動(dòng)畫可支持到 api >= 16)
  4. 使用 ActivityOptions 動(dòng)畫共享組件的方式實(shí)現(xiàn)跳轉(zhuǎn) Activity 動(dòng)畫(api >= 21)

overridePendingTransition方法必須在startActivity的后面或者finish()之后被調(diào)用才生效。

43.PriorityQueue優(yōu)先級(jí)隊(duì)列

        PriorityQueue<BundleProxy> bundleQueue = new PriorityQueue<>(
                10,
                new Comparator<BundleProxy>() {
                    @Override
                    public int compare(BundleProxy o1, BundleProxy o2) {
                        return o2.getConfig().p.value() - o1.getConfig().p.value();
                    }
                }
        );

44.RecyclerView獲取滾動(dòng)距離

僅限于LinearLayout

public int getScollYDistance() {
       LinearLayoutManager layoutManager = (LinearLayoutManager) this.getLayoutManager();
       int position = layoutManager.findFirstVisibleItemPosition();
       View firstVisiableChildView = layoutManager.findViewByPosition(position);
       int itemHeight = firstVisiableChildView.getHeight();
       return (position) * itemHeight - firstVisiableChildView.getTop();
   }

45.mipmap

mipmap

46.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末硕盹,一起剝皮案震驚了整個(gè)濱河市符匾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瘩例,老刑警劉巖啊胶,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異垛贤,居然都是意外死亡焰坪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門聘惦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來某饰,“玉大人,你說我怎么就攤上這事善绎∏” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵禀酱,是天一觀的道長炬守。 經(jīng)常有香客問我,道長剂跟,這世上最難降的妖魔是什么减途? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮浩聋,結(jié)果婚禮上观蜗,老公的妹妹穿的比我還像新娘臊恋。我一直安慰自己衣洁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布抖仅。 她就那樣靜靜地躺著坊夫,像睡著了一般砖第。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上环凿,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天梧兼,我揣著相機(jī)與錄音,去河邊找鬼智听。 笑死羽杰,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的到推。 我是一名探鬼主播考赛,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼莉测!你這毒婦竟也來了颜骤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對情侶失蹤捣卤,失蹤者是張志新(化名)和其女友劉穎忍抽,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體董朝,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸠项,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了子姜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锈锤。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖闲询,靈堂內(nèi)的尸體忽然破棺而出久免,到底是詐尸還是另有隱情,我是刑警寧澤扭弧,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布阎姥,位于F島的核電站,受9級(jí)特大地震影響鸽捻,放射性物質(zhì)發(fā)生泄漏呼巴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一御蒲、第九天 我趴在偏房一處隱蔽的房頂上張望衣赶。 院中可真熱鬧,春花似錦厚满、人聲如沸府瞄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽遵馆。三九已至鲸郊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間货邓,已是汗流浹背秆撮。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留换况,地道東北人职辨。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像戈二,于是被迫代替她去往敵國和親拨匆。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,101評(píng)論 25 707
  • 本文出自 Eddy Wiki 挽拂,轉(zhuǎn)載請注明出處:http://eddy.wiki/interview-androi...
    eddy_wiki閱讀 3,267評(píng)論 0 20
  • 上一篇 一個(gè)神經(jīng)癥患者的自述(三) 陰轉(zhuǎn)多云惭每,今日略微能感受到陽關(guān)的溫存,氣溫正合適慵懶的看書喝茶亏栈。買了杯咖啡往咨...
    半畝方塘yx閱讀 745評(píng)論 3 10
  • 我已經(jīng)試了無數(shù)種方法台腥,想要回到熟睡的身體里去,可惜好像沒什么用绒北,只能坐在地上唉聲嘆氣黎侈。 “真笨”,一聲輕笑從...
    林清何閱讀 268評(píng)論 0 1
  • 本人摩羯女一枚休吠,喜歡研究星座。下面以本人的一些性格特點(diǎn)來分析摩羯座业簿,如果你也是摩羯座瘤礁,歡迎補(bǔ)充。 一梅尤、都說摩羯是工...
    哈兒莉閱讀 813評(píng)論 0 2