Android Activity 面試那些事

學(xué)習(xí)剛要

Activity是與用戶交互的接口
Android系統(tǒng)是通過(guò)Activity棧的形式來(lái)管理Activity

下面我將會(huì)從以下幾個(gè)方面對(duì)Activity進(jìn)行總結(jié):

  • Activity的四種展示形態(tài)
  • Activity的啟動(dòng)模式
  • Activity的生命周期
  • Activity組件之間的通信

Activity四種形態(tài)

  1. Active(Activity處于棧頂)
  2. Paused (可見(jiàn)但不可交互,只是失去和用交互的能力)
  3. Stopped (不可見(jiàn),被另一個(gè)Activity完全覆蓋,在內(nèi)存足夠時(shí),數(shù)據(jù)、狀態(tài)、變量都被保存,內(nèi)存不足時(shí),數(shù)據(jù)、狀態(tài)、變量被系統(tǒng)回收掉)
  4. killed (系統(tǒng)回收掉)

Activity啟動(dòng)模式

  1. Standard
    系統(tǒng)默認(rèn)的啟動(dòng)模式,Activity可多次被實(shí)例化,一個(gè)任務(wù)棧中會(huì)有多個(gè)實(shí)例。
    應(yīng)用場(chǎng)景:系統(tǒng)默認(rèn)

  2. SingleTop
    SingleTop分兩種情況:一種情況是Activity位于棧頂,另一種是Activity不在棧頂時(shí),但存在于棧中。

    • 當(dāng)Activity在棧頂時(shí),啟用Activity,不會(huì)創(chuàng)建新的實(shí)例,并重用棧頂?shù)腁ctivity,通過(guò)onNewIntent()將Intent對(duì)象傳入這個(gè)實(shí)例中。
    • 當(dāng)Activity不在棧頂時(shí),但存在于棧中,會(huì)啟用與standard相同的模式

    應(yīng)用場(chǎng)景:IM對(duì)話框,新聞客戶端推送

  3. SingleTask
    首先會(huì)根據(jù)taskAffinity(任務(wù)相關(guān)性)去尋找當(dāng)前是否存在一個(gè)對(duì)應(yīng)名字的任務(wù)棧,如果不存在,則建一個(gè)新的task放于棧頂,如果存在,則得到該任務(wù)棧,查找該任務(wù)棧中是否存在該Activity實(shí)例,若存在,系統(tǒng)會(huì)銷毀在Activity上的所有的Activity,最終使Activity置于棧頂,再回調(diào)onNewIntent()函數(shù)

    應(yīng)用場(chǎng)景:應(yīng)用的主界面

  4. SingleInstance
    Activity會(huì)在一個(gè)獨(dú)立的任務(wù)中啟動(dòng),并且在這個(gè)棧中只有這一個(gè)實(shí)例,而被該實(shí)例啟動(dòng)的其他Activity會(huì)自動(dòng)運(yùn)行在另一個(gè)任務(wù)中,再次啟動(dòng)時(shí)該實(shí)例會(huì)重用已存在的任務(wù)和實(shí)例,在AndroidManifest文件中的lauchMode屬性中設(shè)置。

    特性:

    • 以SingleInstance模式啟動(dòng)的Activity具有全局唯一性
    • 以SingleInstance模式啟動(dòng)的Activity具有獨(dú)占性

    應(yīng)用場(chǎng)景:呼叫來(lái)電

Activity生命周期

Activity正常情況下的周期調(diào)用

Activity的生命周期就是Activity從創(chuàng)建到銷毀的一個(gè)過(guò)程,仿佛我們?nèi)藦某錾剿劳鲆粯印?/p>

Activity生命周期的方法:
  • onCreate();創(chuàng)建
  • onStart();運(yùn)行
  • onResume();獲取焦點(diǎn)
  • onPause();失去焦點(diǎn)
  • onStop();暫停
  • onDestroy();銷毀
  • onRestart();重運(yùn)行
單個(gè)Activity的多種變化形式:
  • 從無(wú)到有創(chuàng)建一個(gè)Activity
  • 當(dāng)前的Activity失去焦點(diǎn)
  • 從當(dāng)前的Activity跳轉(zhuǎn)到另一個(gè)Activity
  • 當(dāng)前Activity被置入后臺(tái)

從創(chuàng)建一個(gè)Activity到銷毀的生命周期:

  1. 一個(gè)Activity剛創(chuàng)建時(shí)候的生命周期:

onCreate() ——> onStart() ——> onResume()

  1. Activity從創(chuàng)建到銷毀的生命周期:

onCreate() ——> onStart() ——> onResume() ——>onPause() ——> onStop() ——> onDestroy()

  1. Activity從啟動(dòng)到失去焦點(diǎn)生命周期:

onCreate() ——> onStart() ——> onResume() ——> onPause()

  1. Activity從啟動(dòng)到失去焦點(diǎn),再到獲取焦點(diǎn)的生命周期:

onCreate() ——> onStart() ——> onResume() ——> onPause() ——> onResume()

  1. Activity從啟動(dòng)到后臺(tái)的生命周期:

onCreate() ——> onStart() ——> onResume() ——> onPause() ——>onStop()

  1. Activity從啟動(dòng)到后臺(tái),再到前臺(tái)的生命周期:

onCreate() ——> onStart() ——> onResume() ——> onPause() ——> onStop() ——> onRestart() ——> onStart() ——>onResume()

onStart()、onStop() 、 onResume()、 onPause() 的區(qū)別:
onStart和onStop是從Activity是否可見(jiàn)這個(gè)角度來(lái)回調(diào)的,而onResume和onPause是從Activity是否位于前臺(tái)這個(gè)角度來(lái)回調(diào)的。

兩個(gè)Activity從創(chuàng)建到銷毀

有兩個(gè)Activity,分別為A和B,在A已經(jīng)創(chuàng)建的情況下,創(chuàng)建B頁(yè)面,這里可能會(huì)出現(xiàn)兩種情況:

  • 頁(yè)面B完全遮擋住頁(yè)面A
  • 頁(yè)面B沒(méi)有完全遮擋住頁(yè)面A
頁(yè)面B完全遮擋住頁(yè)面A

當(dāng)頁(yè)面B完全遮擋住頁(yè)面A時(shí)的生命周期:


頁(yè)面B完全遮擋住頁(yè)面A.gif
頁(yè)面B完全遮擋住頁(yè)面A.png
頁(yè)面B沒(méi)有完全遮擋住頁(yè)面A

將B頁(yè)面設(shè)為透明的,在AndroidManifest.xml中設(shè)置

android:theme="@android:style/Theme.Translucent"

當(dāng)頁(yè)面B沒(méi)有完全遮擋住頁(yè)面A時(shí)的生命周期:

頁(yè)面B沒(méi)有完全遮擋住頁(yè)面A .gif
頁(yè)面B沒(méi)有完全遮擋住頁(yè)面A.png

從這兩種情況可以看到,當(dāng)頁(yè)面A沒(méi)有被遮擋的時(shí)候,是不走onStop() 方法的,并且在開啟一個(gè)新的頁(yè)面B之前,頁(yè)面A會(huì)先執(zhí)行onPause() 方法。

Activity異常情況下的周期調(diào)用

異常情況下多了兩個(gè)方法:onSaveInstanceState(),onRestoreInstanceState(),這兩個(gè)方法是出現(xiàn)異常情況下系統(tǒng)自動(dòng)調(diào)用的,通常 onSaveInstanceState() 只適合用于保存一些臨時(shí)性的狀態(tài),而 onPause() 適合用于數(shù)據(jù)的持久化保存。當(dāng)Activity被重新創(chuàng)建后,系統(tǒng)會(huì)調(diào)用 onRestoreInstanceState() 方法,此方法會(huì)將Activity銷毀時(shí)通過(guò) onSaveInstanceState() 保存的bundle對(duì)象作為一個(gè)對(duì)象傳給 onRestoreInstanceState() 方法,同時(shí)也會(huì)傳遞給 onCreate() 方法。

onRestoreInstanceState() 方法與 onCreate() 方法都可以進(jìn)行數(shù)據(jù)恢復(fù),他兩區(qū)別在于:onRestoreInstanceState()傳入的參數(shù)一定不能為空,onCreate() 傳入的參數(shù)有可能為空,所以使用onRestoreInstanceState() 進(jìn)行數(shù)據(jù)恢復(fù)比較好。

onRestoreInstanceState() 方法在 onStart() 之后執(zhí)行,onSaveInstanceState() 方法在 onPause() 之后執(zhí)行。

下面看個(gè)橫豎屏切換的小例子觀察下onRestoreInstanceState()方法的調(diào)用

public class ReviewActivity extends AppCompatActivity {
    private final String TAG = ReviewActivity.class.getSimpleName();
    private static final String TURN = "turn";
    @BindView(R.id.et_name)
    EditText mEtName;
    @BindView(R.id.tv_show)
    TextView mTvShow;

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        Log.d(TAG, "onRestoreInstanceState: " + "調(diào)用onRestoreInstanceState");
        super.onRestoreInstanceState(savedInstanceState);
        mTvShow.setText(savedInstanceState.getString(TURN));
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate: 調(diào)用onCreate");

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_review);
        
        ButterKnife.bind(this);
    }

    @Override
    protected void onStart() {
        Log.d(TAG, "onStart: 調(diào)用onStart");
        super.onStart();
    }

    @Override
    protected void onResume() {
        Log.d(TAG, "onResume: 調(diào)用onResume");
        super.onResume();
    }

    @Override
    protected void onRestart() {
        Log.d(TAG, "onRestart: 調(diào)用onRestart");
        super.onRestart();
    }

    @Override
    protected void onPause() {
        Log.d(TAG, "onPause: 調(diào)用onPause");
        super.onPause();
    }

    @Override
    protected void onStop() {
        Log.d(TAG, "onStop: 調(diào)用onStop");
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        Log.d(TAG, "onDestroy: 調(diào)用onDestroy");
        super.onDestroy();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        Log.d(TAG, "onSaveInstanceState: 調(diào)用onSaveInstanceState");
        super.onSaveInstanceState(outState);
        outState.putString(TURN, mEtName.getText().toString());

    }

    @OnClick(R.id.bt_sure)
    public void onViewClicked() {
        mTvShow.setText(mEtName.getText().toString());
    }

}

運(yùn)行后的效果:

操作細(xì)節(jié)
結(jié)果展示

最后防止重新創(chuàng)建activity:
可以在AndroidManifest.xml中指定configChange屬性來(lái)不讓系統(tǒng)重新創(chuàng)建

 <activity
            android:name=".activity.ReviewActivity"
            android:configChanges="orientation|screenSize" />
  /**
     * @param newConfig :
     * @return : void
     * @date 創(chuàng)建時(shí)間: 2018/12/1
     * @author lady_zhou
     * @Description  activity不被重建
     */
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        Log.d(TAG, "onConfigurationChanged: 切屏防止activity調(diào)用onSaveInstanceState");
        super.onConfigurationChanged(newConfig);
    }
操作細(xì)節(jié)
結(jié)果展示
Activity與Fragment生命周期關(guān)系

從創(chuàng)建一個(gè)含有Fragment的Activity到 銷毀的生命周期:

Fragment生命周期的方法:
  • onAttach();fragment已經(jīng)關(guān)聯(lián)到activity,只調(diào)用一次
  • onCreate();系統(tǒng)創(chuàng)建fragment的時(shí)候回調(diào)他,只調(diào)用一次
  • onCreateView();繪制layout
  • onActivityCreated();當(dāng)Activity中的onCreate方法執(zhí)行完后調(diào)用。
  • onStart();運(yùn)行
  • onResume();獲取焦點(diǎn)
  • onPause();失去焦點(diǎn)
  • onStop();暫停
  • onDestroyView();Fragment中的布局被移除時(shí)調(diào)用
  • onDestroy();銷毀
  • onDetach();Fragment和Activity解除關(guān)聯(lián)的時(shí)候調(diào)用
與Activity一樣Fragment也有的多種變化形式:
  • 從無(wú)到有創(chuàng)建一個(gè)Fragment
  • 當(dāng)前Activity被置入后臺(tái)
  1. 剛創(chuàng)建時(shí)候的生命周期:

Activity中onCreate()——>Activity中onStart()——>Fragment中onAttach()——>Fragment中onCreate()——>Fragment中onCreateView()——>Fragment中onActivityCreated()——>Fragment中onStart()——>Activity中onResume()——> Fragment中onResume()

  1. 從創(chuàng)建到銷毀的生命周期:

Activity中onCreate()——>Activity中onStart()——>Fragment中onAttach()——>Fragment中onCreate()——>Fragment中onCreateView()——>Fragment中onActivityCreated()——>Fragment中onStart()——>Activity中onResume()——> Fragment中onResume()——>Activity中onPause()——>Fragment中onPause()——>Activity中onStop()——>Fragment中onStop()——>Activity中onDestroy()——>Fragment中onDestroyView()——>Fragment中onDestroy()——>Fragment中onDetach()

  1. 從啟動(dòng)到后臺(tái)的生命周期:

Activity中onCreate()——>Activity中onStart()——>Fragment中onAttach()——>Fragment中onCreate()——>Fragment中onCreateView()——>Fragment中onActivityCreated()——>Fragment中onStart()——>Activity中onResume()——> Fragment中onResume()——>Activity中onPause()——>Fragment中onPause()——>Activity中onSaveInstanceState()——>Activity中onStop()——>Fragment中onStop()

  1. 從啟動(dòng)到后臺(tái),再到前臺(tái)的生命周期:

Activity中onCreate()——>Activity中onStart()——>Fragment中onAttach()——>Fragment中onCreate()——>Fragment中onCreateView()——>Fragment中onActivityCreated()——>Fragment中onStart()——>Activity中onResume()——> Fragment中onResume()——>Activity中onPause()——>Fragment中onPause()——>Activity中onSaveInstanceState()——>Activity中onStop()——>Fragment中onStop()——>Activity中onRestart()——>Activity中onStart()——>Fragment中onStart()——>Activity中onResume()——> Fragment中onResume()

public class ActivityToFragmentActivity extends AppCompatActivity implements MyFragment.FragmentCallBack {
    private static final String TAG = "Fragment";
    @BindView(R.id.tv_back)
    TextView mTvBack;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "Activity: 調(diào)用onCreate");

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_to_fragment);
        ButterKnife.bind(this);

        FragmentManager fragmentManager = getSupportFragmentManager();

        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        MyFragment mFragment = new MyFragment();

        fragmentTransaction.replace(R.id.fragment, mFragment);
        fragmentTransaction.commit();

    }

    @Override
    protected void onStart() {
        Log.d(TAG, "Activity: 調(diào)用onStart");
        super.onStart();
    }

    @Override
    protected void onResume() {
        Log.d(TAG, "Activity: 調(diào)用onResume");
        super.onResume();
    }

    @Override
    protected void onRestart() {
        Log.d(TAG, "Activity: 調(diào)用onRestart");
        super.onRestart();
    }

    @Override
    protected void onPause() {
        Log.d(TAG, "Activity: 調(diào)用onPause");
        super.onPause();
    }

    @Override
    protected void onStop() {
        Log.d(TAG, "Activity: 調(diào)用onStop");
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        Log.d(TAG, "Activity: 調(diào)用onDestroy");
        super.onDestroy();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        Log.d(TAG, "Activity: 調(diào)用onSaveInstanceState");
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        Log.d(TAG, "Activity: " + "調(diào)用onRestoreInstanceState");
        super.onRestoreInstanceState(savedInstanceState);
    }
}

Fragment

public class MyFragment extends Fragment {
    private static final String TAG = "Fragment";
    @BindView(R.id.tv_text)
    TextView mTvText;
    Unbinder unbinder;

    @Override
    public void onAttach(Context context) {
        Log.d(TAG, "Fragment: 調(diào)用onAttach");
        super.onAttach(context);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        Log.d(TAG, "Fragment: 調(diào)用onCreate");
        super.onCreate(savedInstanceState);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "Fragment: 調(diào)用onCreateView");
        View view = inflater.inflate(R.layout.activity_fragment, container, false);

        unbinder = ButterKnife.bind(this, view);

        return view;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        Log.d(TAG, "Fragment: 調(diào)用 onActivityCreated");
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public void onStart() {
        Log.d(TAG, "Fragment: 調(diào)用 onStart");
        super.onStart();
    }

    @Override
    public void onResume() {
        Log.d(TAG, "Fragment: 調(diào)用 onResume");
        super.onResume();
    }

    @Override
    public void onPause() {
        Log.d(TAG, "Fragment: 調(diào)用 onPause");
        super.onPause();
    }

    @Override
    public void onStop() {
        Log.d(TAG, "Fragment: 調(diào)用 onStop");
        super.onStop();
    }

    @Override
    public void onDestroyView() {
        Log.d(TAG, "Fragment: 調(diào)用 onDestroyView");
        super.onDestroyView();
        unbinder.unbind();
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "Fragment: 調(diào)用 onDestroy");
        super.onDestroy();
    }

 
    @Override
    public void onDetach() {
        Log.d(TAG, "Fragment: 調(diào)用 onDetach");
        super.onDetach();
    }
}
操作細(xì)節(jié)

Activity組件之間的通信

我將Activity組件之間的通信分為以下三種:

1. Activity與Activity之間通信
2. Activity與Fragment之間通信
3. Activity與Service數(shù)據(jù)通信
Activity與Activity之間通信

Activity與Activity之間通信主要有以下幾種方式

1. Intent/Bundle
2. 類靜態(tài)變量
3. 全局變量
4. EventBus

這里主要是介紹第一種方式:Intent/Bundle
第一個(gè)Activity

public class OneActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_one);
        ButterKnife.bind(this);

    }

    @OnClick(R.id.bt_to_activity)
    public void onViewClicked() {
        Bundle bundle = new Bundle();
        bundle.putInt("age", 19);
        bundle.putString("name", "雷東寶");

        Intent intent = new Intent(OneActivity.this, SecondActivity.class);
        intent.putExtras(bundle);
        startActivity(intent);
    }
}

第二個(gè)Activity,顯示從第一個(gè)Activity中傳入的名字和年齡

public class SecondActivity extends AppCompatActivity {

    @BindView(R.id.tv_name)
    TextView mTvName;
    @BindView(R.id.tv_age)
    TextView mTvAge;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        ButterKnife.bind(this);

        //用getIntent()方法獲取intent
        Intent intent = getIntent();
        String name = intent.getStringExtra("name");
        int age = intent.getIntExtra("age", 0);

        mTvName.setText("傳來(lái)的名字是:\t" + name);
        mTvAge.setText("傳來(lái)的年齡是:\t" + age);
    }
}

操作細(xì)節(jié)
Activity與Fragment之間通信

其中Activity與Fragment之間通信又可以分為

  • Activity傳遞數(shù)據(jù)給Fragment
  • Fragment傳遞數(shù)據(jù)給Activity

Fragment 與 Activity 通信存在三種情形:

1. Activity 操作內(nèi)嵌的 Fragment,
2. Fragment 操作宿主 Activity,
3. Fragment 操作同屬 Activity中的其他 Fragment。

下面的demo主要是基于前兩種情形

Activity傳遞數(shù)據(jù)給Fragment的方法我總結(jié)為兩點(diǎn):

1. 使用Bundle
2. 直接在Activity中定義方法

我這里主要介紹使用Bundle方法
步驟在代碼里已經(jīng)注釋清楚了
Fragment

public class MyFragment extends Fragment {
    private static final String TAG = "Fragment";
    @BindView(R.id.tv_text)
    TextView mTvText;
    Unbinder unbinder;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "Fragment: 調(diào)用onCreateView");
        View view = inflater.inflate(R.layout.activity_fragment, container, false);

        unbinder = ButterKnife.bind(this, view);

        if(isAdded()) {//判斷Fragment已經(jīng)依附Activity
            //收到Activity傳來(lái)的值第一步 獲取從Activity中傳過(guò)來(lái)的全部值
            savedInstanceState = this.getArguments();
            //收到Activity傳來(lái)的值第二步  獲取某一個(gè)值
            if (savedInstanceState != null) {
                String message = savedInstanceState.getString("message");
                mTvText.setText("我是fragment\n Activity傳過(guò)來(lái)的值:" + message);
            }
        }

        return view;
    }
}

對(duì)應(yīng)的Activity

public class ActivityToFragmentActivity extends AppCompatActivity  {
    private static final String TAG = "Fragment";
    @BindView(R.id.tv_back)
    TextView mTvBack;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "Activity: 調(diào)用onCreate");

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_to_fragment);
        ButterKnife.bind(this);

        //第一步獲取FragmentManager
        FragmentManager fragmentManager = getSupportFragmentManager();

        //第二步獲取FragmentTransaction
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        //第三步創(chuàng)建需要添加的Fragment
        MyFragment mFragment = new MyFragment();

        //第四步創(chuàng)建Bundle對(duì)象
        Bundle bundle = new Bundle();

        //第五步往bundle中添加數(shù)據(jù)
        bundle.putString("message", "Activity往Fragment中傳值");

        //第六步  將數(shù)據(jù)添加在fragment中
        mFragment.setArguments(bundle);

        //第七步  動(dòng)態(tài)添加fragment
        fragmentTransaction.replace(R.id.fragment, mFragment);
        fragmentTransaction.commit();

    }
}

Fragment傳遞數(shù)據(jù)給Activity的方法也有很多:

1. Handler
2. 廣播
3. EventBus
4. 接口回調(diào)
5. Bundle和setArguments(bundle)

我這里主要介紹Fragment傳遞數(shù)據(jù)給Activity的方法中的接口回調(diào)

實(shí)現(xiàn)Fragment傳遞數(shù)據(jù)給Activity的接口回調(diào)主要分四步:
第一步: 定義回調(diào)接口
第二步: 定義接口屬性
第三步: 獲取相應(yīng)的Activity
第四步: 調(diào)用接口中的方法

下面是Fragment中的代碼:

public class MyFragment extends Fragment {
    private static final String TAG = "Fragment";
    @BindView(R.id.tv_text)
    TextView mTvText;
    Unbinder unbinder;

    //回傳Activity第二步  定義屬性
    private FragmentCallBack mFragmentCallBack;

    @Override
    public void onAttach(Context context) {
        Log.d(TAG, "Fragment: 調(diào)用onAttach");
        super.onAttach(context);
        if (context instanceof FragmentCallBack) {
            mFragmentCallBack = (FragmentCallBack) context;//回傳Activity第三步  獲取相應(yīng)的Activity
        } else {
            throw new IllegalArgumentException("接口必須是FragmentCallBack");
        }
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "Fragment: 調(diào)用onCreateView");
        View view = inflater.inflate(R.layout.activity_fragment, container, false);

        unbinder = ButterKnife.bind(this, view);
        return view;
    }

 @Override
    public void onDestroyView() {
        Log.d(TAG, "Fragment: 調(diào)用 onDestroyView");
        super.onDestroyView();
        unbinder.unbind();
    }
    /**
     * @return : void
     * @date 創(chuàng)建時(shí)間: 2019/1/16
     * @author lady_zhou
     * @Description 將傳遞進(jìn)來(lái)的Activity對(duì)象釋放掉
     */
    @Override
    public void onDetach() {
        Log.d(TAG, "Fragment: 調(diào)用 onDetach");
        super.onDetach();
        mFragmentCallBack = null;
    }

    @OnClick(R.id.bt_button)
    public void onViewClicked(View view) {
                mFragmentCallBack.sendContent("從Fragment中回傳回來(lái)的值");//回傳Activity第四步  調(diào)用接口中的方法
        }
    }

    /**
     * @author lady_zhou
     * @createTime: 2019/2/6
     * @Description 回傳Activity第一步  定義回調(diào)接口
     */
    public interface FragmentCallBack {
        void sendContent(String info);
    }

對(duì)應(yīng)的Activity的代碼:

public class ActivityToFragmentActivity extends AppCompatActivity implements MyFragment.FragmentCallBack {
    private static final String TAG = "Fragment";
    @BindView(R.id.tv_back)
    TextView mTvBack;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "Activity: 調(diào)用onCreate");

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_to_fragment);
        ButterKnife.bind(this);

        //獲取FragmentManager
        FragmentManager fragmentManager = getSupportFragmentManager();

        //獲取FragmentTransaction
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        //創(chuàng)建需要添加的Fragment
        MyFragment mFragment = new MyFragment();

        // 動(dòng)態(tài)添加fragment
        fragmentTransaction.replace(R.id.fragment, mFragment);
        fragmentTransaction.commit();

    }

    /**
     * @param info :  Activity返回的值
     * @return : void
     * @date 創(chuàng)建時(shí)間: 2019/2/6
     * @author lady_zhou
     * @Description 實(shí)現(xiàn)回調(diào)接口
     */
    @Override
    public void sendContent(String info) {
        if (info != null) {
            mTvBack.setText("這是Activity\n從Fragment返回的值是:" + info);
        }
    }
操作細(xì)節(jié)
Activity與Service數(shù)據(jù)通信

Activity與Service數(shù)據(jù)通信主要有以下幾個(gè)方法:

1. 綁定服務(wù),利用ServiceConnection類(在Activity中實(shí)現(xiàn)這個(gè)類,同時(shí)實(shí)現(xiàn)onServiceConnected() 和onServiceDisconnected() 方法)
2. 簡(jiǎn)單通信,利用Intent進(jìn)行傳值
3. 定義一個(gè)回調(diào)接口來(lái)監(jiān)聽(tīng)服務(wù)中的進(jìn)程的變化使用handle切換到主線程

下面的下載小demo使用第一種和第三種方法,主要實(shí)現(xiàn)構(gòu)想是:
點(diǎn)擊下載后,進(jìn)度條顯示當(dāng)前下載的進(jìn)度(沒(méi)有使用網(wǎng)絡(luò),只是個(gè)小demo),代碼很簡(jiǎn)單應(yīng)該很容易看懂
Activity中的代碼

public class ActivityToServiceActivity extends AppCompatActivity {
    private final String TAG = getClass().getSimpleName();
    private static final String KEY = "data";

    @BindView(R.id.bt_download)
    Button mBtDownload;
    @BindView(R.id.progressbar)
    ProgressBar mProgressbar;
    @BindView(R.id.tv_text)
    TextView mTvText;

    //綁定服務(wù)第一步:  先創(chuàng)建服務(wù)中的binder對(duì)象
    private DownLoadService mDownLoadService = null;
    private Intent mIntent;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_to_service);
        ButterKnife.bind(this);

        mIntent = new Intent(ActivityToServiceActivity.this, DownLoadService.class);
    }

    @OnClick(R.id.bt_download)
    public void onViewClicked() {
        bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);//綁定服務(wù)
    }

    ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //綁定服務(wù)第二步:  獲取到DownLoadService返回的binder對(duì)象,并開啟服務(wù)
            mDownLoadService = ((DownLoadService.MyBinder) service).startService();

            //注冊(cè)回調(diào)接口來(lái)接收下載進(jìn)度的變化
            mDownLoadService.setOnProgressListener(new DownLoadService.OnProgressListener() {

                @Override
                public void onProgress(int progress) {
                    mProgressbar.setProgress(progress);

                    //使用Handle
                    Message message = new Message();
                    Bundle bundle = new Bundle();
                    bundle.putInt(KEY, progress);
                    message.setData(bundle);
                    mHandler.sendMessage(message);

                    if (progress == 100) {
                        unbindService(mServiceConnection);
                        mDownLoadService = null;
                        Log.d(TAG, "方法:onProgress: \t\t解綁服務(wù)");
                    }
                    Log.d(TAG, "方法:onProgress: \t\t" + progress);

                }
            });


        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //切換到主線程顯示進(jìn)度
            mTvText.setText(msg.getData().getInt(KEY,0)+"%");
            if(msg.getData().getInt(KEY,0)==100){
                Toast.makeText(ActivityToServiceActivity.this, "下載完成", Toast.LENGTH_SHORT).show();
            }
        }
    };

    @Override
    protected void onDestroy() {
        if (mDownLoadService != null) {
            unbindService(mServiceConnection);
        }
        super.onDestroy();
    }
}

下載服務(wù)實(shí)現(xiàn):

public class DownLoadService extends Service {
    private final String TAG = getClass().getSimpleName();
    //進(jìn)度條的最大值
    public static final int MAX_PROGRESS = 100;

    // 進(jìn)度條的進(jìn)度值
    private int progress = 0;

    private OnProgressListener onProgressListener;
    private Thread mThread;

    /**
     * @param intent :  返回一個(gè)Binder對(duì)象
     * @return : android.os.IBinder
     * @date 創(chuàng)建時(shí)間: 2019/1/16
     * @author lady_zhou
     * @Description
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        startDownLoad();
        return new MyBinder();
    }

    public class MyBinder extends Binder {
        /**
         * 獲取當(dāng)前Service的實(shí)例
         *
         * @return
         */
        public DownLoadService startService() {
            return DownLoadService.this;
        }
    }

    /**
     * @return : void
     * @date 創(chuàng)建時(shí)間: 2019/1/16
     * @author lady_zhou
     * @Description 模擬下載任務(wù),每秒鐘更新一次
     */
    public void startDownLoad() {
        mThread = new Thread(new Runnable() {

            @Override
            public void run() {
                while (progress < MAX_PROGRESS) {
                    progress += 10;
                    //中斷線程
                    if (Thread.currentThread().isInterrupted()) {
                        Log.d(TAG, "方法:run: \t\t中斷線程");
                        break;
                    }
                    //進(jìn)度發(fā)生變化通知調(diào)用方
                    if (onProgressListener != null) {
                        onProgressListener.onProgress(progress);
                    }

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }

                    Log.d(TAG, "方法:run: 線程\t\t" + progress);
                }
            }
        });
        mThread.start();
    }

    /**
     * @author lady_zhou
     * @createTime: 2019/1/16
     * @Description 更新進(jìn)度的回調(diào)接口
     */
    public interface OnProgressListener {
        void onProgress(int progress);
    }

    /**
     * @param onProgressListener :
     * @return : void
     * @date 創(chuàng)建時(shí)間: 2019/1/16
     * @author lady_zhou
     * @Description 注冊(cè)回調(diào)接口的方法,供外部調(diào)用
     */
    public void setOnProgressListener(OnProgressListener onProgressListener) {
        this.onProgressListener = onProgressListener;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG, "方法:onUnbind: \t\t解綁了");
        mThread.interrupt();//中斷線程

        return super.onUnbind(intent);
    }
}
操作細(xì)節(jié)

以上代碼的github鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容