commit 1ee0408aacb94efa439b083436d4c63a712d8c7e Author: linglongxin24 Date: Thu Nov 17 15:16:17 2016 +0800 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..c599907 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +#深入Activity,Activity启动模式LaunchMode完全解析 + +#1.Standard:标准启动模式 +Activity默认模式,所有的Activity遵循元素进栈出栈的特性,例如进栈序列为A->B->C->D,D呈现在页面上,按返回键出栈顺序久违D->C->B->A. + +```flow +st=>start: Start +i=>inputoutput: 输入年份n +cond1=>condition: n能否被4整除? +cond2=>condition: n能否被100整除? +cond3=>condition: n能否被400整除? +o1=>inputoutput: 输出非闰年 +o2=>inputoutput: 输出非闰年 +o3=>inputoutput: 输出闰年 +o4=>inputoutput: 输出闰年 +e=>end +st->i->cond1 +cond1(no)->o1->e +cond1(yes)->cond2 +cond2(no)->o3->e +cond2(yes)->cond3 +cond3(yes)->o2->e +cond3(no)->o4->e +``` + +#2.SingleTop:栈顶复用模式 +栈顶复用模式,如果要开启的activity在任务栈的顶部已经存在,就不会创建新的实例,而是调用 onNewIntent() 方法。避免栈顶的activity被重复的创建。 +#3.SingleTask:栈内复用模式 +如果要启动的Activity在当前栈内启动,activity只会在任务栈里面存在一个实例。如果要激活的activity,在任务栈里面已经存在,就不会创建新的activity,而是复用这个已经存在的activity,调用 onNewIntent() 方法,并且清空这个activity任务栈上面所有的activity。 +#4.SingleInstance:单一实例模式 +整个手机操作系统里面只有一个实例存在。不同的应用去打开这个activity 共享公用的同一个activity。他会运行在自己单独,独立的任务栈里面,并且任务栈里面只有他一个实例存在。应用场景:呼叫来电界面。这种模式的使用情况比较罕见,在Launcher中可能使用。或者你确定你需要使Activity只有一个实例。 \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..e744b22 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,30 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 25 + buildToolsVersion "25.0.0" + defaultConfig { + applicationId "cn.bluemobi.dylan.activitylaunchmode" + minSdkVersion 9 + targetSdkVersion 25 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(include: ['*.jar'], dir: 'libs') + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + compile 'com.android.support:appcompat-v7:25.0.0' + testCompile 'junit:junit:4.12' + compile 'com.android.support:design:25.0.0' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..d28a1a5 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in E:\kejiang\Android\sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/androidTest/java/cn/bluemobi/dylan/activitylaunchmode/ExampleInstrumentedTest.java b/app/src/androidTest/java/cn/bluemobi/dylan/activitylaunchmode/ExampleInstrumentedTest.java new file mode 100644 index 0000000..5a5107e --- /dev/null +++ b/app/src/androidTest/java/cn/bluemobi/dylan/activitylaunchmode/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package cn.bluemobi.dylan.activitylaunchmode; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumentation test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("cn.bluemobi.dylan.activitylaunchmode", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..d9a04d8 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/MainActivity.java b/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/MainActivity.java new file mode 100644 index 0000000..33397b3 --- /dev/null +++ b/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/MainActivity.java @@ -0,0 +1,27 @@ +package cn.bluemobi.dylan.activitylaunchmode; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; + +import cn.bluemobi.dylan.activitylaunchmode.singletask.SingleTaskActivity; +import cn.bluemobi.dylan.activitylaunchmode.singletop.SingleTopActivity; + +public class MainActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.content_main); + + } + + public void onClick(View view) { + startActivity(new Intent(this, SingleTopActivity.class)); + } + + public void onClick2(View view) { + startActivity(new Intent(this, SingleTaskActivity.class)); + } +} diff --git a/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/NotificationUtil.java b/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/NotificationUtil.java new file mode 100644 index 0000000..b905662 --- /dev/null +++ b/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/NotificationUtil.java @@ -0,0 +1,156 @@ +package cn.bluemobi.dylan.activitylaunchmode; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.net.Uri; +import android.support.v7.app.NotificationCompat; +import android.util.Log; +import android.widget.RemoteViews; + +import java.util.Timer; +import java.util.TimerTask; + +import cn.bluemobi.dylan.activitylaunchmode.singletop.SingleTopActivity; + +/** + * 显示通知栏工具类 + * Created by Administrator on 2016-11-14. + */ + +public class NotificationUtil { + /** + * 显示一个普通的通知 + * + * @param context 上下文 + */ + public static void showNotification(Context context) { + Notification notification = new NotificationCompat.Builder(context) + /**设置通知左边的大图标**/ + .setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher)) + /**设置通知右边的小图标**/ + .setSmallIcon(R.mipmap.ic_launcher) + /**通知首次出现在通知栏,带上升动画效果的**/ + .setTicker("通知来了") + /**设置通知的标题**/ + .setContentTitle("这是一个通知的标题") + /**设置通知的内容**/ + .setContentText("这是一个通知的内容这是一个通知的内容") + /**通知产生的时间,会在通知信息里显示**/ + .setWhen(System.currentTimeMillis()) + /**设置该通知优先级**/ + .setPriority(Notification.PRIORITY_DEFAULT) + /**设置这个标志当用户单击面板就可以让通知将自动取消**/ + .setAutoCancel(true) + /**设置他为一个正在进行的通知。他们通常是用来表示一个后台任务,用户积极参与(如播放音乐)或以某种方式正在等待,因此占用设备(如一个文件下载,同步操作,主动网络连接)**/ + .setOngoing(false) + /**向通知添加声音、闪灯和振动效果的最简单、最一致的方式是使用当前的用户默认设置,使用defaults属性,可以组合:**/ + .setDefaults(Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND) + .setContentIntent(PendingIntent.getActivity(context, 1, new Intent(context, SingleTopActivity.class), PendingIntent.FLAG_CANCEL_CURRENT)) + .build(); + NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); + /**发起通知**/ + notificationManager.notify(0, notification); + } + + /** + * 显示一个下载带进度条的通知 + * + * @param context 上下文 + */ + public static void showNotificationProgress(Context context) { + //进度条通知 + final NotificationCompat.Builder builderProgress = new NotificationCompat.Builder(context); + builderProgress.setContentTitle("下载中"); + builderProgress.setSmallIcon(R.mipmap.ic_launcher); + builderProgress.setTicker("进度条通知"); + builderProgress.setProgress(100, 0, false); + final Notification notification = builderProgress.build(); + final NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); + //发送一个通知 + notificationManager.notify(2, notification); + /**创建一个计时器,模拟下载进度**/ + Timer timer = new Timer(); + timer.schedule(new TimerTask() { + int progress = 0; + + @Override + public void run() { + Log.i("progress", progress + ""); + while (progress <= 100) { + progress++; + try { + Thread.sleep(100); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + //更新进度条 + builderProgress.setProgress(100, progress, false); + //再次通知 + notificationManager.notify(2, builderProgress.build()); + } + //计时器退出 + this.cancel(); + //进度条退出 + notificationManager.cancel(2); + return;//结束方法 + } + }, 0); + } + + /** + * 悬挂式,支持6.0以上系统 + * + * @param context + */ + public static void showFullScreen(Context context) { + NotificationCompat.Builder builder = new NotificationCompat.Builder(context); + Intent mIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://blog.csdn.net/itachi85/")); + PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, mIntent, 0); + builder.setContentIntent(pendingIntent); + builder.setSmallIcon(R.mipmap.ic_launcher); + builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher)); + builder.setAutoCancel(true); + builder.setContentTitle("悬挂式通知"); + //设置点击跳转 + Intent hangIntent = new Intent(); + hangIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + hangIntent.setClass(context, MainActivity.class); + //如果描述的PendingIntent已经存在,则在产生新的Intent之前会先取消掉当前的 + PendingIntent hangPendingIntent = PendingIntent.getActivity(context, 0, hangIntent, PendingIntent.FLAG_CANCEL_CURRENT); + builder.setFullScreenIntent(hangPendingIntent, true); + NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); + notificationManager.notify(3, builder.build()); + } + /** + * 折叠式 + * + * @param context + */ + public static void shwoNotify(Context context) { + //先设定RemoteViews + RemoteViews view_custom = new RemoteViews(context.getPackageName(), R.layout.view_custom); + //设置对应IMAGEVIEW的ID的资源图片 + view_custom.setImageViewResource(R.id.custom_icon, R.mipmap.icon); + view_custom.setTextViewText(R.id.tv_custom_title, "今日头条"); + view_custom.setTextColor(R.id.tv_custom_title, Color.BLACK); + view_custom.setTextViewText(R.id.tv_custom_content, "金州勇士官方宣布球队已经解雇了主帅马克-杰克逊,随后宣布了最后的结果。"); + view_custom.setTextColor(R.id.tv_custom_content, Color.BLACK); + NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context); + mBuilder.setContent(view_custom) + .setContentIntent(PendingIntent.getActivity(context, 4, new Intent(context, MainActivity.class), PendingIntent.FLAG_CANCEL_CURRENT)) + .setWhen(System.currentTimeMillis())// 通知产生的时间,会在通知信息里显示 + .setTicker("有新资讯") + .setPriority(Notification.PRIORITY_HIGH)// 设置该通知优先级 + .setOngoing(false)//不是正在进行的 true为正在进行 效果和.flag一样 + .setSmallIcon(R.mipmap.icon); + Notification notify = mBuilder.build(); + NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE); + notificationManager.notify(4, notify); + } +} diff --git a/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/singletask/LoginActivity.java b/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/singletask/LoginActivity.java new file mode 100644 index 0000000..d40bb76 --- /dev/null +++ b/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/singletask/LoginActivity.java @@ -0,0 +1,33 @@ +package cn.bluemobi.dylan.activitylaunchmode.singletask; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; + +/** + * Created by yuandl on 2016-11-17. + */ + +public class LoginActivity extends AppCompatActivity { + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Button button = new Button(this); + button.setGravity(Gravity.CENTER); + button.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + button.setText("1登录界面,无账号点击注册"); + setContentView(button); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(LoginActivity.this, RegisterActivity.class)); + } + }); + } + +} diff --git a/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/singletask/RegisterActivity.java b/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/singletask/RegisterActivity.java new file mode 100644 index 0000000..c4b4fef --- /dev/null +++ b/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/singletask/RegisterActivity.java @@ -0,0 +1,33 @@ +package cn.bluemobi.dylan.activitylaunchmode.singletask; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; + +/** + * Created by yuandl on 2016-11-17. + */ + +public class RegisterActivity extends AppCompatActivity { + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Button button = new Button(this); + button.setGravity(Gravity.CENTER); + button.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + button.setText("2注册界面,注册完成直接登录成功去主界面0"); + setContentView(button); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(RegisterActivity.this, SingleTaskActivity.class)); + } + }); + } + +} diff --git a/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/singletask/SingleTaskActivity.java b/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/singletask/SingleTaskActivity.java new file mode 100644 index 0000000..5ae7c24 --- /dev/null +++ b/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/singletask/SingleTaskActivity.java @@ -0,0 +1,39 @@ +package cn.bluemobi.dylan.activitylaunchmode.singletask; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.TextView; + +import cn.bluemobi.dylan.activitylaunchmode.NotificationUtil; +import cn.bluemobi.dylan.activitylaunchmode.R; +import cn.bluemobi.dylan.activitylaunchmode.singletop.LoginSuccessActivity; +import cn.bluemobi.dylan.activitylaunchmode.singletop.SingleTopActivity; + +/** + * Created by yuandl on 2016-11-17. + */ + +public class SingleTaskActivity extends AppCompatActivity { + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Button button = new Button(this); + button.setGravity(Gravity.CENTER); + button.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + button.setText("0主界面,某些功能需要登陆-->需要点击登陆"); + setContentView(button); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(SingleTaskActivity.this, LoginActivity.class)); + } + }); + } + +} diff --git a/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/singletop/LoginSuccessActivity.java b/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/singletop/LoginSuccessActivity.java new file mode 100644 index 0000000..6b908a9 --- /dev/null +++ b/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/singletop/LoginSuccessActivity.java @@ -0,0 +1,28 @@ +package cn.bluemobi.dylan.activitylaunchmode.singletop; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.widget.TextView; + +/** + * Created by yuandl on 2016-11-17. + */ + +public class LoginSuccessActivity extends AppCompatActivity { + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + TextView textView = new TextView(this); + textView.setText("登陆成功界面"); + setContentView(textView); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + Log.d("Tag","onNewIntent"); + } +} diff --git a/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/singletop/SingleTopActivity.java b/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/singletop/SingleTopActivity.java new file mode 100644 index 0000000..8ed36a4 --- /dev/null +++ b/app/src/main/java/cn/bluemobi/dylan/activitylaunchmode/singletop/SingleTopActivity.java @@ -0,0 +1,40 @@ +package cn.bluemobi.dylan.activitylaunchmode.singletop; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.app.AppCompatActivity; +import android.view.View; + +import cn.bluemobi.dylan.activitylaunchmode.NotificationUtil; +import cn.bluemobi.dylan.activitylaunchmode.R; + +/** + * Created by yuandl on 2016-11-17. + */ + +public class SingleTopActivity extends AppCompatActivity { + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.ac_singletop); + } + + public void onClick1(View v) { + NotificationUtil.showNotification(this); + } + public void onClick2(View v) { + new Thread(){ + @Override + public void run() { + super.run(); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + startActivity(new Intent(SingleTopActivity.this,LoginSuccessActivity.class)); + } + }.start(); + } +} diff --git a/app/src/main/res/layout/ac_singletop.xml b/app/src/main/res/layout/ac_singletop.xml new file mode 100644 index 0000000..b5d29d0 --- /dev/null +++ b/app/src/main/res/layout/ac_singletop.xml @@ -0,0 +1,21 @@ + + + +