Android Activity 面试那些事

学习刚要

Activity是与用户交互的接口
Android系统是通过Activity栈的形式来管理Activity

下面我将会从以下几个方面对Activity进行总结:

  • Activity的四种展示形态
  • Activity的启动模式
  • Activity的生命周期
  • Activity组件之间的通信

Activity四种形态

  1. Active(Activity处于栈顶)
  2. Paused (可见但不可交互,只是失去和用交互的能力)
  3. Stopped (不可见,被另一个Activity完全覆盖,在内存足够时,数据、状态、变量都被保存,内存不足时,数据、状态、变量被系统回收掉)
  4. killed (系统回收掉)

Activity启动模式

  1. Standard
    系统默认的启动模式,Activity可多次被实例化,一个任务栈中会有多个实例。
    应用场景:系统默认

  2. SingleTop
    SingleTop分两种情况:一种情况是Activity位于栈顶,另一种是Activity不在栈顶时,但存在于栈中。

    • 当Activity在栈顶时,启用Activity,不会创建新的实例,并重用栈顶的Activity,通过onNewIntent()将Intent对象传入这个实例中。
    • 当Activity不在栈顶时,但存在于栈中,会启用与standard相同的模式

    应用场景:IM对话框,新闻客户端推送

  3. SingleTask
    首先会根据taskAffinity(任务相关性)去寻找当前是否存在一个对应名字的任务栈,如果不存在,则建一个新的task放于栈顶,如果存在,则得到该任务栈,查找该任务栈中是否存在该Activity实例,若存在,系统会销毁在Activity上的所有的Activity,最终使Activity置于栈顶,再回调onNewIntent()函数

    应用场景:应用的主界面

  4. SingleInstance
    Activity会在一个独立的任务中启动,并且在这个栈中只有这一个实例,而被该实例启动的其他Activity会自动运行在另一个任务中,再次启动时该实例会重用已存在的任务和实例,在AndroidManifest文件中的lauchMode属性中设置。

    特性:

    • 以SingleInstance模式启动的Activity具有全局唯一性
    • 以SingleInstance模式启动的Activity具有独占性

    应用场景:呼叫来电

Activity生命周期

Activity正常情况下的周期调用

Activity的生命周期就是Activity从创建到销毁的一个过程,仿佛我们人从出生到死亡一样。

Activity生命周期的方法:
  • onCreate();创建
  • onStart();运行
  • onResume();获取焦点
  • onPause();失去焦点
  • onStop();暂停
  • onDestroy();销毁
  • onRestart();重运行
单个Activity的多种变化形式:
  • 从无到有创建一个Activity
  • 当前的Activity失去焦点
  • 从当前的Activity跳转到另一个Activity
  • 当前Activity被置入后台

从创建一个Activity到销毁的生命周期:

  1. 一个Activity刚创建时候的生命周期:

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

  1. Activity从创建到销毁的生命周期:

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

  1. Activity从启动到失去焦点生命周期:

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

  1. Activity从启动到失去焦点,再到获取焦点的生命周期:

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

  1. Activity从启动到后台的生命周期:

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

  1. Activity从启动到后台,再到前台的生命周期:

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

onStart()、onStop() 、 onResume()、 onPause() 的区别:
onStart和onStop是从Activity是否可见这个角度来回调的,而onResume和onPause是从Activity是否位于前台这个角度来回调的。

两个Activity从创建到销毁

有两个Activity,分别为A和B,在A已经创建的情况下,创建B页面,这里可能会出现两种情况:

  • 页面B完全遮挡住页面A
  • 页面B没有完全遮挡住页面A
页面B完全遮挡住页面A

当页面B完全遮挡住页面A时的生命周期:


页面B完全遮挡住页面A.gif
页面B完全遮挡住页面A.png
页面B没有完全遮挡住页面A

将B页面设为透明的,在AndroidManifest.xml中设置

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

当页面B没有完全遮挡住页面A时的生命周期:

页面B没有完全遮挡住页面A .gif
页面B没有完全遮挡住页面A.png

从这两种情况可以看到,当页面A没有被遮挡的时候,是不走onStop() 方法的,并且在开启一个新的页面B之前,页面A会先执行onPause() 方法。

Activity异常情况下的周期调用

异常情况下多了两个方法:onSaveInstanceState(),onRestoreInstanceState(),这两个方法是出现异常情况下系统自动调用的,通常 onSaveInstanceState() 只适合用于保存一些临时性的状态,而 onPause() 适合用于数据的持久化保存。当Activity被重新创建后,系统会调用 onRestoreInstanceState() 方法,此方法会将Activity销毁时通过 onSaveInstanceState() 保存的bundle对象作为一个对象传给 onRestoreInstanceState() 方法,同时也会传递给 onCreate() 方法。

onRestoreInstanceState() 方法与 onCreate() 方法都可以进行数据恢复,他两区别在于:onRestoreInstanceState()传入的参数一定不能为空,onCreate() 传入的参数有可能为空,所以使用onRestoreInstanceState() 进行数据恢复比较好。

onRestoreInstanceState() 方法在 onStart() 之后执行,onSaveInstanceState() 方法在 onPause() 之后执行。

下面看个横竖屏切换的小例子观察下onRestoreInstanceState()方法的调用

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: " + "调用onRestoreInstanceState");
        super.onRestoreInstanceState(savedInstanceState);
        mTvShow.setText(savedInstanceState.getString(TURN));
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate: 调用onCreate");

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

    @Override
    protected void onStart() {
        Log.d(TAG, "onStart: 调用onStart");
        super.onStart();
    }

    @Override
    protected void onResume() {
        Log.d(TAG, "onResume: 调用onResume");
        super.onResume();
    }

    @Override
    protected void onRestart() {
        Log.d(TAG, "onRestart: 调用onRestart");
        super.onRestart();
    }

    @Override
    protected void onPause() {
        Log.d(TAG, "onPause: 调用onPause");
        super.onPause();
    }

    @Override
    protected void onStop() {
        Log.d(TAG, "onStop: 调用onStop");
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        Log.d(TAG, "onDestroy: 调用onDestroy");
        super.onDestroy();
    }

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

    }

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

}

运行后的效果:

操作细节
结果展示

最后防止重新创建activity:
可以在AndroidManifest.xml中指定configChange属性来不让系统重新创建

 <activity
            android:name=".activity.ReviewActivity"
            android:configChanges="orientation|screenSize" />
  /**
     * @param newConfig :
     * @return : void
     * @date 创建时间: 2018/12/1
     * @author lady_zhou
     * @Description  activity不被重建
     */
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        Log.d(TAG, "onConfigurationChanged: 切屏防止activity调用onSaveInstanceState");
        super.onConfigurationChanged(newConfig);
    }
操作细节
结果展示
Activity与Fragment生命周期关系

从创建一个含有Fragment的Activity到 销毁的生命周期:

Fragment生命周期的方法:
  • onAttach();fragment已经关联到activity,只调用一次
  • onCreate();系统创建fragment的时候回调他,只调用一次
  • onCreateView();绘制layout
  • onActivityCreated();当Activity中的onCreate方法执行完后调用。
  • onStart();运行
  • onResume();获取焦点
  • onPause();失去焦点
  • onStop();暂停
  • onDestroyView();Fragment中的布局被移除时调用
  • onDestroy();销毁
  • onDetach();Fragment和Activity解除关联的时候调用
与Activity一样Fragment也有的多种变化形式:
  • 从无到有创建一个Fragment
  • 当前Activity被置入后台
  1. 刚创建时候的生命周期:

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

  1. 从创建到销毁的生命周期:

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. 从启动到后台的生命周期:

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. 从启动到后台,再到前台的生命周期:

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: 调用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: 调用onStart");
        super.onStart();
    }

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

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

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

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

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

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

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        Log.d(TAG, "Activity: " + "调用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: 调用onAttach");
        super.onAttach(context);
    }

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

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "Fragment: 调用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: 调用 onActivityCreated");
        super.onActivityCreated(savedInstanceState);
    }

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

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

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

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

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

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

 
    @Override
    public void onDetach() {
        Log.d(TAG, "Fragment: 调用 onDetach");
        super.onDetach();
    }
}
操作细节

Activity组件之间的通信

我将Activity组件之间的通信分为以下三种:

1. Activity与Activity之间通信
2. Activity与Fragment之间通信
3. Activity与Service数据通信
Activity与Activity之间通信

Activity与Activity之间通信主要有以下几种方式

1. Intent/Bundle
2. 类静态变量
3. 全局变量
4. EventBus

这里主要是介绍第一种方式:Intent/Bundle
第一个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);
    }
}

第二个Activity,显示从第一个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("传来的名字是:\t" + name);
        mTvAge.setText("传来的年龄是:\t" + age);
    }
}

操作细节
Activity与Fragment之间通信

其中Activity与Fragment之间通信又可以分为

  • Activity传递数据给Fragment
  • Fragment传递数据给Activity

Fragment 与 Activity 通信存在三种情形:

1. Activity 操作内嵌的 Fragment,
2. Fragment 操作宿主 Activity,
3. Fragment 操作同属 Activity中的其他 Fragment。

下面的demo主要是基于前两种情形

Activity传递数据给Fragment的方法我总结为两点:

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

我这里主要介绍使用Bundle方法
步骤在代码里已经注释清楚了
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: 调用onCreateView");
        View view = inflater.inflate(R.layout.activity_fragment, container, false);

        unbinder = ButterKnife.bind(this, view);

        if(isAdded()) {//判断Fragment已经依附Activity
            //收到Activity传来的值第一步 获取从Activity中传过来的全部值
            savedInstanceState = this.getArguments();
            //收到Activity传来的值第二步  获取某一个值
            if (savedInstanceState != null) {
                String message = savedInstanceState.getString("message");
                mTvText.setText("我是fragment\n Activity传过来的值:" + message);
            }
        }

        return view;
    }
}

对应的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: 调用onCreate");

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

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

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

        //第三步创建需要添加的Fragment
        MyFragment mFragment = new MyFragment();

        //第四步创建Bundle对象
        Bundle bundle = new Bundle();

        //第五步往bundle中添加数据
        bundle.putString("message", "Activity往Fragment中传值");

        //第六步  将数据添加在fragment中
        mFragment.setArguments(bundle);

        //第七步  动态添加fragment
        fragmentTransaction.replace(R.id.fragment, mFragment);
        fragmentTransaction.commit();

    }
}

Fragment传递数据给Activity的方法也有很多:

1. Handler
2. 广播
3. EventBus
4. 接口回调
5. Bundle和setArguments(bundle)

我这里主要介绍Fragment传递数据给Activity的方法中的接口回调

实现Fragment传递数据给Activity的接口回调主要分四步:
第一步: 定义回调接口
第二步: 定义接口属性
第三步: 获取相应的Activity
第四步: 调用接口中的方法

下面是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: 调用onAttach");
        super.onAttach(context);
        if (context instanceof FragmentCallBack) {
            mFragmentCallBack = (FragmentCallBack) context;//回传Activity第三步  获取相应的Activity
        } else {
            throw new IllegalArgumentException("接口必须是FragmentCallBack");
        }
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "Fragment: 调用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: 调用 onDestroyView");
        super.onDestroyView();
        unbinder.unbind();
    }
    /**
     * @return : void
     * @date 创建时间: 2019/1/16
     * @author lady_zhou
     * @Description 将传递进来的Activity对象释放掉
     */
    @Override
    public void onDetach() {
        Log.d(TAG, "Fragment: 调用 onDetach");
        super.onDetach();
        mFragmentCallBack = null;
    }

    @OnClick(R.id.bt_button)
    public void onViewClicked(View view) {
                mFragmentCallBack.sendContent("从Fragment中回传回来的值");//回传Activity第四步  调用接口中的方法
        }
    }

    /**
     * @author lady_zhou
     * @createTime: 2019/2/6
     * @Description 回传Activity第一步  定义回调接口
     */
    public interface FragmentCallBack {
        void sendContent(String info);
    }

对应的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: 调用onCreate");

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

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

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

        //创建需要添加的Fragment
        MyFragment mFragment = new MyFragment();

        // 动态添加fragment
        fragmentTransaction.replace(R.id.fragment, mFragment);
        fragmentTransaction.commit();

    }

    /**
     * @param info :  Activity返回的值
     * @return : void
     * @date 创建时间: 2019/2/6
     * @author lady_zhou
     * @Description 实现回调接口
     */
    @Override
    public void sendContent(String info) {
        if (info != null) {
            mTvBack.setText("这是Activity\n从Fragment返回的值是:" + info);
        }
    }
操作细节
Activity与Service数据通信

Activity与Service数据通信主要有以下几个方法:

1. 绑定服务,利用ServiceConnection类(在Activity中实现这个类,同时实现onServiceConnected() 和onServiceDisconnected() 方法)
2. 简单通信,利用Intent进行传值
3. 定义一个回调接口来监听服务中的进程的变化使用handle切换到主线程

下面的下载小demo使用第一种和第三种方法,主要实现构想是:
点击下载后,进度条显示当前下载的进度(没有使用网络,只是个小demo),代码很简单应该很容易看懂
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;

    //绑定服务第一步:  先创建服务中的binder对象
    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);//绑定服务
    }

    ServiceConnection mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            //绑定服务第二步:  获取到DownLoadService返回的binder对象,并开启服务
            mDownLoadService = ((DownLoadService.MyBinder) service).startService();

            //注册回调接口来接收下载进度的变化
            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解绑服务");
                    }
                    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);
            //切换到主线程显示进度
            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();
    }
}

下载服务实现:

public class DownLoadService extends Service {
    private final String TAG = getClass().getSimpleName();
    //进度条的最大值
    public static final int MAX_PROGRESS = 100;

    // 进度条的进度值
    private int progress = 0;

    private OnProgressListener onProgressListener;
    private Thread mThread;

    /**
     * @param intent :  返回一个Binder对象
     * @return : android.os.IBinder
     * @date 创建时间: 2019/1/16
     * @author lady_zhou
     * @Description
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        startDownLoad();
        return new MyBinder();
    }

    public class MyBinder extends Binder {
        /**
         * 获取当前Service的实例
         *
         * @return
         */
        public DownLoadService startService() {
            return DownLoadService.this;
        }
    }

    /**
     * @return : void
     * @date 创建时间: 2019/1/16
     * @author lady_zhou
     * @Description 模拟下载任务,每秒钟更新一次
     */
    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;
                    }
                    //进度发生变化通知调用方
                    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 更新进度的回调接口
     */
    public interface OnProgressListener {
        void onProgress(int progress);
    }

    /**
     * @param onProgressListener :
     * @return : void
     * @date 创建时间: 2019/1/16
     * @author lady_zhou
     * @Description 注册回调接口的方法,供外部调用
     */
    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);
    }
}
操作细节

以上代码的github链接

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容