I am creating an Android app and wish to store a variable in the Application class. The variable signifies which Activity is currently in focus.
I aim to set this variable in onResume() and reset it in onPause(). Both methods are called as the app initialises. The software crashes on the basis of a Null Pointer Excepetion whenever I run my code, at lines where I try to modify the variable in the Application class. As far as I am aware, it appears to me as though the Application class is null even though I have tested the code and know it call the Application class' onCreate().
Am I correct in assuming it is connected to the Application Class not being completely created? Or is it connected to my instantiation of it all? I'm reasonably new to Android and haven't dealt with the Application class before - as far as I can see, I've followed the guides and tutorials correctly. I'm hoping it's a simple mistake.
Any and all advice is greatly appreciated!
MainActivity.java
public class MainActivity extends FragmentActivity implements ActionBar.TabListener {
//[... other initialisations...]
// Tells software what window is in focus.
// Reference to Application class
private MyApplicationClass app = (MyApplicationClass)getApplication();
private static final int outOfFocus = 0;
private static final int inFocus = 1;
#Override
protected void onResume() {
super.onResume();
//[... other code...]
app.setActivityFocusIndicator(inFocus); //Crashes here
}
#Override
protected void onPause() {
super.onPause();
//[... other code...]
app.setActivityFocusIndicator(outOfFocus); //Crashes here
}
}
MyApplicationClass.java
public class MyApplicationClass extends Application {
private int activityFocusIndicator;
/* activityFocusIndicator is here to indicate which activity is in focus.
* 0 = Nothing in focus (written when pausing.)
* 1 = MainActivity
* 2 = ...
* ...
*/
public void setActivityFocusIndicator(int activityFocusIndicator) {
this.activityFocusIndicator = activityFocusIndicator;
}
public int getActivityFocusIndicator() {
return activityFocusIndicator;
}
#Override
public void onCreate() {
super.onCreate();
Log.d("App", "App was created."); // This line is reached.
}
}
Manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.someApp"
android:versionCode="1"
android:versionName="1.0" >
<uses-feature android:name="android.hardware.bluetooth_le"
android:required="true"/>
<uses-sdk
android:minSdkVersion="18"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/TabTheme"
android:name="com.example.someName.MyApplicationClass" >
<activity
android:name="com.example.someName.MainActivity"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:launchMode="singleInstance" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
...
</activity>
<!-- ... [other activities declared]... -->
<service
android:name=".BluetoothService"/>
</application>
</manifest>
I can post the LogCat if asked.
I don't see the point of this line :
private MyApplicationClass app = (MyApplicationClass)getApplication();
This variable is probably initialized before the reference returned by getApplication() is initialized, and therefore remains null.
Instead of using it, replace each acess to app with a local variable.
For example:
protected void onResume() {
super.onResume();
//[... other code...]
MyApplicationClass app = (MyApplicationClass)getApplication();
app.setActivityFocusIndicator(inFocus);
}
Related
I am still new to Android development, but I’m creating an app that sendings an HTTP request when it receives a broadcast (from a barcode scan). I have tried to implement some other solutions that I read on here but haven't quite figured it out yet. It would be great if someone could help me get going in the right direction.
Essentially, the end goal is for the app to keep running in the background forever so that even if the app is not open and a barcode is scanned and sent to the app via broadcast signal, the HTTP request is still sent.
This is what I have so far:
MainActivity.java
public class MainActivity extends Activity implements CompoundButton.OnCheckedChangeListener {
public static final String BARCODE_BROADCAST = "...";
private final BarcodeReceiver barcodeReceiver = new BarcodeReceiver();
private TextView mTextView;
private String scannedBarcode;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.barcode);
}
#Override
public void onResume() {
super.onResume();
registerBarcodeScanner();
}
#Override
public void onPause() {
super.onPause();
unregisterBarcodeScanner();
// this code needs to keep the app running
Intent restartService = new Intent("RestartService");
this.startService(restartService);
sendBroadcast(restartService);
}
public void onDestroy() {
super.onDestroy();
// this code needs to keep the app running
Intent restartService = new Intent("RestartService");
this.startService(restartService);
sendBroadcast(restartService);
}
private void registerBarcodeScanner() {
registerReceiver(barcodeReceiver, new IntentFilter(BARCODE_BROADCAST));
}
private void unregisterBarcodeScanner() {
unregisterReceiver(barcodeReceiver);
}
private void displayBarcode() {
if (scannedBarcode == null) return;
String text = getString(R.string.barcode_scanned, scannedBarcode);
mTextView.setText(text);
/* SEND HTTP REQUEST */
}
private class BarcodeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(BARCODE_BROADCAST)) {
String barcode = intent.getStringExtra("Barcode");
if (barcode != null) {
scannedBarcode = barcode;
displayBarcode();
}
}
}
}
}
RestartService.java
public class RestartService extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, MainActivity.class));
}
}
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="..."
android:versionCode="1">
<uses-sdk android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
tools:replace="android:label">
<activity
android:name="...MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name="...RestartService"
android:enabled="true"
android:exported="true"
android:label="RestartServiceWhenStopped"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="RestartService" />
</intent-filter>
</receiver>
</application>
</manifest>
I'm writing a service that tracks system changes, meaning, I'm willing to track whenever a keyboard becomes visible / hidden for any application.
To achieve the following task, i built a small Activity that launches a services
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent serviceIntent = new Intent(this, MyService.class);
startService(serviceIntent);
//setContentView(R.layout.activity_main);
}
}
The manifest.xml itself
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="somepackage">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"
android:configChanges="orientation|screenSize|keyboardHidden"></service>
</application>
</manifest>
and the service itself:
public class MyService extends Service {
public MyService() {
}
private static final String TAG =
"abbeyservice";
#Override
public void onCreate() {
Log.d(TAG, "Service onCreate");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service onStartCommand");
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
Log.i(TAG, "Service onBind");
return null;
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
#Override
public void onDestroy() {
Log.i(TAG, "Service onDestroy");
}
}
Problem is I'm notified for changes within, and only for my activity. Which is seen as a white screen for unknown reasons(even though i didn't use SetContentView(..))
When you talk of "keyboard" you are talking about the soft keyboard. This doesn't result in a configuration change, as the configuration has not changed.
There are devices with hardware keyboards that slide out, so they generate a configuration change event when they are slid out or back in again. There is also a possibility to attach an external keyboard to some Android devices and the act of connecting or disconnecting a hardware keyboard also generates a configuration change event.
To detect if the keyboard is shown in your own app, see
How to check visibility of software keyboard in Android?
As far as I know, there is no way to find out if the soft keyboard is shown in another app.
My Class NetworkListener should check, if Internet Connection is available or not. Then, It should show a Snackbar with the InternetState. For this, I'm using an interface.
My whole code:
[MainActivity.java]:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle(R.string.Inbox);
Initialize_NavigationDrawer();
Initialize_Objects();
//1. Here, I initialise my NetworkListener and register my Receiver
NetworkListener mNetworkListener = new NetworkListener();
mNetworkListener.registerReceiver(this);
}
#Override
public void ToggleSnackbar(boolean ShowHide) {
if (ShowHide) snbNoInternet.show();
else snbNoInternet.dismiss();
}
[NetworkListener.java]:
public class NetworkListener extends BroadcastReceiver {
private SnackbarInterface snbInterface;
public NetworkListener() {}
#Override
public void onReceive(Context context, Intent intent) {
//4. After toggling the Network-Connection, a NullReferenceException occurs
//5. System.out.println(snbInterface) shows: null
ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = cm.getActiveNetworkInfo();
if (ni == null || !ni.isConnected()) {
snbInterface.ToggleSnackbar(true);
}
else if (ni != null && ni.isConnected()) {
snbInterface.ToggleSnackbar(false);
}
}
public void registerReceiver(SnackbarInterface receiver) {
snbInterface = receiver; //2. Is called from onCreate
//3. System.out.println(snbInterface) shows: at.guger.email.activities.MainActivity#27472a5e
}
public interface SnackbarInterface {
public void ToggleSnackbar(boolean ShowHide);
}
}
[AndroidManifest.xml]:
<activity
android:name=".activities.MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activities.WriteActivity" />
<activity
android:name=".activities.ReadActivity" />
<receiver
android:name=".NetworkListener">
<intent-filter>
<action
android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
And the permissions:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
The code is called like the numbers are ordered!
I really can't explain, why snbInterface is set to null!
I hope you can help me!
You registered the BroadcastReceiver using the receiver element in the AndroidManifest. Android system creates the BroadcastReceiver instance and calls the onReceive method with the appropriate parameters.
If you want to use a BroadcastReceiver to manipulate UI of your application (like show/hide Snackbar ), you will have to register the receiver within your activity using the registerReceiver(BroadcastReceiver receiver,IntentFilter intentFilter) in the onCreate method and unRegister in the onDestroy method of your activity.
Remove the receiver element from the AndroidManifest.xml file and create the BroadcastReceiver through code.
This question here has a clear explanation on how BroadcastReceivers can be created and registered :
Broadcast Receiver class and registerReceiver method
In the onReceive method of the BroadcastReceiver, call the toggleSnackbar method in your Activity to toggle the Snackbar.
There is an other method for achieving what you want. It is discussed here:
Inform Activity from a BroadcastReceiver ONLY if it is in the foreground
Read more on BroadcastReceivers here
You can write the Receiver as a separate class. Instantiate the Receiver and make a call to registerReceiver with the first parameter as the Receiver and the second parameter as the IntentFilter.
I've imported project into eclipse and when I try to run it, then this exception is thrown:
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.polygraf/com.polygraf.activity.Dashboard}: java.lang.ClassNotFoundException: Didn't find class "com.polygraf.activity.Dashboard" on path: /data/app/com.polygraf-1.apk
I've tried to clean the project, then check if all class names and manifest are ok, but still can't find why this happens. Can you help me a little please?
Dashbard class:
public class Dashboard extends FragmentActivity {
private static final String WELCOME_TYPE = "WELCOME_TYPE";
private static final String HELP_TYPE = "HELP_TYPE";
public static final String ADRESS_CONTENT = "ADRESS_CONTENT";
public static final String DOC_NAME = "DOC_NAME";
private Transcript mContent;
private ISettableContent mListOfDocument;
private String mAddress;
private String mDocName;
public Dashboard() {
}
/** Called with the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dashboard);
boolean content = false;
// View gc = (NoSaveStateFrameLayout)
// findViewById(R.id.content_fragment);
//
Fragment frContent = getSupportFragmentManager().findFragmentById(R.id.content_fragment);
mContent = ((IGetContent) frContent).getContent();
TranscriptSetting cc = Polygraf.getInstance().getContentSetting();
Fragment frDocumentsList = getSupportFragmentManager().findFragmentById(R.id.documents);
mListOfDocument = (ISettableContent) frDocumentsList;
cc.registerContent(mListOfDocument);
if (getIntent().hasExtra(ADRESS_CONTENT)) {
mAddress = getIntent().getStringExtra(ADRESS_CONTENT);
mDocName = getIntent().getStringExtra(DOC_NAME);
mContent.setAddress(mAddress, mDocName);
content = true;
} else if (getIntent().hasExtra(WELCOME_TYPE)) {
content = true;
prepareVisibilityBtnTranscript();
} else if (getIntent().hasExtra(HELP_TYPE)) {
content = true;
mContent.showHelp();
}
if (content) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.hide(frDocumentsList);
ft.commit();
// because on diferent layouts for small and large device
// some views missing, so the test is inportant
View contentLayout = findViewById(R.id.contentLayout);
if (contentLayout != null) {
contentLayout.setVisibility(View.VISIBLE);
}
prepareVisibilityBtnWelcome();
// cp.setContent(mContent);
}
cc.registerContent(mContent);
// cp.setListener(cc);
}
.
.
.
}
And manifest file:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="17" />
<application
android:name=".Polygraf"
android:allowBackup="true"
android:hardwareAccelerated="true"
android:icon="#drawable/icon"
android:label="#string/skeleton_app"
android:theme="#android:style/Theme.Black.NoTitleBar" >
<activity
android:name="com.polygraf.activity.Dashboard"
android:configChanges="orientation|keyboard" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<!-- This places this activity into the main app list. -->
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.polygraf.activity.SettingActivity"
android:label="#string/skeleton_app" />
<activity
android:name="com.polygraf.activity.ContentActivity"
android:label="#string/skeleton_app" >
</activity>
<activity
android:name="com.polygraf.activity.PlayVideo"
android:configChanges="orientation|keyboard"
android:label="#string/skeleton_app" />
</application>
I suppose you're using Eclipse. Your activity is there alright, but Eclipse didn't include the support package in the APK ... If you look above your error in stacktrace you will notice the root of your problem: "Unable to find FragmentActivity". Or you can unpack the apk, undex it and you will see the compatibility package classes were not included.
To fix this, right-click your project, properties, build path and go to export tab. There make sure "Android private libraries" are checked. A clean and rebuild should put you on track ...
After i spend a while on this problem, the solution that i found is a conflict between importing Properties > Android - appcompat_v7 and appcompat_v4 that was added in the libs folder. After i remove the appcompat_v4 the error no longer appear.
I hope that answer can help in the future someone.
You should import new appcompat_v7 from sdk and use it as a built path,it works for me.
I know there is another question on here relating to this, but I don't think it applies to me, as I'm pretty sure I use GSM (isGSM() returns true). In any case, getCdmaDbm returns -1 for me anyway. I am using Android 4.1.1 and an HTC One X. Here is my code (most of which isn't mine):
MainActivity:
package com.example.receptionlookup;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.telephony.PhoneStateListener;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.view.Menu;
import android.widget.Toast;
public class MainActivity extends Activity {
TelephonyManager Tel;
MyPhoneStateListener MyListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/* Update the listener, and start it */
MyListener = new MyPhoneStateListener();
Tel = ( TelephonyManager )getSystemService(Context.TELEPHONY_SERVICE);
Tel.listen(MyListener ,PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
/* Called when the application is minimized */
#Override
protected void onPause()
{
super.onPause();
Tel.listen(MyListener, PhoneStateListener.LISTEN_NONE);
}
/* Called when the application resumes */
#Override
protected void onResume()
{
super.onResume();
Tel.listen(MyListener,PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
}
/* —————————– */
/* Start the PhoneState listener */
/* —————————– */
private class MyPhoneStateListener extends PhoneStateListener
{
/* Get the Signal strength from the provider, each tiome there is an update */
#Override
public void onSignalStrengthsChanged(SignalStrength signalStrength)
{
super.onSignalStrengthsChanged(signalStrength);
Toast.makeText(getApplicationContext(), "Go to Firstdroid!!! GSM Cinr = "
+ String.valueOf(signalStrength.getGsmSignalStrength()), Toast.LENGTH_SHORT).show();
}
};/* End of private Class */
}
AndroidManifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.receptionlookup"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.receptionlookup.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
</manifest>
Does anyone know what the problem is? If I go to Settings->About->Network, I can see the signal strength there. Isn't there some way to just read this value? I've tried several third party apps, and none of them are able to read my signal strength either. I've also tried the proprietary getGSMSignalBar() method, but I get a NoSuchMethodException.
As you can read in the 3GPP 127 007 8.5 the implementation of the at+csq is optional (the command which suppose to give the signal strength). Apparently HTC hide this value from 3rd party applications and they probably have another way to achieve that value for display in their own proprietary Settings application.
The fact that other applications also cannot get that information justifies my case.
This issue is tightly related to yours - thay said that HTC is one of the OEMs that does not worth the modem related developing time.
Try this:
Class signalStrengthClass = signalStrength.getClass();
try {
Method method = signalStrengthClass.getMethod(
"getGsmSignalBar", null);
method.setAccessible(true);
Integer bars = (Integer) method.invoke(signalStrength,
(Object[]) null);
}
} catch (Exception e) {
e.printStackTrace();
}