从Service类调用活动类方法

时间:2014-05-10 20:34:11

标签: android service

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

活动类:

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

服务类:

   @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 
  }

7 个答案:

答案 0 :(得分:87)

定义服务将用于传达事件的接口:

public interface ServiceCallbacks {
    void doSomething();
} 

编写您的服务类。您的活动将绑定到此服务,因此请按照sample shown here进行操作。另外,我们将添加一个方法来设置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;
    }
}

按照相同的指南编写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() {
        ...
    }
}

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

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

答案 1 :(得分:5)

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

  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);
            }
     }
    
  2. 要获得完整的代码,请检查此 link

答案 2 :(得分:2)

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

我的服务:

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);
    }
}

委托课程:

package com.some.package;

public class Delegate {
    static MainActivity theMainActivity;
}

我在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);
}

答案 3 :(得分:0)

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

答案 4 :(得分:0)

您可以通过服务致电

 getContentResolver().notifyChange(uri, null);

并在您的活动中设置了

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

onChange方法将调用UI线程

答案 5 :(得分:0)

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

您可以考虑像这样在runOnUiThread中运行您的活动方法:

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

答案 6 :(得分:0)

我更喜欢使用一些非常简单和干净的解决方案 EventBus