主体思想
使用ActivityCollector来收集所有活动,所有的活动均继承自BaseActivity,使得每个活动在onCreate方法执行时,都会被加入到AcrivityCollector中。在每个活动onDestroy时都会从ActivityCollector中移除。这样就可以一次性将所有的活动全部销毁。在登陆界面输入账号密码,代码的设定是只有当敲击Login按钮时才会去获取两个EditText中,符合逻辑
交互的流程是,输入账号密码,无误后跳转到MainActivity,点击按钮发送广播,app中的recreiver接收到广播执行onReceive方法,弹出AlertDialog窗口,给ok按钮设置监听。按下ok之后,用ActivityCollector销毁所有活动,重新加载login活动
值得注意
因为是从接收器中弹出活动,intent需加入FLAG_ACTIVITY_NEW_TASK
,形如intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
,在接受器里启动活动,需以这样的格式:context.startActivity(intent)
,而intent的初始化是以这样的形式:Intent intent = new Intent(context,MainActivity.class)
,似乎在接收器里都用context来表示接收器的上下文
再有,因为提示框是从广播接收器中弹出的,所以需要把对话框的类型设置为TYPE_SYSTEM_ALERT
,形如:alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
,由于都调用了系统级别的对话框,也需要在Manifest文件下注册<user-permission android:name="android.permission.SYSTEM_ALERT_WINDOW">
,该应用才能使用该对话框
另外需要注意的是,AlertDialog的造法:
1 2 3 4 5 6 7
|
AlertDialog.Builder builder = new AlertDialog.Builder(context) builder.setTitle builder.setMessage builder.setPositiveButton("OK",new OnclickListener{....}) AlertDialog alertDialog = builder.create(); alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT) alertDialog.show()
|
先弄个builder,再用这个builder去建一个AlertDialog,接着再设置这个AlertDialog的类型,最后让他show出来
代码结构
代码结构
上代码
ActivityCollector.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
public class ActivityCollector {
public static List<Activity> activities = new ArrayList<Activity>();
public static void addActivity(Activity activity){ activities.add(activity); }
public static void removeActivity(Activity activity){ activities.remove(activity); }
public static void finishAll(){ for(Activity activity : activities){ if(!activity.isFinishing()){ activity.finish(); } } } }
|
BaseActivity.class
1 2 3 4 5 6 7 8 9 10 11 12 13
|
public class BaseActivity extends Activity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityCollector.addActivity(this); }
@Override protected void onDestroy() { super.onDestroy(); ActivityCollector.removeActivity(this); } }
|
forceReceiver.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
public class ForceOffReceiver extends BroadcastReceiver{
@Override public void onReceive(final Context context, final Intent intent) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle("Waring"); builder.setCancelable(false); builder.setMessage("you are forced to offline"); builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { ActivityCollector.finishAll(); Intent intent1 = new Intent(context,loginActivity.class); intent1.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent1); } });
AlertDialog alertDialog = builder.create(); alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); alertDialog.show(); } }
|
loginActivity.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
public class loginActivity extends BaseActivity {
EditText accountEdit;
EditText passwordEdit;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); accountEdit = (EditText) findViewById(R.id.content_account); passwordEdit = (EditText) findViewById(R.id.content_password); Button btn = (Button) findViewById(R.id.btn_login); btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String account = accountEdit.getText().toString(); String password = passwordEdit.getText().toString(); if(account.equals("guojiale") && password.equals("123456")){ Intent intent = new Intent(loginActivity.this,MainActivity.class); startActivity(intent); } else{ Toast.makeText(loginActivity.this, "Check your account and password", Toast.LENGTH_SHORT).show(); } } }); }
}
|
MainActivity.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
public class MainActivity extends BaseActivity {
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = (Button) findViewById(R.id.btn_sendBrodcast); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent("forceOff"); sendBroadcast(intent); } }); }
}
|
零散笔记
广播接收器中不允许开线程,如果广播接收器中有太多操作,耗时太长,程序会报错
在一个应用的Manifest文件中,配置
使得该应用获得监听系统开机广播的权限,在中,写 rr这是在注册监听器
在manifest中receiver(接收器)的intent-filter中的action是表示该接收器监听的广播类型一旦收到相应类型的广播,就会执行该接收器中的逻辑
在一个活动中发送广播,sendBroadcast
为发送标准广播,sendOrderedBroadcast
为发送有序广播,在Manifest文件下配置receiver
需要的intentFilter
,用priority
来判断接收器的接收顺序
使用abortBroadcast()
截断广播
1 2 3 4
|
LocalBroadcastManager l = LocalBraodcastManager.getInstace(this) l.registerReceiver(localReceiver,intentFilter); l.sendBroadcast(intent) l.unregisterReceiver(localReceiver)
|
抛出异常:
java.lang.RuntimeException: Unable to start receiver com.example.gaby.broadcastbestpractice.ForceOffReceiver: android.view.WindowManager$
BadTokenException: Unable to add window android.view.ViewRootImpl$W@d5bf998 – permission denied for this window type
原因:使用了系统级别的对话框,但没有在Manifest文件下声明该权限
解决办法:在Manifest文件下声明< user-permission android:name=”android.permission.SYSTEM_ALERT_WINDOW” />