Search code examples
android-studioandroid-fragmentsmethodsbackground-processnon-static

How to call a non-static method from the main activity to a fragment?


I'm having a problem with listeners inside a fragment calling a non-static method from the main activity. Android studio gives as a solution to make the method static, but this interupts the the working of the program. Specifically, I have a different fragments containing serveral buttons. When a button is pressed, it activates a background proces to send a message to a Arduino Webserver. This means that the method can not be static in order to work.

Main Activity.

package com.example.ethernettest1;

import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.TextView;
import android.widget.ToggleButton;

import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;

import com.google.android.material.tabs.TabItem;
import com.google.android.material.tabs.TabLayout;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import static android.view.View.*;

public class MainActivity extends AppCompatActivity {

    private TabLayout tabLayout;
    private ViewPager viewPager;
    private TabItem tab1, tab2, tab3;
    public PagerAdapter pageradapter;
    int dayNumber = 0;
    int[] hourOpen = {0, 0, 0, 0, 0, 0, 0, 0};
    int[] minutesOpen = {0, 0, 0, 0, 0, 0, 0, 0};
    int[] hourClose = {0, 0, 0, 0, 0, 0, 0, 0};
    int[] minutesClose = {0, 0, 0, 0, 0, 0, 0, 0};

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

        tabLayout = findViewById(R.id.tablayout);
        tab1 =  findViewById(R.id.Tab1);
        tab2 =  findViewById(R.id.Tab2);
        tab3 =  findViewById(R.id.Tab3);
        viewPager = findViewById(R.id.viewpager);

        pageradapter = new PageAdapter(getSupportFragmentManager(), tabLayout.getTabCount());
        viewPager.setAdapter(pageradapter);

        //noinspection deprecation
        tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                viewPager.setCurrentItem(tab.getPosition());
                if(tab.getPosition() == 0)
                {
                    pageradapter.notifyDataSetChanged();
                }
                else if (tab.getPosition() == 1)
                {
                    pageradapter.notifyDataSetChanged();
                }
                else if (tab.getPosition() == 2)
                {
                    pageradapter.notifyDataSetChanged();
                }
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });

        viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        /*
        Handle action bar item clicks here. The action bar will
        automatically handle clicks on the Home/Up button, so long
        as you specify a parent activity in AndroidManifest.xml.
        */
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    /*****************************************************/
    /*  This is a background process for connecting      */
    /*   to the arduino server and sending               */
    /*    the GET request withe the added data           */
    /*****************************************************/

    public class Background_get extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... params) {
            try {
                URL url = new URL("http://rolluiksturing.ddns.net/?" + params[0]);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();

                BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                StringBuilder result = new StringBuilder();
                String inputLine;
                while ((inputLine = in.readLine()) != null)
                    result.append(inputLine).append("\n");

                in.close();
                connection.disconnect();
                return result.toString();

            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

}

And one off the fragments

package com.example.ethernettest1;


import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CompoundButton;
import android.widget.ToggleButton;

import androidx.fragment.app.Fragment;


/**
 * A simple {@link Fragment} subclass.
 */
public class tab1 extends Fragment {

    public tab1() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        View view = inflater.inflate(R.layout.fragment_tab1, container, false);

        Button open = view.findViewById(R.id.open);
        Button sluit = view.findViewById(R.id.sluit);
        Button openAlles = view.findViewById(R.id.SelectAll);
        Button sluitAlles = view.findViewById(R.id.DeselectAll);
        Button naarBoven = view.findViewById(R.id.naarBoven);
        Button naarOnder = view.findViewById(R.id.naarOnder);
        ToggleButton Roluik1Button = view.findViewById(R.id.roluik1Button);
        ToggleButton Roluik2Button = view.findViewById(R.id.roluik2Button);
        ToggleButton Roluik3Button =  view.findViewById(R.id.roluik3Button);

        open.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN)
                    new MainActivity.Background_get().execute("Open");
                else if (event.getAction() == MotionEvent.ACTION_UP) {
                    // Do nothing
                }
                return true;
            }
        });

        sluit.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    new MainActivity.Background_get().execute("Sluit");
                } else if (event.getAction() == MotionEvent.ACTION_UP) {
                    // Do nothing
                }
                return true;
            }
        });

        openAlles.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    new MainActivity.Background_get().execute("OpenAlles");
                } else if (event.getAction() == MotionEvent.ACTION_UP) {
                    // Do nothing
                }
                return true;
            }
        });

        sluitAlles.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    new MainActivity.Background_get().execute("SluitAlles");
                } else if (event.getAction() == MotionEvent.ACTION_UP) {
                    // Do nothing
                }
                return true;
            }
        });

        naarBoven.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    new MainActivity.Background_get().execute("GaNaarBoven");
                } else if (event.getAction() == MotionEvent.ACTION_UP) {
                    new MainActivity.Background_get().execute("stop");
                }
                return true;
            }
        });

        naarOnder.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    new MainActivity.Background_get().execute("GaNaarBeneden");
                } else if (event.getAction() == MotionEvent.ACTION_UP) {
                    new MainActivity.Background_get().execute("stop");
                }
                return true;
            }
        });

        Roluik1Button.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if(isChecked) {
                    new MainActivity.Background_get().execute("Zet1InArray");
                } else {
                    new MainActivity.Background_get().execute("Zet1UitArray");
                }
            }
        });

        Roluik2Button.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if(isChecked) {
                    new MainActivity.Background_get().execute("Zet2InArray");
                } else {
                    new MainActivity.Background_get().execute("Zet2UitArray");
                }
            }
        });

        Roluik3Button.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if(isChecked) {
                    new MainActivity.Background_get().execute("Zet3InArray");
                } else {
                    new MainActivity.Background_get().execute("Zet3UitArray");
                }
            }
        });

        return inflater.inflate(R.layout.fragment_tab1, container, false);
    }
}

Several articles have given answers for the oppesite of what I need, so I hope someone can give me a clear answer.


Solution

  • One of the things that you can do is add a method to your MainActivity like the following

    //note the following method
    public void runBackgroundGet(String... params){
        new Background_get().execute(params);
    }
    

    And have your fragments call it as follows:

            Roluik3Button.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    if(isChecked) {
                        (MainAticity(getActivity()).runBackgroundGet("Zet3InArray");
                    } else {
                        MainAticity(getActivity()).runBackgroundGet("Zet3UitArray");
                    }
                }
            });
    

    But I have to warn you, working with AsyncTask can lead to lots of issues and leaks, also they will be marked deprecated soon enough. I'm advising trying working with view models and Kotlin coroutines for example to replace AsyncTask.

    :)