延迟从聊天主管服务启动活动

时间:2016-11-01 13:17:50

标签: android android-activity service

我创建了一个应用程序,它具有Facebook,聊天头等服务。在点击聊天时,我正在启动一个活动(请参阅MyActivity的代码)。我在特定情况下启动活动延迟,如下所述

  • 点击聊天头;活动启动良好
  • 按主页按钮;根据我的逻辑,活动会破坏
  • 现在,如果我再次单击“聊天”,它将以延迟启动活动(少数 秒)

如果我从最近的活动堆栈中清除活动,或者如果我按下后退按钮,则此问题不会出现。即使我删除dispatchKeyEvent功能

,问题仍然存在
public class MyActivity extends AppCompatActivity implements ChatHeadListener{

    public static final String DESTROY = "destroy";
    public static final String MAXIMIZED = "MAXIMIZED";
    public static final String MINIMIZED = "MINIMIZED";
    public static final String STATE = "State";
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ChatHead.getInstance().setChatHeadListener(this);
        setContentView(R.layout.float_body);
        textView = (TextView) findViewById(R.id.root_text);
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
                || event.getKeyCode() == KeyEvent.KEYCODE_HOME) {
            finish();
            return true;
        }
        return super.dispatchKeyEvent(event);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Intent destroy = new Intent(DESTROY);
        destroy.putExtra(STATE, MAXIMIZED);
        LocalBroadcastManager.getInstance(this).sendBroadcast(destroy);
    }

    @Override
    protected void onDestroy() {
        Intent destroy = new Intent(DESTROY);
        destroy.putExtra(STATE, MINIMIZED);
        LocalBroadcastManager.getInstance(this).sendBroadcast(destroy);
        super.onDestroy();
    }

    @Override
    public void onChatHeadClick(HeadModel headModel) {
        //method from my interface
        if(textView!=null){
            textView.setText(headModel.getVisitorName()+"");
        }
    }
}

更新(2016年4月4日)

MainActivity

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    button_start = (Button) findViewById(R.id.button_start);
    button_stop = (Button) findViewById(R.id.button_stop);
    Intent intent = new Intent(this, MainActivity.class);
    PendingIntent resultPendingIntent = PendingIntent.getActivity(
            this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    Notification notification = ChatHead.createNotification(
            this, "Chat head", "Service Running",
            R.drawable.ic_android_red_500_48dp, resultPendingIntent);

    View maxView = LayoutInflater.from(this).inflate(R.layout.chat_head_recycler, null);
    View minView = LayoutInflater.from(this).inflate(R.layout.chat_head_view, null);

    chatHead = ChatHead.createInstance(this, maxView, minView, NOTIFICATION_ID,
            notification, new ChatHeadOrientationListener() {
        @Override
        public void beforeOrientationChange(ChatHead chatHead) {
            Toast.makeText(MainActivity.this, "Orientation Change Start",
                    Toast.LENGTH_SHORT).show();
        }

        @Override
        public void afterOrientationChange(ChatHead chatHead) {
            Toast.makeText(MainActivity.this, "Orientation Change End",
                    Toast.LENGTH_SHORT).show();
        }
    });

    button_start.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                startChatHeadForAboveAndroidL();
            } else {
                chatHead.startService();
            }
        }
    });

    button_stop.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            chatHead.stopService();
        }
    });
}

@TargetApi(Build.VERSION_CODES.M)
public void startChatHeadForAboveAndroidL() {
    if (!Settings.canDrawOverlays(this)) {
        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                Uri.parse("package:" + getPackageName()));
        startActivityForResult(intent, PERMISSION_REQUEST_CODE);
    } else {
        chatHead.startService();
    }
}

ChatHead类

public class ChatHead{

    private final View maxView, minView;
    private final Context context;
    private final Notification notification;
    private final int notificationId;
    private static ChatHead chatHead;
    private static State state;
    private final ChatHeadOrientationListener chatHeadOrientationListener;
    private float ratioY = 0;
    private float oldWidth = 0;
    private float oldX = 0;
    private boolean confChange = false;
    private static ChatHeadListener chatHeadListener;
    private static final String TAG = "ChatHead";
    private FragmentTransaction fragmentTransaction;

    /**
     *
     * @return The maxView of the chatHead which is assigned through the
     * {@link #createInstance} method.
     */
    public View getMaxView() {
        return chatHead.maxView;
    }

    /**
     *
     * Creates a Singleton of the Floating Window
     *
     * @param context The application context
     * @param maxView The maxView View, upon clicking it the body is to be opened
     * @param notificationId The notificationId for your notification
     * @param notification The notification which is displayed for the foreground service
     * @param chatHeadOrientationListener The {@link ChatHeadOrientationListener} interface
     *                                    with callbacks which are called when orientation changes.
     * @return A Floating Window
     *
     */
    public static synchronized ChatHead createInstance(Context context, View maxView, View minView,
                                                       int notificationId, Notification notification,
                                                       ChatHeadOrientationListener
                                                               chatHeadOrientationListener) {
        if (chatHead == null) {
            chatHead = new ChatHead(context, maxView, minView, notificationId, notification,
                    chatHeadOrientationListener);
        }
        return chatHead;
    }

    /**
     *
     * Creates a Singleton of the Floating Window
     *
     * @param context The application context
     * @param maxView The maxView View, upon clicking it the body is to be opened
     * @param notificationId The notificationId for your notification
     * @param notification The notification which is displayed for the foreground service
     * @return A Floating Window
     *
     */
    public static synchronized ChatHead createInstance(Context context, View maxView, View minView,
                                                       int notificationId, Notification notification) {
        if (chatHead == null) {
            chatHead = new ChatHead(context, maxView, minView, notificationId,
                    notification, new ChatHeadOrientationListener() {
                @Override
                public void beforeOrientationChange(ChatHead chatHead) {
                    Log.d(TAG, "beforeOrientationChange");
                }

                @Override
                public void afterOrientationChange(ChatHead chatHead) {
                    Log.d(TAG, "afterOrientationChange");
                }
            });
        }
        return chatHead;
    }

    /**
     * @return The same instance of Floating Window, which has been created through
     * {@link #createInstance}. Don't call this method before createInstance
     */
    static synchronized ChatHead getInstance() {
        if (chatHead == null) {
            throw new NullPointerException("ChatHead not initialized! " +
                    "First call createInstance method, then to access " +
                    "ChatHead in any other class call getInstance()");
        }
        return chatHead;
    }

    private ChatHead(Context context, View maxView, View minView, int notificationId,
                     Notification notification, ChatHeadOrientationListener chatHeadOrientationListener) {
        this.maxView = maxView;
        this.minView = minView;
        this.context = context;
        this.notification = notification;
        this.notificationId = notificationId;
        this.chatHeadOrientationListener = chatHeadOrientationListener;
    }

    /**
     * Starts the service and adds it to the screen
     */
    public void startService() {
        Intent intent = new Intent(context, ChatHeadService.class);
        context.startService(intent);
    }

    /**
     * Stops the service and removes it from the screen
     */
    public void stopService() {
        Intent intent = new Intent(context, ChatHeadService.class);
        context.stopService(intent);
    }

    /**
     *
     * Helper method for notification creation.
     *
     * @param context
     * @param contentTitle
     * @param contentText
     * @param notificationIcon
     * @param contentIntent
     * @return Notification for the Service
     */
    public static Notification createNotification(Context context,
                                                  String contentTitle, String contentText,
                                                  int notificationIcon, PendingIntent contentIntent) {
        return new NotificationCompat.Builder(context)
                .setContentTitle(contentTitle)
                .setContentText(contentText)
                .setSmallIcon(notificationIcon)
                .setContentIntent(contentIntent).build();
    }

    public static class ChatHeadService extends Service {

        private WindowManager windowManager;
        private WindowManager.LayoutParams params;
        private LinearLayout mLinearLayout;
        GestureDetectorCompat gestureDetectorCompat;
        DisplayMetrics metrics;
        private boolean didFling;
        private int[] clickLocation = new int[2];
        private LocalBroadcastManager localBroadcastManager;
        private RecyclerView recyclerView;
        private RelativeLayout rProgress, rSingleHeadCon;

        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }

        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE
                    || newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
                int[] location = new int[2];
                mLinearLayout.getLocationOnScreen(location);
                chatHead.oldWidth = metrics.widthPixels;
                chatHead.confChange = true;
                chatHead.oldX = location[0];
                chatHead.ratioY = (float) (location[1]) / (float) metrics.heightPixels;
                chatHead.chatHeadOrientationListener.beforeOrientationChange(chatHead);
                chatHead.stopService();
                chatHead.startService();
                chatHead.chatHeadOrientationListener.afterOrientationChange(chatHead);
            }
        }

        public int onStartCommand(Intent intent, int flags, int startId) {
            Log.d(TAG, "onStartCommand");
            metrics = new DisplayMetrics();
            windowManager.getDefaultDisplay().getMetrics(metrics);
            startForeground(chatHead.notificationId, chatHead.notification);
            return START_STICKY;
        }

        @Override
        public void onCreate() {
            super.onCreate();
            Log.d(TAG, "onCreate");
            localBroadcastManager = LocalBroadcastManager.getInstance(this);
            localBroadcastManager.registerReceiver(receiver,
                    new IntentFilter(MyActivity.DESTROY));
            recyclerView = (RecyclerView) chatHead.maxView.findViewById(R.id.rv_heads);
            recyclerView.setLayoutManager(new LinearLayoutManager(
                    this, LinearLayoutManager.HORIZONTAL, false));
            rProgress = (RelativeLayout) chatHead.minView.findViewById(R.id.head_progress);
            rSingleHeadCon = (RelativeLayout) chatHead.minView.findViewById(R.id.head_view_con);
            mLinearLayout = new LinearLayout(getApplicationContext());

            gestureDetectorCompat = new GestureDetectorCompat(
                    chatHead.context, new GestureDetector.SimpleOnGestureListener() {
                private int initialX;
                private int initialY;
                private float initialTouchX;
                private float initialTouchY;

                @Override
                public boolean onDown(MotionEvent event) {
                    Log.d(TAG, "onDown");
                    initialX = params.x;
                    initialY = params.y;
                    initialTouchX = event.getRawX();
                    initialTouchY = event.getRawY();
                    didFling = false;
                    return false;
                }

                @Override
                public void onShowPress(MotionEvent e) {
                    Log.d(TAG, "onShowPress");
                    chatHead.minView.setAlpha(0.8f);
                }

                @Override
                public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
                                        float distanceY) {
                    params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                    params.width = WindowManager.LayoutParams.WRAP_CONTENT;
                    params.height = WindowManager.LayoutParams.WRAP_CONTENT;
                    params.x = (initialX + (int) ((e2.getRawX() - initialTouchX)));
                    params.y = (initialY + (int) ((e2.getRawY() - initialTouchY)));
                    windowManager.updateViewLayout(mLinearLayout, params);
                    return false;
                }

                @Override
                public boolean onSingleTapConfirmed(MotionEvent e) {
                    Log.e(TAG, "Logging ChatHead: onSingleTapConfirmed ");
                    state = State.LOADING;
                    rProgress.setVisibility(View.VISIBLE);
                    rSingleHeadCon.setVisibility(View.GONE);
                    chatHead.minView.getLocationOnScreen(clickLocation);
                    params.x = clickLocation[0];
                    params.y = clickLocation[1] - 36;
                    windowManager.updateViewLayout(mLinearLayout, params);
                    Intent intent = new Intent(ChatHeadService.this,MyActivity.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
                            | Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
                    return false;
                }

                @Override
                public boolean onDoubleTap(MotionEvent e) {
                    chatHead.stopService();
                    return false;
                }

                @Override
                public boolean onFling(MotionEvent e1, MotionEvent e2,
                                       float velocityX, float velocityY) {
                    Log.d(TAG, "onFling");
                    didFling = true;
                    int newX = params.x;
                    if (newX > (metrics.widthPixels / 2))
                        params.x = metrics.widthPixels;
                    else
                        params.x = 0;
                    windowManager.updateViewLayout(mLinearLayout, params);
                    return false;
                }
            });

            mLinearLayout.setOrientation(LinearLayout.VERTICAL);
            windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
            metrics = new DisplayMetrics();
            windowManager.getDefaultDisplay().getMetrics(metrics);
            params = new WindowManager.LayoutParams(
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.TYPE_PHONE,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                    PixelFormat.TRANSLUCENT);
            params.gravity = Gravity.TOP | Gravity.LEFT;

            if (chatHead.confChange) {
                chatHead.confChange = false;
                if (chatHead.oldX < (chatHead.oldWidth / 2)) {
                    params.x = 0;
                } else {
                    params.x = metrics.widthPixels;
                }
                params.y = (int) (metrics.heightPixels * chatHead.ratioY);
            } else {
                params.x = metrics.widthPixels;
                params.y = 0;
            }
            chatHead.minView.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    gestureDetectorCompat.onTouchEvent(event);
                    if (event.getAction() == MotionEvent.ACTION_UP) {
                        chatHead.minView.setAlpha(1.0f);
                        if (!didFling) {
                            Log.d(TAG, "ACTION_UP");
                            int newX = params.x;
                            if (newX > (metrics.widthPixels / 2)) {
                                params.x = metrics.widthPixels;
                            }else {
                                params.x = 0;
                                windowManager.updateViewLayout(mLinearLayout, params);
                            }
                        }
                    }
                    return true;
                }
            });

            windowManager.addView(mLinearLayout, params);
            mLinearLayout.setFocusable(true);
            LinearLayout.LayoutParams headParams = new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            headParams.gravity = Gravity.TOP | Gravity.RIGHT;
            mLinearLayout.addView(chatHead.minView, headParams);
        }

        private void minimiseChatHead() {
            state = State.MINIMIZED;
            rProgress.setVisibility(View.GONE);
            rSingleHeadCon.setVisibility(View.VISIBLE);
            params.x = clickLocation[0];
            params.y = clickLocation[1] - 36;
            params.width = WindowManager.LayoutParams.WRAP_CONTENT;
            params.height = WindowManager.LayoutParams.WRAP_CONTENT;

            mLinearLayout.setFocusable(true);
            mLinearLayout.removeAllViews();
            LinearLayout.LayoutParams headParams = new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            headParams.gravity = Gravity.TOP | Gravity.RIGHT;
            mLinearLayout.addView(chatHead.minView, headParams);
            mLinearLayout.setTag("IMAGEVIEW_TAG");

            //TODO close activity
            windowManager.updateViewLayout(mLinearLayout, params);
        }

        private void maximiseChatHead() {
            state = State.MAXIMIZED;
            params.x = metrics.widthPixels;
            params.y = 0;
//          params.flags = params.flags & ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
            params.width = WindowManager.LayoutParams.MATCH_PARENT;
            params.height = WindowManager.LayoutParams.WRAP_CONTENT;
//          chatHead.body.setVisibility(View.VISIBLE);
            List<HeadModel> heads = new ArrayList<>();
            heads.add(new HeadModel("chat1"));
            heads.add(new HeadModel("chat2"));
            heads.add(new HeadModel("chat3"));
            final ChatHeadsAdapter chatHeadsAdapter = new ChatHeadsAdapter(chatHead.context, heads);
            recyclerView.setAdapter(chatHeadsAdapter);

            chatHeadsAdapter.setOnLinkClickListener(new ChatHeadsAdapter.OnLinkClickListener() {
                @Override
                public void onSingleTapListener(final HeadModel headModel, final int position) {
                    if(state==State.MAXIMIZED){
                        if(chatHeadListener!=null){
                            chatHeadListener.onChatHeadClick(headModel);
                        }else{
                            maximiseChatHead();
                        }
                    }else if(state==State.MINIMIZED){
                        maximiseChatHead();
                    }
                }

                @Override
                public void onDoubleTapListener(final HeadModel headModel, final int position) {
                    chatHeadsAdapter.getHeads().remove(position);
                    chatHeadsAdapter.notifyItemRemoved(position);
                }
            });

//          mLinearLayout.setFocusable(true);
            mLinearLayout.removeAllViews();
            LinearLayout.LayoutParams headParams = new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            headParams.gravity = Gravity.TOP | Gravity.RIGHT;
            mLinearLayout.addView(chatHead.maxView, headParams);

            windowManager.updateViewLayout(mLinearLayout, params);
        }

        public void onDestroy() {
            super.onDestroy();
            localBroadcastManager.unregisterReceiver(receiver);
            if (mLinearLayout != null) {
                mLinearLayout.removeAllViews();
                windowManager.removeView(mLinearLayout);
            }
            stopForeground(true);
        }

        private final BroadcastReceiver receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String bCast = intent.getStringExtra(MyActivity.STATE);
                Log.e(TAG, "Logging Chathead: onReceive "+bCast);
                if(bCast.equals(MyActivity.MAXIMIZED)){
                    maximiseChatHead();
                }else if(bCast.equals(MyActivity.MINIMIZED)){
                    minimiseChatHead();
                }
            }
        };
    }

    void setChatHeadListener(ChatHeadListener chatHeadListener) {
        ChatHead.chatHeadListener = chatHeadListener;
    }

    public static State getState() {
        return state;
    }

    private enum State {
        MAXIMIZED, MINIMIZED, LOADING
    }
}

清单

<service
    android:name="com.maavratech.chatheads.ChatHead$ChatHeadService"
    android:exported="true"/>

<activity
    android:name=".MyActivity"
    android:label="@string/app_name"
    android:noHistory="true"
    android:launchMode="singleTask"
    android:excludeFromRecents="true"
    android:theme="@style/ThemeChatHead"/>

MyActivity 是一个带有按钮和文字视图的简单活动

2016年7月11日更新

在正常情况下,CPU(用户空间)使用率为2%但是当我按下主页按钮并重新点击聊天头CPU使用率跃升至7%时。我认为7%是正常的,这不是问题的原因。

enter image description here

Method Tracer

enter image description here

1 个答案:

答案 0 :(得分:0)

我认为这可能是Intent Flags的问题。必须尝试添加标志 Intent.FLAG_ACTIVITY_LAUCHED_FROM_HISTORY?我还注意到你在AndroidManifest.xml中设置了android:noHistory =“true”。这有必要吗?

希望以上可以解决您的问题。如果它不起作用,你可以上传一个简单版本的apk进行测试吗?