4

Let's suppose 2 activities Activity1 and Activity2. I need to call method methodAct1() (inside Activity1) from methodAct2 (inside Activity2). I think it should work using callback listener - I don't want to use EventBus libs!

I get java.lang.NullPointerException using this code:

interface:

public interface MyListener {
    public void listen();
}

Activity where event is created:

public class Activity2 extends Activity {

    private MyListener  myListener;

    public void setUpListener(MyListener myListener) {
        this.myListener = myListener;
    }

    private void doWork(){
        //do stuff 
        myListener.listen();
    }
}

Activity where I'd like to get that event when work is done:

public class Activity1 extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Activity2 activity2 = new Activity2();
        activity2.setUpListener(new setUpListener() {
            @Override
            public void listen() {
                // get the event here

            }
        });
    }
}
Kristof U.
  • 1,263
  • 10
  • 17
Vasile Doe
  • 1,674
  • 1
  • 24
  • 40

4 Answers4

7

This is absolutely not possible. You never instanciate a new Activity yourself. You will not have two Activities running at the same time.

If you want another Activity to do something, based on what your previous Activity wants, then you need to add that to your Intent.

Intent intent = new Intent(this, Activity2.class);
intent.putExtra("data field", "data value");
startActivity(intent);

If you want specific functionality through a callback then you might be thinking of Fragments. In this way, you can have the same Activity running and it can tell individual Fragments what they need to do.

Knossos
  • 15,802
  • 10
  • 54
  • 91
  • yeah, maybe this is the easiest way to solve my case, but I had changed a bit the logic to fit this solution – Vasile Doe Nov 23 '15 at 13:14
  • 1
    down vote as yes, yes yes -this is called instrumentation :) - you can drive each activity instantiation and whole app instantiation – ceph3us May 11 '17 at 05:18
  • You do not create it *yourself* though, critically, with the `new` keyword. This is the key issue with the question given. For Activity instrumentation, you would typically use something like `ActivityInstrumentationTestCase2`. – Knossos May 15 '17 at 10:39
5

The NPE is happening because of your statement:

Activity2 activity2 = new Activity2(); <--

you should never do this, and instead you should do in the Activity 1:

Intent intent = new Intent(this, Activity2.class);
intent.putExtra("dataKey", "dataValue");
startActivityForResult(pickContactIntent, CALLBACK_REQUEST);

the startActivityForResult() offers a callback from Activity 2 to Activity 1, and you have to override the result in activity 1:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // Check which request we're responding to
    if (requestCode == CALLBACK_REQUEST) {
        // Make sure the request was successful
        if (resultCode == RESULT_OK) {
            // The Intent's data Uri identifies which contact was selected.

            // Do something with the contact here (bigger example below)
        }
    }
}
ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
4

You could do that in your approach like this....

public class Activity2 extends AppCompatActivity {

    private static MyListener  myListener;

    public static void setUpListener(MyListener Listener) {
        myListener = Listener;
    }

    public void doWork(View view) {
        myListener.listen();
    }
}


public class Activity1 extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Activity2.setUpListener(new MyListener() {
            @Override
            public void listen() {
                Log.d("Hello", "Hello World");
            }
        });
    }

    public void goToAnotherActivity(View view) {
        startActivity(new Intent(Activity1.this, Activity2.class));
    }
}

Though it's not best approach and in order to work with this mechanism your activity1 needs to be created.

Tushar Pramanik
  • 171
  • 2
  • 4
  • This doesn't work in cases where `Activity2` is opened multiple times because of the static `myListener`, for example in a navigation stack. The Android paradigm simply does not use such a concept. If one tries to swim against the waters, it will cause all kinds of issues down the way one has to account for and eventually code becomes fragile and hard to maintain. – Manuel Nov 29 '19 at 03:02
-1

You can do it like this > - STEP 01: Implement a shared interface


public interface SharedCallback {
    public String getSharedText(/*you can define arguments here*/);
}
  • STEP 02: Implement a shared class

final class SharedMethode {
    private static Context mContext;

    private static SharedMethode sharedMethode = new SharedMethode();

    private SharedMethode() {
        super();
    }

    public static SharedMethode getInstance() {
        return sharedMethode;
    }

    public void setContext(Context context) {
        if (mContext != null)
            return;

        mContext = context;
    }

    public boolean contextAssigned() {
        return mContext != null;
    }

    public Context getContext() {
        return mContext;
    }

    public void freeContext() {
        mContext = null;
    }
}

- STEP 03 :: Play with code in First Activity


public class FirstActivity extends Activity implements SharedCallback {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.your_layout);

        // call playMe from here or there
        playMe();
    }

    private void playMe() {
        SharedMethode.getInstance().setContext(this);
        Intent intent = new Intent(this, SecondActivity.class);
        startActivity(intent);
    }

    @Override
    public String getSharedText(/*passed arguments*/) {
        return "your result";
    }

}
  • STEP 04 :: Finalize the game in SecondActivity

public class SecondActivity extends Activity {

    private SharedCallback sharedCallback;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.your_layout);

        if (SharedMethode.getInstance().contextAssigned()) {
            if (SharedMethode.getInstance().getContext() instanceof SharedCallback)
                sharedCallback = (SharedCallback) SharedMethode.getInstance().getContext();

            // to prevent memory leak. no further needs
            SharedMethode.freeContext();
        }

        // You can now call your implemented methodes from anywhere at any time
        if (sharedCallback != null)
            Log.d("TAG", "Callback result = " + sharedCallback.getSharedText());

    }

        @Override
        protected void onDestroy() {
        sharedCallback = null;
        super.onDestroy();
    }

}

you can also implement a backword callback (from First to Second) to get some results from SecondAvtivity or call some methods

tdjprog
  • 706
  • 6
  • 11
  • in this way you can share global variables from mainActivity or publish update from mainActivity to any forground activity. – tdjprog Jan 13 '19 at 00:35
  • 2
    This is a terrible solution. This only works, since it leaks `Activity`. It would also not work, when framework decides to destroy your process and later restore it. In that case `SecondActivity` would get restored, but `FirstActivity` would never get called (`SharedMethode.mContext` would be null). – Peter Feb 20 '20 at 14:36