单例模式“不允许访问构造函数”

时间:2014-11-30 07:11:54

标签: java android service constructor singleton

我是Java的新手,也是自学成才的,所以我希望我会缺少一些基本的理解。

背景:我正在使用我希望加入服务的蓝牙,以便我可以将收到的信息广播到多个活动中。这适用于我的MainActivity,但不适用于任何其他人。无论何时从设备读取任何其他活动的蓝牙特性,它都无法读取并崩溃程序。我发现在广播之前该特性是非空的,但是只要它被接收就是空的。我认为这是由于错误地创建了两个服务实例并从一个从未处理过的实例中读取。因此,为了消除这种可能性,我想将我的服务创建为单身人士。 (我想保留关于主题的问题所以不会问,但建议表示赞赏。)

所以,我需要一个服务(BluetoothService)的单个实例,我用它来运行和处理一些蓝牙操作。我遇到了单身人士的设计模式,这似乎就像我将要追求的那样。我按照各种来源在线描述的方式实现了它:

    private static BluetoothService serviceInstance;
    private BluetoothService() {} // Error occurs here

    public static BluetoothService getSharedBluetoothService() {
        if(serviceInstance == null)
            serviceInstance = new BluetoothService();
        return serviceInstance;
    }

当Activity尝试绑定到服务时,我在Activity中定义了如此定义的binder类:

public class BtBinder extends Binder {
    BluetoothService getService() {
        return getSharedBluetoothService(); // returns reference to current service
        //return BluetoothService.this; // Line used prior to introducing a Singleton pattern.
    }
}

如果我正确理解错误,私有构造函数会导致我的MainActivity出错 - 它无法实例化Service,因为它的构造函数是私有的。如果构造函数是公共的,则MainActivity无法绑定到Service。 onBind()永远不会调用,导致其他地方出现空指针异常。

我在哪里错了?据我所知,我遵循了正确的程序。我不知道该往哪里转。

编辑: 宾德:

@Override
public IBinder onBind(Intent intent) {
    Log.d(TAG, "Currently binding");
    BluetoothManager manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
    mBluetoothAdapter = manager.getAdapter();   
    return myBinder; // When bound, return the whole MyLocalBinder Binder.
}

MainActivity:

public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
    // ...
    BluetoothService BtService;
    boolean isBound = false;

    BluetoothBroadcast btSetupReceiver = null;
    BluetoothBroadcast resultsReceiver = null;
    boolean receiversAreRegistered = false;

        private static final String TAG = "BluetoothGattActivity";
        private static final String DEVICE_NAME = "Suspensionometer 3333";

        private BluetoothAdapter mBluetoothAdapter;
        private SparseArray<BluetoothDevice> mDevices;

        private BluetoothGatt mConnectedGatt;

        private ProgressDialog mProgress;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // Bind the service
            Intent intent = new Intent(this, BluetoothService.class);
            Log.d(TAG, "Attempting to bind to service.");
            bindService(intent, btServiceConnection, Context.BIND_AUTO_CREATE);

            // Set up BroadcastReceiver
            btSetupReceiver = new BluetoothBroadcast(){

            @Override
            public void onReceive(Context context, Intent intent) 
            {               
                // ...
        };

        resultsReceiver = new BluetoothBroadcast() {
            @Override
            public void onReceive(Context context, Intent intent)
            {
                // ...
        };
    }

2 个答案:

答案 0 :(得分:2)

您无法将您的服务构造函数设为私有。 Android需要能够创建许多组件以响应设备上发生的事件。例如,Android可以创建Service类的实例以响应意图。

您可以做的是设置一个单独的单例对象来完成您的工作,并在您的服务中获取该对象。但是,请注意服务的生命周期。如果您的服务是为响应intent或startService调用而启动的,那么该服务运行的时间取决于onStartCommand(START_STICKY等)的返回值。该文档给出了一个很好的概述: http://developer.android.com/reference/android/app/Service.html

编辑:

听起来你只需要一个共同的地方来存储你的服务数据,然后当其中一个活动绑定到服务并请求它时,Android创建的任何服务实例都可以获取该数据。 。看起来你正在使用&#34; LocalService&#34;文档中的模式,这听起来是正确的事情。

我不知道您的蓝牙数据有多复杂,但在Android中存储数据的最常见方式是SharedPreferences(对于更简单的键/值数据)和数据库。如果您认为可以使用SharedPreferences,那么您可以使用JSON将相当多的复杂性存储为长字符串。

如果您的数据太复杂或者更基于表格,那么Android会附带SQLiteDatabase和相关类,还会提供ContentProvider类,它提供对数据库的URI类型访问。

我是否朝着正确的方向前进?我现在就停下来,但如果您需要更多解释,或者我已经离开了轨道,请告诉我。

答案 1 :(得分:0)

将违规私有更改为受保护,它应该可以解决问题。

在这个伟大的博客上阅读单身人士:http://www.javaworld.com/article/2073352/core-java/simply-singleton.html