Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access service functions from fragment, which is bound to parent activity in Android?

I have an Android activity with a viewpager fragment. In the onCreate method of the activity, I bind a service to it which constantly runs in the background.

In the fragment, on a certain condition I need to call a function in the service which deals with the condition. What is the correct way to access the service, and call it's functions?

MainActivity.java

public class MainActivity extends AppCompatActivity {

private String TAG = "MainActivity";

DbHelper dbHelper;
SessionManager sessionManager;
SessionCache sessionCache;
Map<String, ?> userDetails;
protected SocketListener socketService;

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


    sessionManager = new SessionManager(getApplicationContext());

    // Connect to background socketlistener service
    Intent serviceIntent = new Intent(MainActivity.this, SocketListener.class);
    startService(serviceIntent);
    .
    .
    .

    TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
    tabLayout.addTab(tabLayout.newTab().setText("").setIcon(getResources().getDrawable(R.drawable.profileicon)));
    tabLayout.addTab(tabLayout.newTab().setText("").setIcon(getResources().getDrawable(R.drawable.homeicon)));
    tabLayout.addTab(tabLayout.newTab().setText("").setIcon(getResources().getDrawable(R.drawable.chaticon)));

    tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
    final NonSwipeableViewPager viewPager = (NonSwipeableViewPager) findViewById(R.id.view_pager);

    final CustomPagerAdapter pagerAdapter = new CustomPagerAdapter
            (getSupportFragmentManager(), tabLayout.getTabCount());

    viewPager.setAdapter(pagerAdapter);
    viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));

    viewPager.setCurrentItem(1);
    tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
        @Override
        public void onTabSelected(TabLayout.Tab tab) {
            viewPager.setCurrentItem(tab.getPosition());
        }

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

        }

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

        }
    });
}

    private ServiceConnection serviceConnection = new ServiceConnection() {


@Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        socketService = ((SocketListener.LocalBinder) iBinder).getService();
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        socketService = null;
    }
};

}

This is my service. I connect to a server, and constantly listen for updates.

SocketListener.java

    package com.example.gopa2000.mobapps;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

import java.net.URISyntaxException;

import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;

public class SocketListener extends Service {

private static String TAG = "SocketListener";
private Socket socket;

public SocketListener() { }

@Override
public IBinder onBind(Intent intent) {
    // TODO: Return the communication channel to the service.
    return localBinder;
}

private final IBinder localBinder = new LocalBinder();
public class LocalBinder extends Binder {
    public SocketListener getService(){
        Log.i(TAG, "getService: Sitting in local binder.");
        return SocketListener.this;
    }

    public void sendMessage(String message){
        socket.emit("match", message);
    }
}

@Override
public void onCreate() {
    super.onCreate();
}

public void isBoundable(){
    Log.i(TAG, "Bind like a baller.");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);

    Runnable connect = new ConnectSocket();
    new Thread(connect).start();
    return START_STICKY;
}

class ConnectSocket implements Runnable {
    @Override
    public void run() {
        try {
            socket = IO.socket(RESTClient.getURL());

            socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
                @Override
                public void call(Object... args) {
                    Log.i(TAG, "call: Connected to backend!");
                }
            });

            socket.connect();
        } catch (URISyntaxException e){
            Log.e(TAG, "run: ", e);
        }
    }
}

public Socket getSocket(){
    return this.socket;
}
}

And this is the fragment where I would need to call the sendMessage(string).

public class MainViewFragment extends Fragment {

private final String TAG = "MVFragment";

private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;
private RecyclerView.Adapter adapter;
private SessionManager sessionManager;
private ArrayList<CustomCard> cards;
private CardAdapter cardAdapter;
private Button btn;
private SwipeFlingAdapterView flingContainer;
private Map<String, ?> userDetails;
// hax
private static String userEmail;



@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View view = inflater.from(getContext()).inflate(R.layout.fragment_main_view, container, false);

            .
            .

    flingContainer.setAdapter(adapter);

    flingContainer.setFlingListener(new SwipeFlingAdapterView.onFlingListener(){
            .
            .

        @Override
        public void onRightCardExit(Object o) {
            .
            .

            if(match){

            // need to call sendMessage from the service here. <------------------------

                sessionCache.addToMatchTable(Liker, Likee);
            }
        }

        @Override
        public void onAdapterAboutToEmpty(int i) {

        }

        @Override
        public void onScroll(float v) {

        }
    });


    flingContainer.setOnItemClickListener(new SwipeFlingAdapterView.OnItemClickListener(){
        @Override
        public void onItemClicked(int itemPosition, Object dataObject){
            Toast.makeText(getActivity(), "Clicked!", Toast.LENGTH_SHORT).show();
            Intent intent = new Intent(getActivity().getApplicationContext(), FullScreenCardLayout.class);
            startActivity(intent);
        }
    });

    return view;
}
like image 527
doberoi96 Avatar asked Mar 11 '23 14:03

doberoi96


1 Answers

First the method sendMessage(message) should be inside the service not the LocalBinder class

public class SocketListener extends Service {

    public void sendMessage(String message){
        socket.emit("match", message);
    }
}

Second to access activity method from fragment you should create interface inside your fragment

interface MessageSender {
    void sendMessage(String message);
}

then implement it in your activity

public class MainActivity extends AppCompatActivity implements MessageSender {

    @Override
    public void sendMessage(String message) {
        // call the service here
        socketService.sendMessage(message);
    }
}

inside your fragment, implement onAttach() and initialize the interface instance

public class MainViewFragment extends Fragment {
    private MessageSender mMessageSenderCallback;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
         try {
            mMessageSenderCallback = (MessageSender) context;
        } catch (ClassCastException e) {
            // Error, class doesn't implement the interface
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        // Remove activity reference
        mMessageSenderCallback = null;
    }
}

To send a message, call mMessageSenderCallback.sendMessage(message) with your message inside the fragment.

like image 145
SaNtoRiaN Avatar answered Apr 07 '23 00:04

SaNtoRiaN