Refresh Main Activity when my Bind Service changes its state

131 Views Asked by At

I need to refresh Main Activity when my Bind Service changes its state. Code for my MainActivity :

    public class MainActivity extends AppCompatActivity
        implements UDPService.OnHeadlineSelectedListener{
      protected void onStart() {
         super.onStart();
         Intent intent = new Intent(this, UDPService.class);
         bindService(intent, myConnection, Context.BIND_AUTO_CREATE);
         //startService(intent);
     }
      private ServiceConnection myConnection = new ServiceConnection() {
            public void onServiceConnected(ComponentName className, IBinder service) {
                // This is called when the connection with the service has been
                // established, giving us the object we can use to
                // interact with the service.  We are communicating with the
                // service using a Messenger, so here we get a client-side
                // representation of that from the raw IBinder object.
                UDPService.MyLocalBinder binder = (UDPService.MyLocalBinder) service;
                myService = binder.getService();
            }
            public void onServiceDisconnected(ComponentName className) {
                // This is called when the connection with the service has been
                // unexpectedly disconnected -- that is, its process crashed.
                myService = null;
            }
        };

       protected void onCreate(Bundle savedInstanceState) {
         ... //In this part i have initialized BaseAdaptater
       }

       public static Context getContextOfApplication() {
        return contextOfApplication;
    }



       @Override
       public void onArticleSelected(int position) {
        baseAdapter.notifyDataSetChanged();
       }
}

While the service is:

public class UDPService extends Service  {
    private final IBinder myBinder = new MyLocalBinder();
    LampManager lm = LampManager.getInstance();
    int port = 4096;
    public String URL;
    private DatagramSocket udpSocket;
    private DatagramPacket packet;
    String text;
    static boolean bol =false;
    OnHeadlineSelectedListener mCallback;
    int i=2;
    private void listenAndWaitAndThrowIntent() throws Exception {
        byte[] message = new byte[5120];
        if(udpSocket == null || udpSocket.isClosed()){
            udpSocket = new DatagramSocket(port);
        }
        packet = new DatagramPacket(message, message.length);
        //Thread.sleep(5000);
        Log.i("UDP client: ", "about to wait to receive");
        udpSocket.receive(packet);
        String text = new String(message, 0, packet.getLength());
        this.text = text;
        Log.d("Received data", text);
        packet.getPort();
        URL = packet.getAddress().toString().replace("/", "");
        Log.d("Address", String.valueOf(packet.getAddress()));
        Log.d("Port", String.valueOf(packet.getPort()));
        udpSocket.close();
    }

    Thread UDPBroadcastThread;

    void startListenForUDPBroadcast(){
        UDPBroadcastThread = new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare();
                while (true) {
                    try {
                        listenAndWaitAndThrowIntent();
                         bol = lm.addLamp(URL,text);
                        mCallback = (OnHeadlineSelectedListener) MainActivity.getContextOfApplication();
                        mCallback.onArticleSelected(i);
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        Log.i("UDP", e.getMessage());
                    }
                }
            }
        });
        UDPBroadcastThread.start();
    }

    private void stopListen() {
        udpSocket.close();
    }




    @Override
    public void onDestroy() {
        stopListen();
    }

    /*public int onStartCommand(Intent intent, int flags, int startId){
        startListenForUDPBroadcast();
        Log.i("UDP", "Service Started");
        return START_STICKY;
    }*/
    @Override
    public void onCreate(){
        super.onCreate();
        startListenForUDPBroadcast();
    }
    @Override
    public IBinder onBind(Intent intent) {
        // We don't provide binding, so return null
        Log.i("UDP", "Service Started");
        return myBinder;
    }

    public interface OnHeadlineSelectedListener {
        void onArticleSelected(int position);
    }

    public class MyLocalBinder extends Binder {
        UDPService getService() {
            return UDPService.this;
        }
        }
}

The main Activity have a Listview, a method addLamp(URL,text) adds the Lamp to the list. I need to refresh Main Activity, when bol returns true, I call notifyDataSetChanged() to refresh the listView. The code works because when call onCreate() in the main activity, that contain notifyDataSetChanged(), to refresh list with the lamp that I created with addLamp. My problem is that the Service doesn't come out of looper. Code for addLamp is:

public class LampManager extends AppCompatActivity {


    private static final LampManager ourInstance = new LampManager();
    private List<Lamp> lista = new ArrayList();
    Context applicationContext = MainActivity.getContextOfApplication();
 public boolean addLamp(String URL, String name) throws InterruptedException{
        String ip = URL.replace("/", "");
        Log.i("UDP", "Messagio ricevuto!");
        boolean b = true;
        System.out.println(getLamps().size());
        Lamp l =null;
        try {
        for(int i=0; i<getLamps().size();i++) {
            System.out.println(getLamp(i).getURL());
            System.out.println(getLamp(i).getURL());
            char c = name.charAt(name.length()-1);
            Thread.sleep(5000);
            if (lista.get(i).getName().equals(name)) {
                b = false;
            }else if(c>='0' && c<='9' && name.contains("LAMP_"))
                b=true;
            else
                b=false;
        }
        if(b){
            System.out.println("Thread.sleep(5000)");
            l = new Lamp(URL, name);
            new TcpClient(l, applicationContext).execute();
            lista.add(l);
            return b;
        }
        }catch (Exception e){
            Log.d("ERR",e.getMessage());
        }
        return b;
    }
}

While code for lamp is:

public  class Lamp extends AppCompatActivity {
    private String name;
    private int rgb;
    private Bitmap image;;
    private int intensity;
    private Boolean state;
    public String   URL;

    //save the context recievied via constructor in a local variable
    Context applicationContext = MainActivity.getContextOfApplication();


    public Lamp( String URL, String name){
        this.name=name;
        this.URL=URL;
        SharedPreferences sh = PreferenceManager.getDefaultSharedPreferences(applicationContext);
        SharedPreferences.Editor editor = sh.edit();
        setName(name);
        editor.putString(getName()+":URL", URL);
        editor.apply();
    }
1

There are 1 best solutions below

7
On

Use Interfaces

first, Define a Interface on your Service class:

    // Container Activity must implement this interface
public interface OnHeadlineSelectedListener {
    public void onArticleSelected(int position);
}

Now the fragment can deliver messages to the activity by calling the onArticleSelected() method (or other methods in the interface) using the mCallback instance of the OnHeadlineSelectedListener interface.

Then, on the Activity:

public static class MainActivity extends Activity
    implements HeadlinesFragment.OnHeadlineSelectedListener{
...

public void onArticleSelected(int position) {
    // The user selected the headline of an article from the HeadlinesFragment
    // Do something here to display that article
}

}

Sucess :D