Android服务创建Singleton类的新实例

时间:2014-07-08 07:05:27

标签: java android singleton android-service

我正在使用A Singleton Class来保存一些数据,这些数据来自应用程序,这是一些Queue。

我正在创建onCreate类的单例类实例Application方法。

 @Override
 public void onCreate() {
    super.onCreate();
    mInstance = this;
    mContext = getApplicationContext();
    Queue.getInstance(); // this is my singleton class instance
  }

在此之后,我在我的活动中添加了这个单例类的数据

Queue.getInstance().addItem(qItem);
Log.d(Constants.TAG, "Added Item Queue Size: "+Queue.getInstance().getQueueList().size());

直到这一切工作正常。我可以访问ActivitiesListView Adapter中的数据,但是当我启动服务并尝试访问服务的数据onCreate

Log.d(Constants.TAG, "Playing Item Queue Size: "+Queue.getInstance().getQueueList().size()+" Current Item No. "+Queue.getInstance().getCurrentPlayingItem());
String url = Queue.getInstance().getQueueItem(Queue.getInstance().getCurrentPlayingItem()).getLinkUrl();

我的单例实例变为空,我的单例创建新实例。这导致我的服务内部数据丢失。

以下是我的错误流程。

  1. 启动应用程序创建实例 - 工作
  2. 从活动和适配器添加数据 - 工作
  3. 启动服务和访问数据 - 不工作,因为Singleton 实例在服务中变为空
  4. 以下是我的Singleton类的代码

    import java.util.ArrayList;
    
    import com.taazi.utils.Constants;
    
    import android.util.Log;
    
    public class Queue {
        private ArrayList<QueueItem> mQueueList;
        static Queue mInstance;
        private int currentPlayingItem=0;
    
        private Queue(){
            mQueueList = new ArrayList<QueueItem>();
        }
    
        public static Queue getInstance(){
            if(mInstance == null){
                mInstance = new Queue();
                Log.d(Constants.TAG, "New Instance");
            }
            return mInstance;
        }
    
        public void addItem(QueueItem item){
            mQueueList.add(item);
        }
    
        public void removeItem(int position){
            mQueueList.remove(position);
        }
    
        public ArrayList<QueueItem> getQueueList(){
            return mQueueList;
        }
    
        public QueueItem getQueueItem(int position){
            return mQueueList.get(position);
        }
    
        public int getCurrentPlayingItem() {
            return currentPlayingItem;
        }
    
        public void setCurrentPlayingItem(int currentPlayingItem) {
            this.currentPlayingItem = currentPlayingItem;
        }
    
    
    }
    

    AudioPlayBackService.Java

    package com.taazi.services;
    
    import android.app.Service;
    import android.content.Intent;
    import android.media.MediaPlayer;
    import android.net.Uri;
    import android.os.IBinder;
    import android.util.Log;
    
    import com.taazi.helper.NotificationHelperNew;
    import com.taazi.models.Queue;
    import com.taazi.models.QueueItem;
    import com.taazi.utils.Constants;
    
    public class AudioPlayBackService extends Service {
    
        /**
         * Called to go toggle between pausing and playing the music
         */
        public static final String TOGGLEPAUSE_ACTION = "com.taazi.services.togglepause";
    
        /**
         * Called to go to pause the playback
         */
        public static final String PAUSE_ACTION = "com.taazi.services.pause";
    
        /**
         * Called to go to stop the playback
         */
        public static final String STOP_ACTION = "com.taazi.services.stop";
    
        /**
         * Called to go to the previous track
         */
        public static final String PREVIOUS_ACTION = "com.taazi.services.previous";
    
        /**
         * Called to go to the next track
         */
        public static final String NEXT_ACTION = "com.taazi.services.next";
    
        /**
         * Used to build the notification
         */
        private NotificationHelperNew mNotificationHelper;
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        MediaPlayer player;
    
        @Override
        public void onCreate() {
            super.onCreate();
         // Initialize the notification helper
            mNotificationHelper = new NotificationHelperNew(this);
    
            Log.d(Constants.TAG, "Playing Item Queue Size: "+Queue.getInstance().getQueueList().size()+" Current Item No. "+Queue.getInstance().getCurrentPlayingItem());
            String url = Queue.getInstance().getQueueItem(Queue.getInstance().getCurrentPlayingItem()).getLinkUrl();
            player = MediaPlayer.create(this, Uri.parse(url));
            player.setLooping(false); // Set looping
            updateNotification();
        }
        public int onStartCommand(Intent intent, int flags, int startId) {
            player.start();
            return 1;
        }
    
        public void onStart(Intent intent, int startId) {
            // TO DO
        }
        public IBinder onUnBind(Intent arg0) {
            // TO DO Auto-generated method
            return null;
        }
    
        public void onStop() {
    
        }
        public void onPause() {
    
        }
        @Override
        public void onDestroy() {
            mNotificationHelper.killNotification();
            player.stop();
            player.release();
        }
    
        @Override
        public void onLowMemory() {
    
        }
    
        /**
         * Updates the notification, considering the current play and activity state
         */
        private void updateNotification() {
            QueueItem item =  Queue.getInstance().getQueueItem(Queue.getInstance().getCurrentPlayingItem());
                mNotificationHelper.buildNotification("", item.getArtist(),
                        item.getTitle(), (long)50, null, true);
        }
    
    }
    

    的AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        package="com.taazi.android"
        android:versionCode="1"
        android:versionName="1.0" >
    
        <uses-sdk
            android:minSdkVersion="10"
            android:targetSdkVersion="20" />
    
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <uses-permission android:name="android.permission.WRITE_SETTINGS" />
        <uses-permission android:name="android.permission.GET_TASKS" />
    
    
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
    
        <uses-permission android:name="android.permission.WAKE_LOCK" />
    
        <application
            android:name="com.taazi.app.AppController"
            android:allowBackup="true"
            android:hardwareAccelerated="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/Theme.Apptheme" >
            <activity
                android:name="com.taazi.activities.MainActivity"
                android:label="@string/app_name"
                android:screenOrientation="portrait" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
            <!-- Music service -->
            <service
                android:name="com.taazi.services.AudioPlayBackService"
                android:label="@string/app_name"
                android:process=":main" />
    
        </application>
    
    </manifest>
    

2 个答案:

答案 0 :(得分:5)

您正在使用与Service上下文不同的其他流程运行Application,这就是 null 导致问题归结的原因在新的过程中。

从清单中的Service中删除以下内容,您就可以了:

android:process=":main"

此外,我建议您在服务中使用HandlerThread来卸载一些繁重的操作。

答案 1 :(得分:1)

好的,这是线程安全的版本。

    // package, imports ...

    public class Queue {

        // Make 100% sure your QueueItem class is immutable! Otherwise it will not be thread safe!
        // Also, it makes more sense (more readable) to put your QueueItem together with your Queue class 
        public static class QueueItem {
            //...
        }

        // changed the below line - was: private ArrayList<String> mQueueList; 
        // (search for programming against an interface rather than an implementation)
        private List<QueueItem> mQueueList; 
        static Queue mInstance;
        private int currentPlayingItem=0;

        private Queue() {
            // See javadoc on the synchronizedList() method. 
            mQueueList = Collections.synchronizedList(new ArrayList<QueueItem>());
        }

        // Added synchronized keyword below 
        public synchronized static Queue getInstance(){
            if(mInstance == null){
                mInstance = new Queue();
                Log.d(Constants.TAG, "New Instance");
            }
            return mInstance;
        }

        // Thread safe as it is (provided that QueueItem is immutable)
        public void addItem(QueueItem item){
            mQueueList.add(item);
        }

        // Thread safe as it is
        public void removeItem(int position){
            mQueueList.remove(position);
        }

        // This method is actually inherently flawed, remove this method - you should never need 
        // mQueueList - if you do need this method then your code is structured wrong.
        // changed the below line - was: public ArrayList<QueueItem> getQueueList(){
        /*public List<QueueItem> getQueueList(){
            return mQueueList;
        }*/

        // Thread safe as it is (provided that QueueItem is immutable) 
        public QueueItem getQueueItem(int position){
            return mQueueList.get(position);
        }

        // Made this method synchronized (and thus thread safe) - very unlikely to cause performance issue.
        public synchronized int getCurrentPlayingItem() {
            return currentPlayingItem;
        }

        // Made this method synchronized (and thus thread safe) - very unlikely to cause performance issue.
        public synchronized void setCurrentPlayingItem(int currentPlayingItem) {
            this.currentPlayingItem = currentPlayingItem;
        }


    }