Long story short, I have a class that handles my app shared preferences.
I call it from various other classes without issues, but when I try to call it from my service (from the same APK) I get a null exception. I am guessing that it's getting called from the wrong context or something like that. Here is the relevant code.
MainActivity.java
package com.deskwizard.audiomanager;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import com.deskwizard.audiomanager.DataSaveRestore;
public class MainActivity extends FragmentActivity {
public static Context contextOfApplication;
final FragmentManager fm = getFragmentManager();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
contextOfApplication = getApplicationContext();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragment_settings, new FadeBalanceFragment());
ft.commit();
// TODO: Load previously saved settings for all values
DataSaveRestore.restore_all();
// TODO: init I2C
}
public static Context getContextOfApplication() {
return contextOfApplication;
}
}
DataSaveRestore.java (defaultpreferences class)
package com.deskwizard.audiomanager;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
public class DataSaveRestore extends Application {
// Data variables
public static int Bass_level, Bass_CFreq, Bass_Qfact, Sub_level,
Sub_Lowpass, Treble_level, Treble_CFreq, Mid_level, Mid_CFreq,
Mid_Qfact, Fade, Balance, Loudness_level, Loudness_freq,
Loudness_boost;
static boolean Bass_DCMode, Loudness_state;
static Context applicationContext = MainActivity.getContextOfApplication();
public static void restore_all() {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(applicationContext);
if (prefs.getInt("data_saved", 0) == 0) {
set_defaults();
load_defaults();
} else {
load_defaults();
}
//TODO: send settings to TDA7418
DS3903.set_lowpass(DataSaveRestore.Sub_Lowpass);
};
Service code snippet:
public class AudioManagerService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO do something useful
Log.d("com.deskwizard.audiomanager", "starting service...");
DataSaveRestore.restore_all(); // restore settings to TDA7418/DS3903
start();
return Service.START_STICKY;
}
The Null Exception error refers to this line, only when called from the service, it works properly from the main application and other classes:
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(applicationContext);
Let me know if any further code can help narrow it down.
Thanks,
DW
Because, In your service when you call, DataSaveRestore.restore_all(); It make reference on, (As there is no MainActivity context available from Servce)
static Context applicationContext = MainActivity.getContextOfApplication();
on this line, applicationContext will be null as it can't find MainActivity initialization
Simply, Just change your restore_all() method from Application class.
First remove static and and use getApplicationContext() of Android application class method to get application context as in Service,
public void restore_all() {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
if (prefs.getInt("data_saved", 0) == 0) {
set_defaults();
load_defaults();
} else {
load_defaults();
}
//TODO: send settings to TDA7418
DS3903.set_lowpass(DataSaveRestore.Sub_Lowpass);
};
Now call, restore_all(); by initializing object of Application class not a static way.
Like,
DataSaveRestore dataSaveRestore = (DataSaveRestore) getApplicationContext();
dataSaveRestore.restore_all();
Related
I'm trying to stub a getExtras() call on a mocked intent but it seems when()...thenReturn() doesn't work (returns NULL) when I use any of the TelephonyManager string constants. I've tried using dummy strings and it works so I know the test isn't working because of the when()...thenReturn() calls.
Here's my code
package metabrick.com.notrightnow;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.runners.MockitoJUnitRunner;
import metabrick.com.notrightnow.CatchingMissedCallsFeature.MissedCallBroadcastReceiver;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertSame;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
#RunWith(MockitoJUnitRunner.class)
/*This class tests the logic of MissedallBroadcastReceiver class logic .i.e
* The logic of detecting a missed phone call*/
public class MissedCallBroadcastReceiverTest {
#Mock private Context context;
#Mock private Intent intent;
#Mock Bundle bundle ;
private MissedCallBroadcastReceiver missedCallBroadcastReceiver;
#Before
public void setUpMissedCallBroadcastReceiver(){
MockitoAnnotations.initMocks(this);
missedCallBroadcastReceiver = new MissedCallBroadcastReceiver();
}
#Test
public void onReceiveTest(){
when(intent.getStringExtra(anyString()))
.thenReturn(telephonyManager.EXTRA_STATE_RINGING);
when(intent.getExtras()).thenReturn(bundle);
when(bundle.getString("incoming_number")).thenReturn("905-456-4520");
//Calling onReceive
missedCallBroadcastReceiver.onReceive(context, intent);
//Verfy that attempt was made to retrieve the state of the phone
verify(intent).getStringExtra(TelephonyManager.EXTRA_STATE);
//verfy that an attempt was made to retrievr the number of the caller
verify(bundle).getString("incoming_number");
/*Testing a received call scenario */
when(intent.getStringExtra(anyString()))
.thenReturn(TelephonyManager.EXTRA_STATE_RINGING)
.thenReturn(TelephonyManager.EXTRA_STATE_OFFHOOK);
missedCallBroadcastReceiver.onReceive(context, intent);
//check that the callRinging variable is set to true
assertTrue(missedCallBroadcastReceiver.isCallRinging());
//check that the callReceived variable is set to true
assertTrue(missedCallBroadcastReceiver.isCallReceived());
/*Testing a missed call scenario */
when(intent.getStringExtra(anyString()))
.thenReturn(TelephonyManager.EXTRA_STATE_RINGING)
.thenReturn(TelephonyManager.EXTRA_STATE_IDLE);
missedCallBroadcastReceiver.onReceive(context, intent);
//check that the callReceived and ringing variables are set to false
assertFalse(missedCallBroadcastReceiver.isCallReceived());
assertFalse(missedCallBroadcastReceiver.isCallRinging());
// checking that the number gotten from the intent
assertSame("905-456-4520", missedCallBroadcastReceiver.getCallerNumber());
}
}
Here's the method under test
#Override
public void onReceive(Context context, Intent intent) {
//Getting the phone state
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if(state == null) return;
//Getting the caller's number
callerNumber = intent.getExtras().getString("incoming_number");
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) rang = true;
if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) callReceived = true;
//if the phone is idle
if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)){
if (ringing&&!callReceived){
ringing = false;
try{
Toast.makeText(context, "Missed call", Toast.LENGTH_LONG).show();
}catch (Exception e){
e.printStackTrace();
}
}
callReceived = false;
}
}
I've searched for a while now I can't find any answers and I don't know how else to stub the intent for these calls to getExtras(). Can anyone help me out?
SharedPrefencesChangeListener is not working in this code. Please point out if anything is missed.
I am wondering if it is happening because I have declared it in a service.
Code to change the SharedPreferences from another activity:
getSharedPreferences("TRACKER", Context.MODE_PRIVATE).edit().putString("TRIP_LIST", String.valueOf(trip_list)).apply();
///
package com.tracker;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager;
import org.json.JSONException;
import org.json.JSONObject;
public class SharedPrefMonService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener {
LocalBroadcastManager broadcaster = LocalBroadcastManager.getInstance(this);
public SharedPrefMonService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.unregisterOnSharedPreferenceChangeListener(this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.registerOnSharedPreferenceChangeListener(this);
return Service.START_STICKY;
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(key.equals("TRIP_LIST")){
try {
JSONObject trip_list = new JSONObject(sharedPreferences.getString("TRIP_LIST", "{}"));
if(trip_list.keys().hasNext()){
//start location service
}else{
//stop location service
}
//update trip list view here
Intent intent = new Intent("SharedPrefMonService");
intent.putExtra("updated_trip_list", trip_list.toString());
broadcaster.sendBroadcast(intent);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
It's not that you have the listener in a Service, necessarily. You're not setting the listener on the same SharedPreferences that you're modifying.
Context#getSharedPreferences() creates a SharedPreferences with the name you give it. PreferenceManager.getDefaultSharedPreferences() creates a SharedPreferences from your package name with _preferences appended. They're both ultimately XML files, but a listener on one won't be notified of changes on another.
Either change the SharedPreferences you're modifying to use the default - PreferenceManager.getDefaultSharedPreferences() - or set your listener on the one you're currently saving to - getSharedPreferences("TRACKER", Context.MODE_PRIVATE).
I would also mention that an OnSharedPreferenceChangeListener will only fire when a particular key's value changes. If you save a key with the same value it already had, onSharedPreferenceChanged() won't run.
hi i have created a global actions class and created functions inside this class which i'm trying to access inside another activity the problem i'm having is that in eclipse I'm getting coding errors around the functions that access system feature such as getSystemService() and getApplicationContext() does anyone know why or how to let a global class accept system features?
heres what i have so far heres my GloblActions.java
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
public class GlobalActions{
Context mContext;
// constructor
public GlobalActions(Context context){
this.mContext = context;
}
public final static boolean isOnline (Context someContext){ {
Log.v("globals", "isonline");
ConnectivityManager cm = (ConnectivityManager) someContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
}
return false;
}
}
public final static void checkInternet(Context someContext){
isOnline(someContext);
if(isOnline(someContext) == false){
Log.v("globals", "isOnline = false");
Intent register = new Intent(someContext.getApplicationContext(), LoginForm.class);
someContext.startActivity(register);
}
}
}
heres where i'm using the function in an activity. my goal is is to check internet connection on every activity by just calling the global function and if no connection is found go to an activity that says no internet connection.
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.TextView;
import android.os.Handler;
import com.myApp.myApp.GlobalActions;
public class IntroLoader extends Activity {
public Handler handler;
public TextView loadText = null;
public Animation AniFadein = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lo_introloader);
findViewById(R.id.progressBar1).setVisibility(View.GONE);
findViewById(R.id.loadTextView).setVisibility(View.GONE);
GlobalActions.isOnline(null);
GlobalActions.checkInternet(null);
handler = new Handler();
final Runnable fadeIn = new Runnable()
{
public void run()
{
animations();
findViewById(R.id.progressBar1).setVisibility(View.VISIBLE);
findViewById(R.id.loadTextView).setVisibility(View.VISIBLE);
}
};
handler.postDelayed(fadeIn, 3000);
final Runnable aSyncTask= new Runnable()
{
public void run()
{
PostTask posttask;
posttask = new PostTask();
posttask.execute();
}
};
handler.postDelayed(aSyncTask, 4000);
}
public void animations(){
loadText = (TextView)findViewById(R.id.loadTextView);
AniFadein = AnimationUtils.loadAnimation(this, R.anim.fadein);
loadText.startAnimation(AniFadein);
}
public class PostTask extends AsyncTask<Void, String, Boolean> {
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(Void... params) {
boolean result = false;
publishProgress("progress");
return result;
}
protected void onProgressUpdate(String... progress) {
StringBuilder str = new StringBuilder();
for (int i = 1; i < progress.length; i++) {
str.append(progress[i] + " ");
}
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
checkLoginData();
}
}
public void checkLoginData(){
Intent register = new Intent(getApplicationContext(), LoginForm.class);
startActivity(register);
}
}
Do
ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
Contexts can use the method getSystemService() but your class isn't a Context, you need to use your mContext variable.
This means that you can also replace getApplicationContext() with mContext. And if you really need getApplicationContext() (unlikely - normal Contexts should work fine), use
mContext.getApplicationContext()
Also, you declare your isOnline() method as static, but then you need to use a Context for checking and making the toast. Either don't make it static or change it so it accepts in a Context, eg
public final static boolean isOnline (Context someContext){
And replace calls there that need a Context with someContext. Static methods don't need an instance of the class, and so, you can't use mContext. Once you fix the getApplicationContext() issue you have now, the compiler should throw an error about accessing a non static field in a static way. Same with your checkInternet(). I suggest you revaluate your logic, there are multiple problems with your class - I suggest making everything a static method that accepts in a Context which will be given by the calling Activity.
Lastly be careful about showing Toasts and other UI Elements in a global non-ui class. Toasts should be fine since they run on top of windows, but a Dialog will need a window, and if mContext is not an instance of Activity, that will fail (Activities have a window, other Contexts (like getApplicationContext()), do not.
Anyone know if I can receive my main Activity's onStop, onPause and onResume callbacks inside another class / object?
I've got a broadcast receiver that lives inside another class (a WebView). I use the receiver to detect when the network goes down and switch to a local copy of my page with some useful content. I need to un-register the broadcast receiver when onStop/onPause are called and re-register it during onResume.
I can do this by hand (I added a couple public methods to a class that extends WebView to do just that) , but it'd be nice to have Android just call it for me.
edit: Sure, here's the class, I'd like it to be able to receive get a callback from Android when my main activity's onStop gets called without having to call startInternetMonitoring() / stopInternetMonitoring():
package com.glimmersoft.spent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.util.AttributeSet;
import android.util.Log;
import android.webkit.WebSettings;
import android.webkit.WebView;
/**
* #author Jer
*
*/
public class OfflineWebView extends WebView {
private BroadcastReceiver receiver;
private IntentFilter filter;
private Context myContext;
public OfflineWebView(Context context,AttributeSet attrs) {
super(context, attrs);
WebSettings webSettings = this.getSettings();
webSettings.setJavaScriptEnabled(true);
myContext = context;
}//END CLASS CONSTRUCTTOR
/**
* #param internetOn The URL to display in this OfflineWebView when there is an active Internet connection.
* #param internetOff The URL to display in this OfflineWebView if there is no active Internet connection.
*/
public void setPages(final String internetOn, final String internetOff){
final OfflineWebView finalThisRef = this;
filter = new IntentFilter();
filter.addAction(SpendConstants.ANDROID_CONNECTIVITY_CHANGED);
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager cm=(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if(cm.getActiveNetworkInfo()!=null&&cm.getActiveNetworkInfo().isConnected()){// TODO: THIS FAILES IF
finalThisRef.loadUrl(internetOn);
}else{
finalThisRef.loadUrl(internetOff);
}
}//END IF/ELSE
};
myContext.registerReceiver(receiver, filter);
}//END FUNCTION SETPAGES
public void startInternetMonitoring(){
myContext.registerReceiver(receiver, filter);
}//END METHOD STARTINTERNETMONITORING
public void stopInternetMonitoring(){
myContext.unregisterReceiver(receiver);
}//END METHOD STOPINTERNETMONITORING
}//END CLASS OfflineWebView
Thanks all!
Instead of putting your BroadcastReceiver inside your OfflineWebView, make it a static class you register maybe in a base Activity and have it a hold a reference to your OfflineWebView. When onReceive is called, you can then reference your OfflineWebView to load your online/offline content.
file: MyBaseActivity.java
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.webkit.WebView;
public class MyBaseActivity extends Activity {
private static final String ANDROID_CONNECTIVITY_CHANGED = "android.net.conn.CONNECTIVITY_CHANGE";
protected static final ConnectivityBroadcastReceiver sReceiver = new ConnectivityBroadcastReceiver();
private static final IntentFilter sFilter = new IntentFilter(ANDROID_CONNECTIVITY_CHANGED);
static class ConnectivityBroadcastReceiver extends BroadcastReceiver {
private String internetOnUrl = "your online url";
private String internetOffUrl = "your offline url";
WebView offlineWebView;
#Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
// only do your online/offline loading if we have a webview set
if (offlineWebView != null) {
if (cm.getActiveNetworkInfo() != null
&& cm.getActiveNetworkInfo().isConnected()) {
offlineWebView.loadUrl(internetOnUrl);
} else {
offlineWebView.loadUrl(internetOffUrl);
}
}
}
}
#Override
public void onStart() {
super.onStart();
// register receiver
registerReceiver(sReceiver, sFilter);
}
#Override
public void onStop() {
super.onStop();
// unregister receiver
unregisterReceiver(sReceiver);
}
}
file: MyActivity.java
import android.R;
import android.os.Bundle;
import android.webkit.WebView;
public class MyActivity extends MyBaseActivity {
private WebView mWebView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// load your content root
setContentView(R.layout.main_layout);
// find your webview
mWebView = (WebView)findViewById(R.id.webView);
}
#Override
public void onStart() {
super.onStart();
// set your webview in the OfflineBroadcastReceiver
sReceiver.offlineWebView = mWebView;
}
#Override
public void onStop() {
super.onStop();
// clear your webview from the OfflineBroadcastReceiver
sReceiver.offlineWebView = null;
}
}
This is my non-activity class:
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
public class PostManager {
private Bundle bundle;
private Context context;
private Session session;
private String victimId=null;
public PostManager() {
SavedFriend savedFriend = new SavedFriend();
bundle = savedFriend.getBundle();
context = savedFriend.getContext();
session = savedFriend.getSession();
victimId = savedFriend.getfriendsId();
Log.e("postManager", victimId);
Log.e("postManager", bundle.getString("message"));
}
}
This is my application class:
import java.util.List;
import android.app.Application;
import android.content.Context;
import android.os.Bundle;
import com.facebook.Session;
import com.facebook.model.GraphUser;
public class SavedFriend extends Application {
private List<GraphUser> selectedUsers;
private String friendsId;
private Session session;
private Bundle bundle;
private Context context;
public List<GraphUser> getSelectedUsers() {
return selectedUsers;
}
public void setSelectedUsers(List<GraphUser> selectedUsers) {
this.selectedUsers = selectedUsers;
}
public String getfriendsId() {
return friendsId;
}
public void setfriendsId(String id) {
this.friendsId = id;
}
public Session getSession(){
return session;
}
public void setSession(Session session){
this.session = session;
}
public void setContext(Context context){
this.context = context;
}
public Context getContext(){
return context;
}
public void setBundle(Bundle bundle){
this.bundle = bundle;
}
public Bundle getBundle(){
return bundle;
}
}
I have used the data of the application class in a fragment class (friendsId) which is not null.
When I call the application class's data from PostManager it returning the value null.
I have tried to see the value of friendsId and message by Log.e. but it gives me nullPointer exception.
Does that means all of the values I call in my PostManager constructor from application class are null? If yes, what should I do?
I need the session, applicationcontext, message, friendsId value in my PostManager class. I can pass these values to PostManager, but this class is called by onReceive() of alarm class which class extends BroadcastReceiver, and this alarm is set from another class which extend Fragment. All the values I need are created by this class except friendsId, and I don't know how to pass these value from first class->alarm class->postmanager class.
In manifest for alarm class:
<application android:name=".SavedFriend"
.......>
....
<receiver android:name="package name.Alarm"/>
....
</application>
You're creating a new instance of your Application subclass, so none of those member variables will be set.
Instead, you can use the approach from this question and store an easy to access static variable of your Application. Use something like this instead of creating a new instance.