自定义View能否知道onPause被调用了?

问题描述 投票:0回答:7

我有一个自定义视图,它运行一个线程操作,该操作定期调用互联网。我想知道是否有一种方法可以让我不必从父 Activity (onPause) 中杀死该线程,以便在 Activity 后台运行(和/或杀死)后,线程不会在后台闲逛。

这里的目的是让自定义视图自给自足,不需要活动的额外处理。做到这一点的方法是让它监听其父级何时进入后台,然后让线程中的无限睡眠循环到期。我没有找到办法做到这一点,但我希望我忽略了一些事情。

android multithreading custom-view
7个回答
69
投票

是的,您可以使用下面的代码,

@Override
protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
    super.onVisibilityChanged(changedView, visibility);
    if (visibility == View.VISIBLE) //onResume called
    else // onPause() called
}

@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
    super.onWindowFocusChanged(hasWindowFocus);
    if (hasWindowFocus) //onresume() called
    else // onPause() called
}

@Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        // onDestroy() called
}

@Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        // onCreate() called
}

19
投票

除非您直接通知,否则不会。

为了您的目的,覆盖

View.onDetachedFromWindow()
并放弃您的线程。然后,当视图再次可见时,将线程旋转回
View.onAttachedToWindow()
。 onPause() 和 onResume() 的问题是,您仍然可以拥有屏幕上可见的视图,但附加到暂停的 Activity。发生这种情况的一个例子是,如果窗口中的一个 Activity 覆盖了另一个 Activity。

或者,正如 william gouvea 所建议的那样,Fragment 可能更适合您的目的,因为它已经具有用于暂停和恢复的生命周期挂钩,并且无论如何与网络通信的任何内容都确实属于 controller 领域。


10
投票

如果

Build.VERSION.SDK_INT < Build.VERSION_CODES.N

@Override
protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
    super.onVisibilityChanged(changedView, visibility);
    if (visibility == View.VISIBLE) //onResume called
    else // onPause() called
}

然后

Build.VERSION.SDK_INT >= Build.VERSION_CODES.N

@Override
public void onVisibilityAggregated(boolean isVisible) {
    super.onVisibilityAggregated(isVisible);
    if (isVisible) //onresume() called
    else // onPause() called
}

您可以阅读ProgressBar的源代码来了解。


9
投票

是的,你可以。 您所需要的只是拥有一个 LifecycleOwner 类型的字段。 有关更多信息,请参阅官方文档。 就我而言,我使用来自第 3 方库的另一个视图 - CameraView 创建了一个自定义视图。

首先,自定义视图需要实现LifecycleOberver接口

public class MakePhotoView extends ConstraintLayout implements LifecycleObserver

所以,我的自定义视图中有一个字段:

private LifecycleOwner mLifecycleOwner;

我将它作为参数之一传递到构造函数中:

public MakePhotoView(Context context, OnPhotoMadeListener onPhotoMadeListener, LifecycleOwner lifecycleOwner) {
    super(context);
    mOnPhotoMadeListener = onPhotoMadeListener;
    mLifecycleOwner = lifecycleOwner;
    init();
}

之后,我将自定义视图注册为 LifecycleOwner 中生命周期事件的观察者:

private void init() {
    //other code
    mLifecycleOwner.getLifecycle().addObserver(this);
}

最后我可以监听生命周期事件:

@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void startCamera() {
    AppLog.logObject(this, "On Resume called for MakeCameraView");
    mCameraView.start();
}

@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void stopCamera() {
    AppLog.logObject(this, "On Pause called for MakeCameraView");
    mCameraView.stop();
}

@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
public void destroyCamera() {
    AppLog.logObject(this, "On Destroy called for MakeCameraView");
    mCameraView.destroy();
}

2
投票

要么你必须让你的视图知道所属的 Activity 不再位于前台,要么使用某种方法轮询系统来查询当前哪个任务位于前台,这似乎效率很低。

这里有两个解决此问题的链接:

(这可能不是真正的答案,但对于评论来说太大了)


2
投票

如果您只是重写 View 类并创建自己的 CustomView,您可以创建一个接口来充当侦听器,该接口应该由您的父 Activity 实现,因此当发生某些情况时,您会触发事件并在这些组件之间建立通信向前。

根据您想要实现的目标,片段可能很有用,因为该组件具有与 Activity 类似的自己的生命周期(例如 onPause/onResume),保存您自己的状态,有或没有视图,并且可以在配置更改之间保留其状态.

查看更多内容: http://developer.android.com/reference/android/app/Fragment.html http://developer.android.com/guide/components/fragments.html


0
投票

使用生命周期所有者

您应该使用

androidx.lifecycle.LifecycleOwner
实现此功能并在初始化时注册它。

有关更多信息,请参阅https://developer.android.com/reference/android/arch/lifecycle/DefaultLifecycleObserver

Kotlin 中的自定义视图示例:

import android.content.Context
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import android.util.AttributeSet
import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout

class YourCustomView : ConstraintLayout, DefaultLifecycleObserver {

    constructor(context: Context) : super(context) {
        initAttributes()
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        initAttributes(attrs)
    }

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        initAttributes(attrs, defStyleAttr, defStyleAttr)
    }

    init {
        inflate(context, R.layout.your_custom_layout, this)
        // makes this view lifecycle aware
        (context as? LifecycleOwner)?.lifecycle?.addObserver(this)
    }

    // region next hook into the lifecycle methods you need

    override fun onPause(owner: LifecycleOwner) {
        super.onPause(owner)
    }

    override fun onResume(owner: LifecycleOwner) {
        super.onResume(owner)
    }

    override fun onDestroy(owner: LifecycleOwner) {
        super.onDestroy(owner)
    }

    // endregion

}
© www.soinside.com 2019 - 2024. All rights reserved.