您现在的位置是:主页 > news > 网站建设图片怎么切/百度电脑版下载官方

网站建设图片怎么切/百度电脑版下载官方

admin2025/5/2 8:13:23news

简介网站建设图片怎么切,百度电脑版下载官方,淮安做网站服务单位,顺义区住房城乡建设委 房管局 官方网站一、前言 如果我们在AndroidManifest.xml中声明Activity时,没有对android:configChanges进行特殊的声明,那么在屏幕旋转时,会导致Activity的重建,几个关键声明周期的调用情况如下所示: 旋转屏幕前的Activity中的变量都…

网站建设图片怎么切,百度电脑版下载官方,淮安做网站服务单位,顺义区住房城乡建设委 房管局 官方网站一、前言 如果我们在AndroidManifest.xml中声明Activity时,没有对android:configChanges进行特殊的声明,那么在屏幕旋转时,会导致Activity的重建,几个关键声明周期的调用情况如下所示: 旋转屏幕前的Activity中的变量都…

一、前言

如果我们在AndroidManifest.xml中声明Activity时,没有对android:configChanges进行特殊的声明,那么在屏幕旋转时,会导致Activity的重建,几个关键声明周期的调用情况如下所示:

旋转屏幕前的Activity中的变量都会被销毁,但是有时候我们某些任务的执行不和Activity的生命周期绑定,这时候我们就可以利用Fragment提供的setRetainInstance方法,该方法的说明如下:
如果给Fragment设置了该标志位,那么在屏幕旋转之后,虽然它依附的Activity被销毁了,但是该Fragment的实例会被保留,并且在Activity的销毁过程中,只会调用该FragmentonDetach方法,而不会调用onDestroy方法。

而在Activity重建时,会调用该Fragment实例的onAttachonActivityCreated方法,但不会调用onCreate方法。

根据Fragment提供的这一特性,那么我们就可以将一些在屏幕旋转过程中,仍然需要运行的任务放在具有该属性的Fragment中执行。在 Handling Configuration Changes with Fragments 这篇文章中,作者介绍了通过这个技巧来实现了一个不被中断的AsyncTask,大家有需要了解详细说明的可以查看这篇文章。

今天,我们跟着前人脚步,用RxJava来演示在屏幕旋转导致Activity重建时,仍然保持后台任务继续执行的例子。

二、示例

2.1 示例

首先,我们声明一个接口,用于FragmentActivity一个ConnectableObservable,使得Activity可以监听到Fragment中后台任务的工作进度。

public interface IHolder {public void onWorkerPrepared(ConnectableObservable<Long> workerFlow);
}
复制代码

下面,我们来实现WorkerFragment,我们在onCreate中创建了数据源,它每隔1s向下游发送数据,在onResume中,通过前面定义的接口向Activity传递一个ConnectableObservable用于监听。这里最关键的是需要调用我们前面说到的setRetainInstance方法,最后别忘了,在onDetach中将mHolder置为空,否则它就会持有需要被重建的Activity示例,从而导致内存泄漏。

public class WorkerFragment extends Fragment {public static final String TAG = WorkerFragment.class.getName();private ConnectableObservable<String> mWorker;private Disposable mDisposable;private IHolder mHolder;@Overridepublic void onAttach(Context context) {super.onAttach(context);if (context instanceof IHolder) {mHolder = (IHolder) context;}}@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setRetainInstance(true);if (mWorker != null) {return;}Bundle bundle = getArguments();final String taskName = (bundle != null ? bundle.getString("task_name") : null);mWorker = Observable.create(new ObservableOnSubscribe<String>() {@Overridepublic void subscribe(ObservableEmitter<String> observableEmitter) throws Exception {for (int i = 0; i < 10; i++) {String message = "任务名称=" + taskName + ", 任务进度=" + i * 10 + "%";try {Log.d(TAG, message);Thread.sleep(1000);//如果已经抛弃,那么不再继续任务。if (observableEmitter.isDisposed()) {break;}} catch (InterruptedException error) {if (!observableEmitter.isDisposed()) {observableEmitter.onError(error);}}observableEmitter.onNext(message);}observableEmitter.onComplete();}}).subscribeOn(Schedulers.io()).publish();mDisposable = mWorker.connect();}@Overridepublic void onResume() {super.onResume();if (mHolder != null) {mHolder.onWorkerPrepared(mWorker);}}@Overridepublic void onDestroy() {super.onDestroy();mDisposable.dispose();Log.d(TAG, "onDestroy");}@Overridepublic void onDetach() {super.onDetach();mHolder = null;}
}
复制代码

最后来看Activity,当点击“开始工作任务”后,我们尝试添加WorkerFragment,这时候就会走到WorkerFragmentonCreate方法中启动任务,之后当WorkerFragment走到onResume方法后,就调用onWorkerPrepared,让Activity进行订阅,Activity就可以收到当前任务进度的通知,来更新UI。而在任务执行完毕之后,我们就可以将该Fragment移除了。

public class RotationPersistActivity extends AppCompatActivity implements IHolder {private static final String TAG = RotationPersistActivity.class.getName();private Button mBtWorker;private TextView mTvResult;private CompositeDisposable mCompositeDisposable;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.d(TAG, "onCreate");setContentView(R.layout.activity_rotation_persist);mBtWorker = (Button) findViewById(R.id.bt_start_worker);mBtWorker.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {startWorker();}});mTvResult = (TextView) findViewById(R.id.tv_worker_result);mCompositeDisposable = new CompositeDisposable();}@Overridepublic void onWorkerPrepared(Observable<String> worker) {DisposableObserver<String> disposableObserver = new DisposableObserver<String>() {@Overridepublic void onNext(String message) {mTvResult.setText(message);}@Overridepublic void onError(Throwable throwable) {onWorkerFinished();mTvResult.setText("任务错误");}@Overridepublic void onComplete() {onWorkerFinished();mTvResult.setText("任务完成");}};worker.observeOn(AndroidSchedulers.mainThread()).subscribe(disposableObserver);mCompositeDisposable.add(disposableObserver);}private void startWorker() {WorkerFragment worker = getWorkerFragment();if (worker == null) {addWorkerFragment();} else {Log.d(TAG, "WorkerFragment has attach");}}private void onWorkerFinished() {Log.d(TAG, "onWorkerFinished");removeWorkerFragment();}private void addWorkerFragment() {WorkerFragment workerFragment = new WorkerFragment();Bundle bundle = new Bundle();bundle.putString("task_name", "学习RxJava2");workerFragment.setArguments(bundle);FragmentManager manager = getSupportFragmentManager();FragmentTransaction transaction = manager.beginTransaction();transaction.add(workerFragment, WorkerFragment.TAG);transaction.commit();}private void removeWorkerFragment() {WorkerFragment workerFragment = getWorkerFragment();if (workerFragment != null) {FragmentManager manager = getSupportFragmentManager();FragmentTransaction transaction = manager.beginTransaction();transaction.remove(workerFragment);transaction.commit();}}private WorkerFragment getWorkerFragment() {FragmentManager manager = getSupportFragmentManager();return (WorkerFragment) manager.findFragmentByTag(WorkerFragment.TAG);}@Overrideprotected void onDestroy() {super.onDestroy();Log.d(TAG, "onDestroy");mCompositeDisposable.clear();}
}
复制代码

我们来演示一下屏幕旋转时的效果,在屏幕旋转之后,我们仍然可以继续收到任务进度的更新:

2.2 示例解析

下面,我们来解释一下示例中的几个要点:

2.2.1 Activity 和 Fragment 之间的数据传递

数据传递分为两个方向,它们各自可以通过以下方法来实现:

  • ActivityFragment传递数据(示例中我们传递了任务的名称) 一般用于向WorkerFragment传递一些任务参数,此时可以通过FragmentsetArguments传入相关的字段,FragmentonCreate方法中通过getArguments获取参数。
  • FragmentActivity传递数据(示例中我们传递了ObservableActivity订阅以获取进度) 可以让Activity实现一个接口,我们在FragmentonAttach方法中获取Activity实例转换成对应的接口类型,之后通过它来调用Activity的方法,需要注意的是,在Fragment#onDetach时,要将该Activity的引用置空,否则会出现内存泄漏。

2.2 为什么调用 publish 方法,使用 Hot Observable 作为 WorkerFragment 的数据源

推荐大家先看一下这篇文章 RxJava 教程第三部分:驯服数据流之 Hot & Cold Observable,这里面对于Cold & Hot Observable进行了解释,它们之间关键的区别就是:

  • 只有当订阅者订阅时,Cold Observale才开始发送数据,并且每个订阅者都独立执行一遍数据流代码。
  • Hot Observable不管有没有订阅者,它都会发送数据流。

而在我们的应用场景中,由于WorkerFragment是在后台执行任务:

  • Activity的角度来看:每次Activity重建时,在Activity中都需要用一个新的Observer实例去订阅WorkerFragment中的数据源,因此我们只能选择通过Hot Observable,而不是Cold Observable来实现WorkerFragment中的数据源,否则每次都会重新执行一遍数据流的代码,而不是继续接收它发送的事件。
  • WorkerFragment的角度来看,它只是一个任务的执行者,不管有没有人在监听它的进度,它都应该执行任务。

通过Observable.create方法创建的是一个Cold Observable,该Cold Observable每隔1s发送一个事件。我们调用publish方法来将它转换为Hot Observable,之后再调用该Hot Observableconnect方法让其对源Cold Observable进行订阅,这样源Cold Observable就可以开始执行任务了。并且,通过connect方法返回的Disposable对象,我们就可以管理转换后的Hot Observable和源Cold Observable之间的订阅关系。

Disposable的用途在于:在某些时候,我们希望能够停止源Observable任务的执行,例如当该WorkerFragment真正被销毁时,也就是执行了它的onDestroy方法,那么我们就可以通过上面的Disposable取消Hot Observable对源Cold Observable的订阅,而在Cold Observable的循环中,我们判断如果下游(也就是Hot Observable)取消了订阅,那么就不再执行任务。

整个的架构图如下所示:

2.3 在任务执行之后 removeFragment

在了能让WorkerFragment能正常进行下一次任务的执行,我们需要在发生错误或者任务完成的时候,通过remove的方式销毁WorkerFragment


更多文章,欢迎访问我的 Android 知识梳理系列:

  • Android 知识梳理目录:www.jianshu.com/p/fd82d1899…
  • 个人主页:lizejun.cn
  • 个人知识总结目录:lizejun.cn/categories/