我正在使用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());
直到这一切工作正常。我可以访问Activities
和ListView 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();
我的单例实例变为空,我的单例创建新实例。这导致我的服务内部数据丢失。
以下是我的错误流程。
以下是我的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>
答案 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;
}
}