Reputation: 1318
I am facing a problem, that I created a class Controller
it is singleton but its object is recreating when I access in different activity of same application,
Main_Activity is my launching activity
public class Main_Activity extends Activity{
private Controller simpleController;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
simpleController = Controller.getInstance(this);
}
}
This is my Controller
it is singleton, in it I am setting alarm which is of 10sec from now and my MyMainLocalReciever
receives that alarm and notify using notification.
public class Controller {
private MediaPlayer mp;
public Context context;
private static Controller instance;
public static Controller getInstance(Context context) {
if (instance == null) {
instance = new Controller(context);
}
return instance;
}
private Controller(Context context) {
Log.d("TAG", "Creating Controller object");
mp = null;
this.context = context;
setAlarm(10);
}
public void setAlarm(int position) {
Intent intent = new Intent(context, MyMainLocalReciever.class);
intent.putExtra("alarm_id", "" + position);
PendingIntent sender = PendingIntent.getBroadcast(context,
position, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Get the AlarmManager service
AlarmManager am = (AlarmManager) context
.getSystemService(Activity.ALARM_SERVICE);
am.cancel(sender);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ (position*1000), sender);
}
}
This is my receiver MyMainLocalReciever
it notify and I am binding an intent which starts an activity called NotificationDialog
public class MyMainLocalReciever extends BroadcastReceiver {
private NotificationManager notificationManager;
private int alarmId = 0;
@Override
public void onReceive(Context context, Intent intent) {
if (notificationManager == null) {
notificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
}
Bundle bundle = intent.getExtras();
String alarm_Id = bundle.getString("alarm_id");
try {
alarmId = Integer.parseInt(alarm_Id);
} catch (Exception e) {
Log.d("Exception", "exception in converting");
}
Controller myC = Controller.getInstance(context);
if ((myC.getMp() != null)) {
myC.getMp().stop();
myC.setMp(null);
}
if (myC.getMp() == null) {
myC.setMp(MediaPlayer.create(context , R.id.mpFile));
myC.getMp().start();
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setTicker("Its Ticker")
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Its Title")
.setContentText("Its Context")
.setAutoCancel(true)
.setContentIntent(
PendingIntent.getActivity(context, 0, new Intent(context,
NotificationDialog.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK), 0));
notificationManager.notify("interstitial_tag", alarmId,
builder.getNotification());
}
}
Till now(before NotificationDialog
) code is working perfect MediaPlayer
object which is in Controller
class is working fine too, but when I access my singleton Controller
here in NotificationDialog
, it is creating new object of Controller, it should not do that, it should retain that Controller
object which is singleton.
public class NotificationDialog extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.notification_dialog);
}
public void onViewContent(View v) { //this method is invoked when I click on a button binded in xml file
Controller myC = Controller.getInstance(getApplicationContext());
if (myC.getMp() != null) {
myC.getMp().stop();
myC.setMp(null);
}
finish();
}
}
Kindly help me regarding this, I will appreciate your help. Regards
EDIT: Here is my Manifest
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".Main_Activity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="test.SettingsActivity"
android:label="@string/app_name" />
<activity
android:name="test.NotificationDialog"
android:label="@string/app_name" />
<service android:name="test.MyService" >
</service>
<receiver
android:name="test.MyMainLocalReciever"
android:process=":remote" />
</application>
Upvotes: 4
Views: 2001
Reputation: 95578
Your process is getting killed by Android when it is idle in the background. Android will kill off your process if there are no active components (Activities, Services, etc.) or when it needs the memory (even if you have active components).
When the user uses your notification, Android creates a new process for you. That is why the Singleton is gone and needs to get recreated.
EDIT:
After you posted your manifest I immediately saw the problem. This is it:
<receiver
android:name="test.MyMainLocalReciever"
android:process=":remote" />
Your process isn't getting killed. Your BroadcastReceiver is running in another separate process. In that process, the singleton hasn't been set up yet.
Remove android:process=":remote"
from your <receiver>
tag in the manifest.
Upvotes: 6
Reputation: 7892
As the Singleton will be a static object used by many Activities, you don't have to pass the Context to the constructor. Passing it to the methods which will need it, is a better option.
public class Controller {
private static volatile Controller instance = null;
private Controller () { }
public static Controller getInstance() {
if (instance == null) {
synchronized (Controller .class)
if (instance == null) {
instance = new Controller();
}
}
return instance;
}
public void setAlarm(Context context, int position) {
// do stuff
}
}
Upvotes: 0
Reputation: 1854
Please read about the Initialization-on-demand holder idiom. It's very clear and simple article about right Singleton in the Java programming language.
Upvotes: 1