2020大厂面试集合,GitHub,百度,flutter下拉加载
由于Fragment的生命周期與Activity的生命周期有著牽扯,所以把兩者的圖放到一起作為對比理解。
[圖片上傳失敗…(image-a13b49-1601037655916)]
接下來就不同情況下的Fragment生命周期做一簡單介紹:
Fragment在Activity中replace
新替換的Activity:onAttach() —> onCreate() —> onCreatView() —> onViewCreated —> onActivityCreated() —> onStart —>onResume()
被替換的Activity:onPause() —> onStop() —> onDestoryView() —> onDestory() —> onDetach()
Fragment在Activity中replace,并addToBackStack
新替換的Fragment(沒有在BackStack中):onAttach?> onCreate >?onCreateView >?onViewCreated >?onActivityCreated >?onStart >?onResume
新替換的Fragment(已經在BackStack中):onCreateView > onViewCreated > onActivityCreated > onStart > onResume
被替換的Fragment:onPause > onStop > onDestroyView
Fragment在ViewPager中切換
我們稱切換前的的Fragment稱為PreviousFragment,簡稱PF;切換后的Fragment稱為NextFragment,簡稱NF;其他Fragment稱為OtherFragment,簡稱OF。
(在ViewPager中setUserVisibleHint能反映出Fragment是否被切換到后臺或前臺,所以在這里也當作生命周期)
- 如果相關的Fragment沒有被加載過:
NF: setUserVisibleHint(false)【用戶不可見】 > onAttach > onCreate > setUserVisibleHint(true)【用戶可見】 > onCreateView > onViewCreated > onActivityCreated > onStart > onResume
OF跟NF相鄰: setUserVisibleHint(false) > onAttach > onCreate > onCreateView > onViewCreated > onActivityCreated > onStart > onResume
- 如果相關的Fragment已經被加載過:
NF跟PF相鄰? :setUserVisibleHint(true)
NF跟PF不相鄰:setUserVisibleHint(true)?> onCreateView > onViewCreated > onActivityCreated > onStart > onResume
PF跟NF相鄰? :setUserVisibleHint(false)
PF跟NF不相鄰:setUserVisibleHint(false) > onPause > onStop > onDestroyView
OF跟PF相鄰:onPause > onStop > onDestroyView
OF跟NF相鄰:onCreateView > onViewCreated > onActivityCreated > onStart > onResume
OF夾在PF和NF中間:不調用任何生命周期方法
NF跟PF相鄰? :setUserVisibleHint(true)
NF跟PF不相鄰:setUserVisibleHint(true)?> onCreateView > onViewCreated > onActivityCreated > onStart > onResume
PF跟NF相鄰? :setUserVisibleHint(false)
PF跟NF不相鄰:setUserVisibleHint(false) > onPause > onStop > onDestroyView
OF跟PF相鄰:onPause > onStop > onDestroyView
OF跟NF相鄰:onCreateView > onViewCreated > onActivityCreated > onStart > onResume
OF夾在PF和NF中間:不調用任何生命周期方法
- 如果重寫了FragmentPagerAdapter的DestroyItem方法,并且相關的Fragment已經加載過:
相互切換時只會調用setUserVisibleHint
Fragment進入了運行狀態:
Fragment在進入運行狀態時,以下四個生命周期會隨它所屬的Activity一起被調用:
onPause() —> onStop() —> onStart() —> onResume()
關于Fragment的onActivityResult方法:
使用Fragment的startActivity方法時,FragmentActivity的onActivityResult方法會回調相應的Fragment的onActivityResult方法,所以在重寫FragmentActivity的onActivityResult方法時,注意調用super.onActivityResult。
8、?如何實現Fragment的滑動?
將Fragment與viewpager綁定,通過viewpager中的touch事件,會進行move事件的滑動處理。
Fragment布局
Fragment代碼:
public class FragmentOne extends Fragment { @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_one, container, false); }}
public class FragmentTwo extends Fragment { @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_Two, container, false); }}
viewpager布局:
xmlns:tools=“http://schemas.android.com/tools” android:layout_width=“match_parent” android:layout_height=“match_parent” tools:context=“com.example.spreadtrumshitaoli.fragmentscroll.MainActivity”> <android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_height=“match_parent” android:layout_width=“match_parent”/> </android.support.constraint.ConstraintLayout>
MainActivity代碼:
public class MainActivity extends AppCompatActivity { private FragmentOne fragmentOne; private FragmentTwo fragmentTwo; private ViewPager viewPager; private ArrayList mFragmentList = new ArrayList (); private FragmentPagerAdapter fragmentPagerAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } private void init() { viewPager = (ViewPager) findViewById(R.id.view_pager); fragmentOne = new FragmentOne(); fragmentTwo = new FragmentTwo(); mFragmentList.add(fragmentOne); mFragmentList.add(fragmentTwo); //將adapter和fragment綁定在一起。 fragmentPagerAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) { @Override public Fragment getItem(int i) { return mFragmentList != null ? mFragmentList.get(i) : null; } @Override public int getCount() { return mFragmentList != null ? mFragmentList.size() : 0; } }; viewPager.setAdapter(fragmentPagerAdapter); viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int i, float v, int i1) { } @Override public void onPageSelected(int i) { //TODO: } @Override public void onPageScrollStateChanged(int i) { } }); } }
在這段代碼中,我們
首先fragment以及viewpager都實例化;
再將fragment添加到泛型arraylist里;
最后將帶有fragment的arraylist和adapter綁定。
9、fragment之間傳遞數據的方式?
方法一:
-
1、在MainFragment中設置一個setData()方法,在方法中設置更改按鈕名稱;
-
//MainFragment.java文件中
-
public void setData(String string) {
-
bt_main.setText(string);
-
}
-
2、在MenuFragment中的ListView條目點擊事件中通過標簽獲取到MainFragment,并調用對應的setData()方法,將數據設置進去,從而達到數據傳遞的目的。
-
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-
@Override
-
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-
MainFragment mainFragment =
-
(MainFragment) getActivity()
-
.getSupportFragmentManager()
-
.findFragmentByTag("mainFragment");
-
mainFragment.setData(mDatas.get(position));
-
}
-
});
只需上面區區兩步即可達到數據傳遞的目的。
方法二:
采取接口回調的方式進行數據傳遞。
-
step1: 在Menuragment中創建一個接口以及接口對應的set方法:
-
//MenuFragment.java文件中
-
public interface OnDataTransmissionListener {
-
public void dataTransmission(String data);
-
}
-
public void setOnDataTransmissionListener(OnDataTransmissionListener mListener) {
-
this.mListener = mListener;
-
}
-
step2: 在MenuFragment中的ListView條目點擊事件中進行接口進行接口回調
-
//MenuFragment.java文件中
-
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-
@Override
-
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-
/**
-
* 方法二:采取接口回調的方式進行數據傳遞
-
*/
-
if (mListener != null) {
-
mListener.dataTransmission(mDatas.get(position));
-
}
-
}
-
});
-
step3: 在MainActivity中根據menuFragment獲取到接口的set方法,在這個方法中進行進行數據傳遞,具體如下:
-
//在MainActivity.java中
-
menuFragment.setOnDataTransmissionListener(new MenuFragment.OnDataTransmissionListener() {
-
@Override
-
public void dataTransmission(String data) {
-
mainFragment.setData(data); //注:對應的mainFragment此時應該要用final進行修飾
-
}
-
});
通過上面的三步也可以輕松做到Fragment數據之間的傳遞。
方法三:
使用三方開源框架:EventBus
那么問題來了:EventBus是個啥東西???
簡單來說,EventBus是一款針對Android優化的發布/訂閱(publish/subscribe)事件總線。主要功能是替代Intent,Handler,BroadCast在Fragment,Activity,Service,線程之間傳遞消息。簡化了應用程序內各組件間、組件與后臺線程間的通信。優點是開銷小,代碼更優雅,以及將發送者和接收者解耦。比如請求網絡,等網絡返回時通過Handler或Broadcast通知UI,兩個Fragment之間需要通過Listener通信,這些需求都可以通過EventBus實現。
下面我們就用EventBus來實現以下Fragment之間的數據傳遞:
- step1:引入EventBus
- step2:注冊事件接收者
這里MainFragment是要接收MenuFragment發送來的數據,所以我們在MainFragment中的onCreateView()方法中進行注冊:
-
step3:發送事件
注:發送事件之前其實還有一步定義事件類型,這里我們傳遞的數據只有一個類型,所以這一步取消了。
MenuFragment發送數據給MainFragment,所以我們在MenuFragment中將要傳遞的數據進行發送事件操作: -
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
-
@Override
-
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-
EventBus.getDefault().post(mDatas.get(position));
-
}
-
});
-
step4:接收消息并處理
在MainFragment中我們接收來自MenuFragment傳遞過來的數據,并進行對應的處理(注:EventBus 3.0版本這一步必須要寫注解@Subscribe (與2.4版本有所區別)): -
@Subscribe
-
public void onEvent(String data) {
-
bt_main.setText(data);
-
}
通過上面這一步即可完成數據之間的傳遞,需要注意的是在銷毀的時候我們要注銷事件接收。
-
step5:注銷事件接收
-
//MainFragment.java中
-
@Override
-
public void onDestroy() {
-
super.onDestroy();
-
EventBus.getDefault().unregister(this);
-
}
以上五步完成了Fragment之間的數據傳遞,看似比上面兩個方法要復雜的多,但當我們涉及到復雜的Fragment之間數據傳遞(例如Fragment中嵌套多層Fragment)時,就會體會到EventBus的爽快之處~~~這里不進行贅述了。
10、Activity 怎么和Service 綁定?
這需要實現service中的onBind()函數以返回service實例給activity
1、創建service類和activity類。
2、在service類中定義一個內部類繼承自Binder()類:
public?class?MyBinder?extends?Binder{
public?Service1?getService(){
return?Service1.this;
}
} ?
實例化onBind()方法:
private final IBinder binder = new MyyBinder();
@Override
public IBinder onBind(Intent intent){
Log.i(LOG,“onBind…”);
return binder;
}
3、在activity中完成綁定
Intent intent = new Intent(Activity1.this,Activity2.class);
bindService(intent,conn,Context.BIND_AUTO_CREATE);
- bindService的第二個參數是一個ServiceConnection類型的參數。service和其他組件之間的連接都表示為一個ServiceConnection,要想將service和其他組件進行綁定,就需要實現一個新的ServiceConnection。
public?ServiceConnection?conn=?new?ServiceConnection()?{
@Override
public?void?onServiceDisconnected(ComponentName?name)?{
//當連接意外斷開時調用
Log.i(LOG,?“onServiceDisconnected>>>>>>>>”);
myservice?=?null;
}
@Override
public?void?onServiceConnected(ComponentName?name,?IBinder?service)?{
//當建立連接時調用
Log.i(LOG,?“onServiceConnected>>>>>>>>”);
myservice?=?((Service1.MyBinder)service).getService();
}
};
- bindService的第三個參數是一個flag。
可以使用的flag有:
BIND_AUTO_CREATE:綁定完成后就啟動目標service
BIND_DEBUG_UNBIND:這只在debug時使用,跟unbind有關。
BIND_NOT_FOREGROUND:確保被綁定的service永遠不會有運行于前臺的優先級,因為默認情況下,綁定一個service會提高它的優先級
BIND_ABOVE_CLIENT:確保客戶端處于前臺時,綁定的service也變
《Android學習筆記總結+最新移動架構視頻+大廠安卓面試真題+項目實戰源碼講義》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整內容開源分享
為前臺進程
BIND_ALLOW_OOM_MANAGEMENT:允許系統在低內存等狀態下刪除該service(這是自己對源碼中注釋的理解)
BIND_WAIVE_PRIORITY:綁定service時不改變其優先級
BIND_ADJUST_WITH_ACTIVITY:系統根據service所綁定的activity的重要程度來調整這個service的優先級。
11、service生命周期?
1.??? 被啟動的服務(startService())的生命周期。
???????????? 如果一個Service被某個Activity 調用Context.startService() 方法啟動,那么不管是否有Activity使用bindService()綁定或unbindService()解除綁定到該Service,該Service都在后臺運行。如果一個Service被多次執行startService(),它的onCreate()方法只會調用一次,也就是說該Service只會創建一個實例,而它的onStartCommand()將會被調用多次(對應調用startService()的次數)。該Service將會一直在后臺運行,直到被調用stopService(),或自身的stopSelf方法。當然如果系統資源不足,系統也可能結束服務。
2.??? 被綁定的服務(bindService())的生命周期。
???????????? 如果一個Service被調用?Context.bindService ()方法綁定啟動,不管調用bindService()調用幾次,onCreate()方法都只會調用一次,而onStartCommand()方法始終不會被調用,這時會調用onBind()方法。當連接建立之后,Service將會一直運行,除非調用Context.unbindService() 斷開連接或者之前調用bindService() 的 Context 不存在了(如該Activity被finish),系統將會自動停止Service,對應onDestroy()將被調用。
3.??? 被啟動又被綁定的服務的生命周期。
?????????????如果一個Service又被啟動又被綁定,則該Service將會一直在后臺運行。調用unbindService()將不會停止Service,而必須調用stopService()或Service的stopSelf()方法來停止服務。
4.?? 當服務被停止時清除服務。
??????????? 當一個Service被終止時,Service的onDestroy()方法將會被調用,在這里應當做一些清除工作,如停止在Service中創建并運行的線程等。
12、 activity和service的綁定方式以及怎么在Activity 中啟動自己對應的Service?
1、activity能進行綁定得益于Serviece的接口。為了支持Service的綁定,實現onBind方法。
2、Service和Activity的連接可以用ServiceConnection來實現。需要實現一個新的ServiceConnection,重現onServiceConnected和OnServiceDisconnected方法,一旦連接建立,就能得到Service實例的引用。
3、執行綁定,調用bindService方法,傳入一個選擇了要綁定的Service的Intent(顯示或隱式)和一個你實現了的ServiceConnection的實例
13、Service的啟動方式?
采用**Context.startService()**方法啟動服務,在服務未被創建時,系統會先調用服務的onCreate()方法,接著調用onStart()方法。如果調用startService()方法前服務已經被創建,多次調用startService()方法并不會導致多次創建服務,但會導致多次調用onStart()方法。采用startService()方法啟動的服務,只能調用Context.stopService()方法結束服務,服務結束時會調用onDestroy()方法。
采用**Context.bindService()**方法啟動服務,在服務未被創建時,系統會先調用服務的 onCreate()方法,接著調用onBind()方法。這個時候調用者和服務綁定在一起,調用者退出了,系統就會先調用服務的onUnbind()方 法,接著調用onDestroy()方法。如果調用bindService()方法前服務已經被綁定,多次調用bindService()方法并不會導致 多次創建服務及綁定(也就是說onCreate()和onBind()方法并不會被多次調用)。如果調用者希望與正在綁定的服務解除綁定,可以調用 unbindService()方法,調用該方法也會導致系統調用服務的onUnbind()–>onDestroy()方法。
14、談談ContentProvider、ContentResolver、ContentObserver之間的關系?
ContentProvider:
-
四大組件的內容提供者,主要用于對外提供數據
-
實現各個應用程序之間的(跨應用)數據共享,比如聯系人應用中就使用了ContentProvider,你在自己的應用中可以讀取和修改聯系人的數據,不過需要獲得相應的權限。其實它也只是一個中間人,真正的數據源是文件或者SQLite等
-
一個應用實現ContentProvider來提供內容給別的應用來操作,通過ContentResolver來操作別的應用數據,當然在自己的應用中也可以
ContentResolver:
-
內容解析者,用于獲取內容提供者提供的數據
-
ContentResolver.notifyChange(uri)發出消息
ContentObserver:
-
內容監聽器,可以監聽數據的改變狀態
-
目的是觀察(捕捉)特定Uri引起的數據庫的變化,繼而做一些相應的處理,它類似于數據庫技術中的觸發器(Trigger),當ContentObserver所觀察的Uri發生變化時,便會觸發它。觸發器分為表觸發器、行觸發器,相應地ContentObsever也分為表ContentObserver、行ContentObserver,當然這是與它所監聽的Uri MIME Type有關的
-
ContentResolver.registerContentObserver()監聽消息
15、廣播的分類?
分為有序廣播和無序廣播兩類。
- 無序廣播發送代碼:
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void click(View v){ //啟動界面 startActivity //發送廣播 sendBroadcast Intent intent = new Intent(); intent.setAction(“com.itheima.cctv.action.NEWS”); intent.putExtra(“data”, “我是一個無須的廣播”); sendBroadcast(intent); }}
- 無序廣播的監聽代碼:
public class CctvReceiver extends BroadcastReceiver { private static final String TAG = “CctvReceiver”; @Override public void onReceive(Context context, Intent intent) { String data = intent.getStringExtra(“data”); Log.d(TAG, “data===”+data); } }
- 有序廣播發送:
有序接收:
public class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.d(“vivi”, “我是恩恩主席的內線,我收到的指令是:”+getResultData()); } }
啟動模式:
1、standard:標準化啟動模式
每啟動一個Activity,都會重新創建Activity的新的實例,將其放在棧的頂部。不需要考慮這個實例是否已經存在。
每一次啟動,它的onCreate()、onStart()、onResume()方法都會被依次調用。
2、singleTop:棧頂復用模式
當前棧中已經有該Activity實例,并且該實例位于棧頂時,會去調用onNewIntent()方法。
當前棧中已有該Activity的實例但是該實例不在棧頂時,依然會去創建Activity。
當前棧中不存在該Activity實例時,會去新創建一個該Activity。
應用場景:IM對話框、新聞客戶端推送。
3、singleTask:棧內復用模式
它主要檢測【尋找,通過taskAffinity】整個棧中是否已經存在當前想要啟動的Activity,存在的話直接將該Activity置于棧頂,之前位于該Activity上面的Activity將被銷毀,同時調用onNewIntent()方法,而不存在的話進行創建。
應用場景:應用主界面。
4、singleInstance:
一個人獨享一個任務棧。當該Activity啟動時,系統會創建一個新的任務棧,同時將Activity放到這個新的任務棧當中,有別的應用來啟動該Activity時,由于棧內復用的特性,不會再去創建相應Activity任務棧,而是這兩個應用獨享一個Activity實例。
例如:應用A中現有兩個Activity E、Activity F,為standard啟動模式,應用B中有一個Activity G,但其啟動模式是singleInstance。應用A想用應用B任務棧當中的Activity G,盡管在不同的應用下,但是應用A仍然會直接復用Activity G。
特性:
1、以SingleInstance模式啟動的Activity具有全局唯一性【全局唯一性即指在整個系統當中只會存在一個這樣的實例】;
2、如果在啟動這樣一個Activity時,【整個系統都是單例的】,已經存在了一個實例;
3、以SingleInstance模式啟動的Activity具有獨占性。
應用場景:呼叫來電。
問題:onNewIntent()調用時機?
- singleTop:如果新Activity已經位于任務棧的棧頂,就不會重新創建,并回調?onNewIntent(intent)?方法。
- singleTask:只要該Activity在一個任務棧中存在,都不會重新創建,并回調?onNewIntent(intent)?方法。
網絡協議:
協議:【協議指計算機通信網絡中兩臺計算機之間進行通信所必須共同遵守的規定或規則】
HTTP協議
基本概念:【超文本傳輸協議】允許將HTML(超文本標記語言)文檔從Web服務器傳送到客戶端的瀏覽器。HTTP協議是 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 基于TCP/IP通信協議來傳輸數據的,可以從服務器端獲取圖片等數據資源。
URI:【uniform resource identifier】統一的資源標識符,用來唯一的標識一個資源。強調資源!!!
組成部分:
1)訪問資源的命名機制;file
2)存放資源的主機名;
總結
以上是生活随笔為你收集整理的2020大厂面试集合,GitHub,百度,flutter下拉加载的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ubuntu中vim编辑模式退格键无法删
- 下一篇: 干货!基于元消歧的偏多标记学习