I am using A Singleton Class for holding some data through out of application Which is some Queue.
I am creating Singleton Class Instance onCreate
method of my Application
Class.
@Override
public void onCreate() {
super.onCreate();
mInstance = this;
mContext = getApplicationContext();
Queue.getInstance(); // this is my singleton class instance
}
After this I am adding data inside of this singleton class in my activities
Queue.getInstance().addItem(qItem);
Log.d(Constants.TAG, "Added Item Queue Size: "+Queue.getInstance().getQueueList().size());
Until this Everything working fine. I can access data in my Activities
and ListView Adapter
however When I Start Service and try to access data onCreate
of service
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();
My Singleton Instance become null and my singleton creates new instance. Which cause my data loss inside of Service.
Following is flow of my error.
Following is the code of my Singleton Class
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>
You are running your Service
in a different process which is not the same as your Application
context, that's why the Queue turns out to by null in the new process.
Remove the following from your Service
in manifest and you are good to go:
android:process=":main"
Moreover, I would suggest you to make use of HandlerThread
in your service to offload some heavy operations.
Ok, here is the thread-safe version.
// 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;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.