Tobias de Bruijn
Tobias de Bruijn

Reputation: 25

Call a non static method from a different class in Java

I'm working on an Android app, but am stuck at a problem I can't seem to find an answer to. I want to call the method "updateTime" in class "MainActivity" from method "run" (thus calling it from a Thread) in class "TaskHandler".

I've Googled for the answer for about an hour now, visited multiple websites and found multiple solutions, of which non worked for me. I have also asked about it in the LinusTechTips and Corsair discord servers.

MainActivity class:

    package thedutchmc.net.alarm;

import android.os.Bundle;
import android.widget.EditText;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.time.LocalTime;


public class MainActivity extends AppCompatActivity {

    public static String alarmTime;
    public static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(3);
    public static boolean alarmBool = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final TextView mTextView = (TextView) findViewById(R.id.currentTime);

        mTextView.setText("Current Time: ");
        Main.scheduler.scheduleAtFixedRate(new TaskHandler(), 1, 1, TimeUnit.SECONDS);
    }

    public void onSubmit(View v){
        System.out.println("Submit!");
        EditText alarmTimeEditText = (EditText) findViewById(R.id.setAlarmTime);
        alarmTime = alarmTimeEditText.getText().toString();
        System.out.println("MainActivity (alarmTime): " + alarmTime);
        alarmBool = true;

    }

    public void updateTime() {
        TextView seeTime = (TextView) findViewById(R.id.currentTime);
        seeTime.setText(LocalTime.now().toString());
    }
}

TaskHandler class:

package thedutchmc.net.alarm;

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class TaskHandler implements Runnable {

    final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("HH:mm");
    public static boolean isRinging = false;
    private String alarmTime;
    public static final MainActivity activity = new MainActivity();

    @Override
    public void run() {
        activity.updateTime();
        if (checkAlarmBool()) {
            System.out.println("Bool true! Alarm!");
            Main.alarm.set(false);
            Main.alarm.ringAlarm();
        }
    }

    boolean checkAlarmBool() {
        if (MainActivity.alarmBool && !isRinging) {
            String lTime = LocalTime.now().format(dtf);

            System.out.println("TaskHandler alarmTime: " + MainActivity.alarmTime);
            System.out.println("TaskHandler LocalTime: " + lTime);

            if(lTime.equalsIgnoreCase(MainActivity.alarmTime)) {
                isRinging = true;
                return true;
            } else {

                return false;
            }
        } else {
            return false;
        }
    }

I hope someone can help me :)

Upvotes: 0

Views: 99

Answers (3)

Greg Moens
Greg Moens

Reputation: 1825

Make TaskHandler an inner class inside MainActivity. Then you'll be able to call updateTime(). And drop that static final MainActivity variable, you won't need it if TaskHandler is inside MainActivity. Never create activities with the new operator.

One other thing you'll probably run into, you can't update UI from a background thread, so you'll probably want to use runOnUiThread(Runnable) either when calling updateTime() or inside updateTime().

Upvotes: 1

Dimness
Dimness

Reputation: 162

Use Broadcasts. In Your TaskHandler class, from inside "run" method, send broadcast:

Intent i = new Intent("run_method");
sendBroadcast(i);

In Your MainActivity class, in onResume(), register Broadcast Receiver:

private BroadcastReceiver receiver;
if (receiver == null){
   receiver = new BroadcastReceiver() {
       @Override
       public void onReceive(Context context, Intent intent) {
            updateTime();
       }
   };
}
registerReceiver(receiver, new IntentFilter("run_method"));

Upvotes: 0

TheWanderer
TheWanderer

Reputation: 17824

You can't directly access an Activity's methods outside of the Activity itself. The recommended way to communicate among components is to use Broadcasts.

You do have direct access to your Activity, because you instantiate the TaskHandler from it. You could just pass your Activity in the constructor of TaskHandler (and save it as a global variable in the TaskHandler), but this might lead to crashes if that Activity is finished before TaskHandler executes.

Add a Context to TaskHandler's constructor:

private Context context;

public TaskHandler(Context context) {
    this.context = context;
}

and instantiate the TaskHandler with

new TaskHandler(getApplicationContext());

and you'll be able to send a Broadcast that you can then receive in a BroadcastReceiver registered inside your Activity (read the link for details on BroadcastReceivers and such).

Replace Context with MainActivity, and getApplicationContext() with this, and you can just directly call the method you want, but that can cause crashes, and this will only work if TaskHandler is only used inside MainActivity.

If it is only used inside MainActivity, just make it an inner class, and then you can call the method directly, without any reference.

No matter what you do, you can't make a new instance of Activity classes yourself and expect them to work.

Upvotes: 0

Related Questions