Android: Reference to Activity object in another class becomes NULL - java

What i am trying to do is to pass a reference to the mainactivity to another class and use it.
when i first pass the reference it is not null. but later when i use it in an event handler it becomes null.
here is the code:
public class MainActivity extends MapActivity implements SmsReceivedListener {
SmsReceiver smsreceiver = new SmsReceiver();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
smsreceiver.setSmsReceivedListener(this);
}
public void drawme() {
// do smth
}
#Override
public void onSmsReceived(String id, String lon, String lat) {
Toast.makeText(this, "SMS delivered", Toast.LENGTH_LONG).show();
}
}
The other class where I obtain the reference:
public class SmsReceiver extends BroadcastReceiver {
private SmsReceivedListener listener;
private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
#SuppressLint("NewApi")
#Override
public void onReceive(final Context context, final Intent intent) {
// Here it is NULL
if(listener!=null)
listener().onSmsReceived(carNumber, lon,lat);
}
public void setSmsReceivedListener(SmsReceivedListener mainActivity) {
//It is no null when I first set the object here
listener = (mainActivity);
}
}

It will only "become" null if you
set it to null
use it in a way which is not thread safe and you are reading in a different thread to setting
you are using the same field, but in a different object.

You are not registering the SmsReceiver, therefor i guess the following :
The SmsReceiver is registered in the Manifest. Therefore, an instance of the receiver is created by the system when the broadcast is detected, and it is not the same instance as the one you create.
Suggestion : register the receiver in the activity, not in the manifest.

Related

How can i use result in main activity

I am new user of android studio. I am using priority in manifest file and all required permissions but I do not know how can I use result in main activity, help me out.
public abstract class SmsBroadcastReceiver extends BroadcastReceiver {
protected abstract void onSmsReceived(SmsMessage smsMessage);```
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
Object[] pduObjectList = (Object[]) bundle.get("pdus");
if (pduObjectList != null) {
for (Object pduObject : pduObjectList) {
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pduObject);
onSmsReceived(smsMessage);
}
}
}
}
}
The abstract keyword is a non-access modifier, used for classes and methods:
Abstract class: is a restricted class that cannot be used to create objects (to access it, it must be inherited from another class).
Abstract method: can only be used in an abstract class, and it does not have a body. The body is provided by the subclass (inherited from).
In your activity:
public class MyActivity extends Activity {
private smsReceiver SmsBroadcastReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.map_one_position);
smsReceiver = new SmsBroadcastReceiver() {
// this code is call asyncrously from the receiver
#Override
protected void onSmsReceived() {
// Add your activty logic here
}
};
}
#Override
protected void onPause() {
super.onPause();
this.unregisterReceiver(this.smsReceiver);
}
}
One easy way is by using static variables.
On the MainActivity add the following:
public class MainActivity extends AppCompatActivity{
public static SmsMessage result;
//...
}
Then, add the following line MainActivity.result = smsMessage to the code you provided just after you get the message.
Then you can use the variable result in any part of the MainActivity (also by calling MainActivity.result you have the value of the variable in any part of your code).
Just be careful, static variables are defined as null before any assignment.
Automatic SMS Verification with the SMS Retriever API used so this is easily getting in SMS,So there was no problem and No permission is needed
https://developers.google.com/identity/sms-retriever/overview

Get in the Main Activity data from a BroadcastReceiver

I readed a lot of similar questions, but i can't figure out how to do this. I have my MainActivity with this code:
MyBroadcastReceiver broad = new MyBroadcastReceiver();
broad.onReceive(context, new Intent("api6.intent.action.TRANSACTION_COMPLETED"));
Then in MyBroadcastReceiver, a class apart from the main, i have:
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intents.ACTION_TRANSACTION_COMPLETED.equals(action)) {
if (intent.getExtras() != null) {
String txid = String.valueOf(intent.getExtras().get(Intents.INTENT_EXTRAS_TRANSACTION_ID));
}
}
}
}
I need the String txid in MainActivity just after this line:
broad.onReceive(context, new Intent("api6.intent.action.TRANSACTION_COMPLETED"));
you can achieve in lot of ways, either by writing the broadcast class inside MainActivity class or use an interface, implement it inside MainActivity
Eg
MA extends AppCompat implements AnInterface{
onCreate(){
broadcast = new YourBroadcastClass(this);
}
#override
public void interfaceMethod(String value){
}
and inside your broadcast class constructor
> AndInterface interface; MyBroad(AnInterface interface){ this.interface
> = interface; }
>
> and onReceive(){ interface.interfaceMethod("whatever you wanna send")

How to interact with UI from a different class

I would like to update my UI from a different class. I am familiar with runOnUiThread() method, but don't know how to implement it in this scenario?
public class UploadAct extends MainActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_upload);
}
//my code and functions would go here
}
Then, my UploadData class
public class UploadData extends UploadAct {
public void doSomethig(){
printThis("I want to print this message to the UI");
}
public void printThis(String messsage) {
final String mess = message;
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(),mess,Toast.LENGTH_LONG).show();
// I want this to display on the main thread
txt_upload.setText(mess);// and this also
}
});
}
}
Use BroadcastReceiver
// define a Broadcast Intent Action in String resources
<string name="broadcast_id">MY_BROADCAST_ID</string>
// register receiver in constructor/onCreate()
MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();
IntentFilter myIntentFilter = new IntentFilter();
myIntentFilter.addAction(context.getString(R.string.broadcast_id));
context.registerReceiver(myBroadcastReceiver, myIntentFilter);
// place your BroadcastReceiver in MainActivity, your UploadData class
public class MyBroadcastReceiver extends BroadcastReceiver {
public MyBroadcastReceiver(){
super();
}
#Override public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Broadcast received");
if(intent.getAction() != null && intent.getAction().equals(context.getString(R.string.broadcast_id)) ){
// do something
}
}
}
// send Broadcasts from where you want to act, your UploadAct class.
Intent intent = new Intent();
intent.setAction(context.getString(R.string.broadcast_id));
context.sendBroadcast(intent);
Log.d(TAG, "Broadcast sent.");
// you can unregister this receiver in onDestroy() method
context.unregisterReceiver(myBroadcastReceiver);
You can also use an interface to update your UI as a listener.
First, Create an interface
public interface UpdateTextListener {
void updateText(String data);
}
Then, Call its method in your UploadData class
public class UploadData extends UploadAct {
UpdateTextListener listener;
public void doSomethig(){
listener.updateText("data to be loaded");
}
}
Then, Update your UploadAct by listening to this method
public class UploadAct extends MainActivity implements UpdateTextListener {
#Override
public void updateText(String data) {
textview.setText(data);
}
}
First of all - there is no such thing like UI of some class. There are activities that can have handles to UI widgets (ex TextView). If you want to make some changes to UI from your UploadData class you have to pass somehow reference to this class. Possibly by constructor:
public class UploadData extends UploadAct{
private TextView txt_upload;
public UploadData(TextView tv)
{
txt_upload = tv;
}
public void doSomethig(){
printThis("I want to print this message to the UI")
}
public void printThis(String messsage) {
final String mess = message;
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(),mess,Toast.LENGTH_LONG).show();// I want this to display on the main thread
txt_upload.setText(mess);// and this also
}
});
}
}
I assume that you create DataUpload in your MainActivity.
Everyone use so much library to be trendy as they forget built in functions in Android :)
For sure isn't any hard thing to use AsyncTask, beside it provides the doInBackground function it has the https://developer.android.com/reference/android/os/AsyncTask.html#publishProgress(Progress...) function too, what you have asked for.
Just create a class (UploadTask) which extends AsyncTask and override 1-2 function.

BroadcastReceiver object only uses initial values, why?

Hi I'm trying to run a code which has one activity and a BroadcastReceiver which runs when new message comes and yes it's run clearly but I have a problem with BroadcastReceiver object !
It's part of MainActivity CLASS :
public class MainActivity extends FragmentActivity {
private IncomingSms checkAndDo; //=> OBJECT
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkAndDo= new IncomingSms();
checkAndDo.setProgramState(210); // program state is a variable
checkAndDo.getProgramState(this); // Toast output : " >>>210 "
....
But problem starts when a new message comes and onReceived() called ! IncommingSms class :
public class IncomingSms extends BroadcastReceiver {
private int programState=110; // Which state we are ? 110=> white / 111=> off / 210=>black ...
public void onReceive(Context context, Intent intent) {
final Bundle bundle = intent.getExtras();
this.getProgramState(context);
// This method called again but toast output is : ">>>110"
// which is initial value !?
AND ....
}
public void setProgramState(int status) {
this.programState=status;
}
public void getProgramState( Context context) {
Toast.makeText(context, ">>>"+this.programState , Toast.LENGTH_LONG).show();
}
question : I'm not sure why it happens but onReceive() uses only the initial value which is so bad . ANY Idea?
this.getProgramState(context);
// This method called again but toast output is : ">>>110"
// which is initial value !?
You met that problem because you registered your BroadcastReceiver in the manifest. So Android will create a new BroadcastReceiver and pass the sms broadcast to it.
If you would like to get the state you set in your program, you must register your BroadcastReceiver in your Activity.
IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
registerReceiver(checkAndDo, filter);
using Intent data instead bundle
Intent(ContextHolder.applicationContext!!, NotificationDeleteReceiver::class.java).setData(conversation.conversationId.toUri())

Android-Libgdx, Calling Another Activity after the Game starts on Button click

I faced a major problem when I need to call another activity when the button is clicked after the Game is started. The Game is called via initiate(game, ) method from AndroidApplication interface.
In normal Activity, I can easily call the another Activity but it seems to be difficult to call another Activity from Libgdx class that implements AndroidApplication.
Could anyone suggest a proper method to call the Activity from Libgdx class that implements AndroidApplication interface?
I tried to do this for a week but it seems that my method is totally wrong..
Thanks in advance.
Define a callback interface in you LibGdx class, and use it to notify your AndroidLauncher to start the new activity.
For example in your LibGdx game class:
// Your Game class in the core package
public class MyGame extends Game {
// Define an interface for your various callbacks to the android launcher
public interface MyGameCallback {
public void onStartActivityA();
public void onStartActivityB();
public void onStartSomeActivity(int someParameter, String someOtherParameter);
}
// Local variable to hold the callback implementation
private MyGameCallback myGameCallback;
// ** Additional **
// Setter for the callback
public void setMyGameCallback(MyGameCallback callback) {
myGameCallback = callback;
}
#Override
public void create () {
...
}
...
private void someMethod() {
...
// check the calling class has actually implemented MyGameCallback
if (myGameCallback != null) {
// initiate which ever callback method you need.
if (someCondition) {
myGameCallback.onStartActivityA();
} else if (someOtherCondition) {
myGameCallback.onStartActivityB();
} else {
myGameCallback.onStartSomeActivity(someInteger, someString);
}
} else {
Log.e("MyGame", "To use this class you must implement MyGameCallback!")
}
}
}
Then ensure your AndroidLauncher implements the required interface:
// Your AndroidLauncher
public class AndroidLauncher extends AndroidApplication implements MyGame.MyGameCallback {
#Override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
// create an instance of MyGame, and set the callback
MyGame myGame = new MyGame;
// Since AndroidLauncher implements MyGame.MyGameCallback, we can just pass 'this' to the callback setter.
myGame.setMyGameCallback(this);
initialize(myGame, config);
}
#Override
public void onStartActivityA() {
Intent intent = new Intent(this, ActivityA.class);
startActivity(intent);
}
#Override
public void onStartActivityB(){
Intent intent = new Intent(this, ActivityB.class);
startActivity(intent);
}
#Override
public void onStartSomeActivity(int someParameter, String someOtherParameter){
Intent intent = new Intent(this, ActivityA.class);
// do whatever you want with the supplied parameters.
if (someParameter == 42) {
intent.putExtra(MY_EXTRA, someOtherParameter);
}
startActivity(intent);
}
}

Categories

Resources