我创建了一个应用程序,它具有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%是正常的,这不是问题的原因。
Method Tracer
答案 0 :(得分:0)
我认为这可能是Intent Flags的问题。必须尝试添加标志 Intent.FLAG_ACTIVITY_LAUCHED_FROM_HISTORY?我还注意到你在AndroidManifest.xml中设置了android:noHistory =“true”。这有必要吗?
希望以上可以解决您的问题。如果它不起作用,你可以上传一个简单版本的apk进行测试吗?