Service and Activity communication summary

A little thought

Feelings can be regarded as a summary of work. The four major components of Service are basically used in projects. Service and Activity communication is a problem we often need to deal with. Here I will talk about several methods that I am more familiar with:
①BroadcastReceiver Form, this is the method I first used, but the efficiency is particularly low, especially when the amount of data is large, and then the registration and broadcasting,
unbinding and other tasks need to be done, but it is very cumbersome; ②Hander method, I use in actual work There are few;
③EventBus form, I have been using this method until there is no problem. The amount of code in this method is really small and simple. The only disadvantage is that it is difficult to maintain when there are too many message types, but I found out later in my work If the message frequency is too high, there will be a memory leak. I haven't studied the EventBus source code in detail, and haven't found the root cause;
④The interface form, which is also the form I currently use, is very efficient and easy to operate.

How to use interface form to communicate with Activity

①New interface class IDataCallback


public interface IDataCallback {
    
    

    void dataCallback(Object obj);
}

②Create MyBinder and inherit Binder

public class MyBinder extends Binder {
    
    
    private MyService mService;

    public MyService getService() {
    
    
        return this.mService;
    }

    public void setService(MyService service) {
    
    
        this.mService = service;
    }
}

③Create Myservice to inherit Service

public class MyService extends Service {
    
    
    private IDataCallback mCallback;
    private int mCount = 0;

    public void setCallback(IDataCallback callback) {
    
    
        MyService.this.mCallback = callback;
    }

    @Override
    public void onCreate() {
    
    
        super.onCreate();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    
    
            startForeground(this);
        }
        Log.d(">>>>", "onCreate: 服务已启动");
        sendData();
    }

    private void sendData() {
    
    
        //模拟发送数据
        final Handler handler = new Handler();
        final Runnable runnable = new Runnable() {
    
    
            @Override
            public void run() {
    
    
                if (mCallback != null) {
    
    
                    mCount++;
                    MyService.this.mCallback.dataCallback("发送数据次数:" + mCount);
                }
                if (mCount <= 10) {
    
    
                    handler.postDelayed(this, 1000);
                }

            }
        };

        handler.postDelayed(runnable, 1000);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
    
    
        return new MyBinder(MyService.this);
    }

    public static void startForeground(Service ctx) {
    
    
        try {
    
    
            String CHANNEL_ONE_ID = "CHANNEL_ONE_ID";
            String CHANNEL_ONE_NAME = "CHANNEL_ONE_ID";
            int SERVICE_ID = 811;
            NotificationChannel notificationChannel;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    
    
                notificationChannel = new NotificationChannel(
                        CHANNEL_ONE_ID, CHANNEL_ONE_NAME, NotificationManager.IMPORTANCE_HIGH);
                notificationChannel.enableLights(true);
                notificationChannel.setLightColor(R.color.colorAccent);
                notificationChannel.setShowBadge(true);
                notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
                NotificationManager nm = (NotificationManager) ctx.getSystemService(NOTIFICATION_SERVICE);
                if (nm != null) {
    
    
                    nm.createNotificationChannel(notificationChannel);
                }
            }
            Intent intent = new Intent();
            Class<?> className = Class.forName("com.struggle.servicedemo.MainActivity");
            intent.setClassName(ctx, className.getName());
            PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 0, intent, 0);
            NotificationCompat.Builder builder = new NotificationCompat.Builder(ctx, CHANNEL_ONE_ID);
            builder.setContentTitle("标题")
                    .setContentText("内容")
                    .setWhen(System.currentTimeMillis())
                    .setPriority(Notification.PRIORITY_MIN)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentIntent(pendingIntent)
                    .setAutoCancel(true);
            Notification notification = builder.build();
            ctx.startForeground(SERVICE_ID, notification);
        } catch (ClassNotFoundException e) {
    
    
            e.printStackTrace();
        }
    }
}

④Code in Activity

public class MainActivity extends AppCompatActivity implements IDataCallback {
    
    
    private MyBinder mBinder;
    private ServiceConnection mConn;
    private Intent mIntent;

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

    public void startService(View view) {
    
    
        startService();
    }

    public void bindService(View view) {
    
    
        mConn = new MyServiceConn();
        bindService(mIntent, mConn, Context.BIND_AUTO_CREATE);
    }

    private void startService() {
    
    
        mIntent = new Intent(this, MyService.class);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    
    
            //ps 8.0 后一定要通过这种方式启动
            startForegroundService(mIntent);
        } else {
    
    
            startService(mIntent);
        }
    }

    @Override
    public void dataCallback(Object obj) {
    
    
        Log.d(">>>>>", "dataCallback: "+obj.toString());
    }


    private class MyServiceConn implements ServiceConnection {
    
    

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
    
    
            Log.d(">>>>", "onServiceConnected: 服务已绑定");
            mBinder = (MyBinder) service;
            mBinder.getService().setCallback(MainActivity.this);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
    
    
            Log.d(">>>>", "onServiceDisconnected: 服务绑定失败");
            mBinder = null;
            unbindService(mConn);
        }
    }
}

So far, the communication has been completed, but there are a few issues that need to be paid attention to:
① The service must be registered in the list (basic common sense), otherwise the service will not be activated.

 <application
  <service android:name=".MyService" />
  </application>

②Apply for permission

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

Otherwise it will report:

 Caused by: java.lang.SecurityException: Permission Denial: startForeground from pid=30149, uid=10249 requires android.permission.FOREGROUND_SERVICE
to sum up

The code has commented on how to start the service. 8.0 should be that Google has fixed the vulnerability of the service. startForeground() is mainly used to operate the notification bar to remind the user what is running. Before 7.0, it can be the same by starting two id, hide the notification bar, 8.0 will not work after testing, and the CHANNEL_ID of NotificationChannel and NotificationCompat must be consistent.

Guess you like

Origin blog.csdn.net/zhuhuitao_struggle/article/details/104808689