Android 从服务类调用活动类方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23586031/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 07:17:21  来源:igfitidea点击:

Calling activity class method from Service class

androidservice

提问by Siju

I have seen many posts in SO regarding this but could not get the exact and most easy way to call an activity method from service class. Is broadcast receiver only the option? No easy way out ? I just need to call the following method in Activity class after the media player is prepared in Service class .

我在 SO 中看到了很多关于此的帖子,但无法获得从服务类调用活动方法的准确和最简单的方法。广播接收器是唯一的选择吗?没有捷径 ?在 Service 类中准备好媒体播放器后,我只需要在 Activity 类中调用以下方法。

Activity class:

活动类:

    public void updateProgress() {
    // set Progress bar values
    songProgressBar.setProgress(0);
    songProgressBar.setMax(100);
    // Updating progress bar
    updateProgressBar();
}

Service class:

服务等级:

   @Override
public IBinder onBind(Intent intent) {
    Log.d(this.getClass().getName(), "BIND");
    return musicBind;
}

@Override
public boolean onUnbind(Intent intent) {
    return false;
}
    @Override
public void onPrepared(MediaPlayer mp) {
    try {
        mp.start();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    }

           // updateProgress();// Need to call the Activity method here 
  }

回答by Karakuri

Define an interface your Service will use to communicate events:

定义一个你的服务将用来传达事件的接口:

public interface ServiceCallbacks {
    void doSomething();
} 

Write your Service class. Your Activity will bind to this service, so follow the sample shown here. In addition, we will add a method to set the ServiceCallbacks.

编写您的服务类。您的 Activity 将绑定到此服务,因此请按照此处显示示例进行操作。此外,我们将添加一个方法来设置ServiceCallbacks.

public class MyService extends Service {
    // Binder given to clients
    private final IBinder binder = new LocalBinder();
    // Registered callbacks
    private ServiceCallbacks serviceCallbacks;


    // Class used for the client Binder.
    public class LocalBinder extends Binder {
        MyService getService() {
            // Return this instance of MyService so clients can call public methods
            return MyService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    public void setCallbacks(ServiceCallbacks callbacks) {
        serviceCallbacks = callbacks;
    }
}

Write your Activity class following the same guide, but also make it implement your ServiceCallbacks interface. When you bind/unbind from the Service, you will register/unregister it by calling setCallbackson the Service.

按照相同的指南编写您的 Activity 类,但也要使其实现您的 ServiceCallbacks 接口。当您从服务绑定/取消绑定时,您将通过调用setCallbacks服务来注册/取消注册。

public class MyActivity extends Activity implements ServiceCallbacks {
    private MyService myService;
    private boolean bound = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(...);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // bind to Service
        Intent intent = new Intent(this, MyService.class);
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // Unbind from service
        if (bound) {
            myService.setCallbacks(null); // unregister
            unbindService(serviceConnection);
            bound = false;
        }
    }

    /** Callbacks for service binding, passed to bindService() */
    private ServiceConnection serviceConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            // cast the IBinder and get MyService instance
            LocalBinder binder = (LocalBinder) service;
            myService = binder.getService();
            bound = true;
            myService.setCallbacks(MyActivity.this); // register
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            bound = false;
        }
    };

    /* Defined by ServiceCallbacks interface */
    @Override
    public void doSomething() {
        ...
    }
}

Now when your service wants to communicate back to the activity, just call one of the interface methods from earlier. Inside your service:

现在,当您的服务想要与活动进行通信时,只需调用之前的接口方法之一。在您的服务中:

if (serviceCallbacks != null) { 
    serviceCallbacks.doSomething();
}

回答by Mukesh Y

Use Broadcast receiver with service for updating your view from the service class. For example:

使用带有服务的广播接收器从服务类更新您的视图。例如:

  1. In my activity class

    public class ServiceDemoActivity extends Activity {
    
        Intent intent;
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            final TextView notification = (TextView) findViewById(R.id.notification);
            if (CheckIfServiceIsRunning()) {
    
            } else {
                startService(new Intent(this, MyService.class));
            }
        }
    
        private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                updateDate(intent);
            }
        };
    
        private void updateDate(Intent intent) {
            String time = intent.getStringExtra("time");
            Toast.makeText(getApplicationContext(), "Yea!!! Service called", Toast.LENGTH_SHORT).show();
            TextView date = (TextView) findViewById(R.id.date);
            date.setText(time);
        }
    
        @Override
        public void onResume() {
            super.onResume();
            registerReceiver(broadcastReceiver, new IntentFilter(
                    MyService.BROADCAST_ACTION));
        }
    }
    

    And in my service class I am calling my update ui after a few interval of time which updates my UI.

    public class MyService extends Service {    
    
            public static final String
            BROADCAST_ACTION = "com.mukesh.service";    
            private final Handler handler = new Handler();
    
    
            @Override
            public void onCreate() {
    
                intent = new Intent(BROADCAST_ACTION);
            }
    
            @Override   
            public void onDestroy() {
    
                stopService(intent);
            }
    
            @Override
            public void onStart(Intent intent, int startid) {
                int i = 0;
                while (i <= 2) {
                    if (i > 1) {
                        i++;
                        this.onDestroy();
                    } else {
                        counter = i;
                        i++;
                        handler.removeCallbacks(sendUpdatesToUI);
                        handler.postDelayed(sendUpdatesToUI, 1 * 1000); // 1 sec
                    }
                }       
            }
    
            private Runnable sendUpdatesToUI = new Runnable() {
                public void run() {
                    DisplayLoggingInfo();           
                            handler.postDelayed(this, 7 * 1000); // 7 sec
                }
            };
    
            private void DisplayLoggingInfo() {  
                intent.putExtra("time", new Date().toLocaleString());
                intent.putExtra("counter", String.valueOf(counter));
                sendBroadcast(intent);
                stopService(intent);
            }
     }
    
  1. 在我的活动课上

    public class ServiceDemoActivity extends Activity {
    
        Intent intent;
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            final TextView notification = (TextView) findViewById(R.id.notification);
            if (CheckIfServiceIsRunning()) {
    
            } else {
                startService(new Intent(this, MyService.class));
            }
        }
    
        private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                updateDate(intent);
            }
        };
    
        private void updateDate(Intent intent) {
            String time = intent.getStringExtra("time");
            Toast.makeText(getApplicationContext(), "Yea!!! Service called", Toast.LENGTH_SHORT).show();
            TextView date = (TextView) findViewById(R.id.date);
            date.setText(time);
        }
    
        @Override
        public void onResume() {
            super.onResume();
            registerReceiver(broadcastReceiver, new IntentFilter(
                    MyService.BROADCAST_ACTION));
        }
    }
    

    在我的服务类中,我在更新我的 UI 的几个时间间隔后调用我的更新 ui。

    public class MyService extends Service {    
    
            public static final String
            BROADCAST_ACTION = "com.mukesh.service";    
            private final Handler handler = new Handler();
    
    
            @Override
            public void onCreate() {
    
                intent = new Intent(BROADCAST_ACTION);
            }
    
            @Override   
            public void onDestroy() {
    
                stopService(intent);
            }
    
            @Override
            public void onStart(Intent intent, int startid) {
                int i = 0;
                while (i <= 2) {
                    if (i > 1) {
                        i++;
                        this.onDestroy();
                    } else {
                        counter = i;
                        i++;
                        handler.removeCallbacks(sendUpdatesToUI);
                        handler.postDelayed(sendUpdatesToUI, 1 * 1000); // 1 sec
                    }
                }       
            }
    
            private Runnable sendUpdatesToUI = new Runnable() {
                public void run() {
                    DisplayLoggingInfo();           
                            handler.postDelayed(this, 7 * 1000); // 7 sec
                }
            };
    
            private void DisplayLoggingInfo() {  
                intent.putExtra("time", new Date().toLocaleString());
                intent.putExtra("counter", String.valueOf(counter));
                sendBroadcast(intent);
                stopService(intent);
            }
     }
    

For complete code check this link

有关完整的代码,请检查此链接

回答by fenadoruk

I created a general class called Delegate (it's not a special name, you can name it John) and passed MainActivity class into it as a static field. Then I can access it from the service since its global now. I am not sure if it is cost-effective but it solved the problem for me simple.

我创建了一个名为 Delegate 的通用类(它不是一个特殊名称,您可以将其命名为 John)并将 MainActivity 类作为静态字段传递给它。然后我可以从服务访问它,因为它现在是全球性的。我不确定它是否具有成本效益,但它为我解决了简单的问题。

My service:

我的服务:

package com.some.package;
import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;

public class FirebaseInstanceIDService extends FirebaseInstanceIdService {

    @Override
    public void onTokenRefresh() {
        String token = FirebaseInstanceId.getInstance().getToken();
        Delegate.theMainActivity.onDeviceTokenChange(token);
    }
}

Delegate class:

委托类:

package com.some.package;

public class Delegate {
    static MainActivity theMainActivity;
}

What I did in MainActivity:

我在 MainActivity 中做了什么:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Delegate.theMainActivity = this;

    //rest of the code...
}

public void onDeviceTokenChange(String token){
    Log.e("updated token:", token);
}

回答by Zohab Ali

You can call a method of activity from service by implementing your own listener like this https://stackoverflow.com/a/18585247/5361964

您可以通过像这样实现自己的侦听器来从服务调用活动方法 https://stackoverflow.com/a/18585247/5361964

You might consider running your activity method in runOnUiThreadlike this:

您可能会考虑runOnUiThread像这样运行您的活动方法:

    // method will be called from service
    override fun callback(activity: Activity, result: String) {
        runOnUiThread{
            Toast.makeText(activity, result, Toast.LENGTH_LONG).show()
        }
    }

回答by Onur

You can't call your sevices method direcly from your activity or vise versa. There are 3 ways to communicate with a service; using broadcasters and receivers, using Messengeror binding to the service. For further information look at http://developer.android.com/guide/components/bound-services.html

您不能直接从您的活动中调用您的服务方法,反之亦然。有 3 种方式与服务通信;使用广播器和接收器,使用Messenger或绑定到服务。有关更多信息,请查看http://developer.android.com/guide/components/bound-services.html

回答by asaf gitai

You can call from your service

您可以从您的服务中拨打电话

 getContentResolver().notifyChange(uri, null);

and in your activity you set up a

在您的活动中,您设置了一个

getContentResolver().registerContentObserver(uri, false, new ContentObserver(getHandler())
{
    public void onChange(boolean selfChange)
    {
        updateProgress()
    }
};

the onChange method will ba called on the UI thread

onChange 方法将在 UI 线程上调用