【问题标题】:Pass Activity context in onCreate method在 onCreate 方法中传递 Activity 上下文
【发布时间】:2017-10-25 18:47:15
【问题描述】:

一旦构建活动,我需要将活动上下文传递给我的服务。这是我的代码:

public class myService extends Service
{
    private AppCompatActivity activity;

    public void setActivity(AppCompatActivity activity)
    {
        this.activity = activity;
    }
}

public class myActivity extends AppCompatActivity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        // ... some things are being executed and myService is being bound
        mService.setActivity(this);
    }
}

我得到NullPointerException,因为-我想-myActivity 类仍在构建中,无法传递引用。我怎样才能让Android在onCreate之后运行这个方法?我找到了一些涉及工厂模式的 Java 解决方案,但我不确定如何使用它,如果我可以在我的情况下使用它的话。

【问题讨论】:

  • 什么是mService,是否实例化
  • 我们也不使用上下文传递来处理我们使用广播意图的 ui 线程
  • 如果我们反其道而行之,会不会是个大问题?整个应用程序已经这样编写了,我不确定我是否能够自己强制进行此类更改。
  • 对不起,不是,这只是我从书中学到的方法。你可以随心所欲。

标签: java android oncreate


【解决方案1】:

Service 本身就是一个上下文。所以如果你只需要Context,你可以在你的Serviceclass 中调用this

或者,您应该在启动服务之前将Activity 传递给服务。确保在调用super.onCreate(bundle); 后通过Activity

但是,您不应操纵您的 Activity 或其来自 Service 的视图。更好的方法是从您的Service通知您的Activity

Notify activity from service

编辑:观察者模式

创建一个名为 NotificationCenter.java 的新类

public class NotificationCenter {

    private static int totalEvents = 1;

    public static final int updateActivity = totalEvents++;
    // you can add more events
    // public static final int anotherEvent = totalEvents++;

    private final SparseArray<ArrayList<Object>> observers = new SparseArray<>();
    private final SparseArray<ArrayList<Object>> removeAfterBroadcast = new SparseArray<>();
    private final SparseArray<ArrayList<Object>> addAfterBroadcast = new SparseArray<>();

    private int broadcasting = 0;

    public interface NotificationCenterDelegate {
        void didReceivedNotification(int id, Object... args);
    }

    private static volatile NotificationCenter Instance = null;

    public static NotificationCenter getInstance() {
        NotificationCenter localInstance = Instance;
        if (localInstance == null) {
            synchronized (NotificationCenter.class) {
                localInstance = Instance;
                if (localInstance == null) {
                    Instance = localInstance = new NotificationCenter();
                }
            }
        }
        return localInstance;
    }

    public void postNotificationName(int id, Object... args) {
        broadcasting++;
        ArrayList<Object> objects = observers.get(id);
        if (objects != null && !objects.isEmpty()) {
            for (int a = 0; a < objects.size(); a++) {
                Object obj = objects.get(a);
                ((NotificationCenterDelegate) obj).didReceivedNotification(id, args);
            }
        }
        broadcasting--;
        if (broadcasting == 0) {
            if (removeAfterBroadcast.size() != 0) {
                for (int a = 0; a < removeAfterBroadcast.size(); a++) {
                    int key = removeAfterBroadcast.keyAt(a);
                    ArrayList<Object> arrayList = removeAfterBroadcast.get(key);
                    for (int b = 0; b < arrayList.size(); b++) {
                        removeObserver(arrayList.get(b), key);
                    }
                }
                removeAfterBroadcast.clear();
            }
            if (addAfterBroadcast.size() != 0) {
                for (int a = 0; a < addAfterBroadcast.size(); a++) {
                    int key = addAfterBroadcast.keyAt(a);
                    ArrayList<Object> arrayList = addAfterBroadcast.get(key);
                    for (int b = 0; b < arrayList.size(); b++) {
                        addObserver(arrayList.get(b), key);
                    }
                }
                addAfterBroadcast.clear();
            }
        }
    }

    public void addObserver(Object observer, int id) {
        if (broadcasting != 0) {
            ArrayList<Object> arrayList = addAfterBroadcast.get(id);
            if (arrayList == null) {
                arrayList = new ArrayList<>();
                addAfterBroadcast.put(id, arrayList);
            }
            arrayList.add(observer);
            return;
        }
        ArrayList<Object> objects = observers.get(id);
        if (objects == null) {
            observers.put(id, (objects = new ArrayList<>()));
        }
        if (objects.contains(observer)) {
            return;
        }
        objects.add(observer);
    }

    public void removeObserver(Object observer, int id) {
        if (broadcasting != 0) {
            ArrayList<Object> arrayList = removeAfterBroadcast.get(id);
            if (arrayList == null) {
                arrayList = new ArrayList<>();
                removeAfterBroadcast.put(id, arrayList);
            }
            arrayList.add(observer);
            return;
        }
        ArrayList<Object> objects = observers.get(id);
        if (objects != null) {
            objects.remove(observer);
        }
    }
}

然后让你的Activities看起来像这样,你在didReceivedNotification()中收到来自Service的消息

public class YourActivity implements NotificationCenter.NotificationCenterDelegate {

    @Override
    public void onPause() {
        NotificationCenter.getInstance().removeObserver(this, NotificationCenter.updateActivity);
        super.onPause();
    }

    @Override
    public void onResume() {
        NotificationCenter.getInstance().addObserver(this, NotificationCenter.updateActivity);
        super.onResume();
    }

    @Override
    public void didReceivedNotification(int id, Object... args) {
        if (id == NotificationCenter.updateActivity) {
            // do something with your activity, your service called this
        }
    }
}

最后将您的Service 中的消息发送给所有正在收听的Activities

NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateActivity, optionalData);

这很好,你不必传递 Activity 实例。

NotificationCenter 来源来自 Telegram。

【讨论】:

  • 不,我需要当前活动的具体上下文。当用户更改应用程序中的页面时,服务的反应应该会发生变化。这是否意味着我可以设置一个起始活动,然后在每个 intent.startActivity() 之前调用 setActivity() 方法?
  • 是的,确保您的Service 具有初始化的Activity,然后实际运行Service
  • 哦,你的意思是我应该在启动服务之前传递上下文,而不是活动?所以第一步是设置activity,接下来启动服务,当activity改变时应该传递另一个上下文,服务重启?无论如何,我会看看通知方法。
  • 没错!您应该这样做以防止 NullpointerException
  • 所以我肯定需要尝试一下通知。一旦应用程序弹出并在后台一直运行,我就有一项服务正在启动。它基本上保持 TCP 连接打开并且应该处理传入的数据包和更新活动,这就是我需要上下文的原因。
【解决方案2】:
public class myService extends Service
{
 public static myActivity activity;

 public static void setActivity(myActivity activity)
 {
     this.activity = activity;
 }
 public void useActivityExample()
{
  myService.myActivity.update();
 }
}

public class myActivity extends AppCompatActivity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
   {
       // ... some things are being executed and myService is being bound
      mService.setActivity(getActivity());
   }
}

【讨论】:

  • 我不能使用 myActivity 作为 myService 中的活动类型,因为我想使用多个自定义活动并且它们不适合。也无法解析 getActivity()。
  • 对不起不是getActivity它实际上是getContext,或者myActivity.this
猜你喜欢
  • 1970-01-01
  • 2016-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-04
  • 1970-01-01
  • 2016-08-29
  • 1970-01-01
相关资源
最近更新 更多