• android入门学习 -- 3 -- 碎片Fragment&广播Broadcast


    android入门学习

    第四章

    简单碎片使用

    碎片Fragment兼顾平板
    嵌入在活动中的UI片段

    例子:一个活动中添加两个碎片
    新建一个左侧碎片布局和右侧碎片布局
    left_fragment.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/button"
            android:layout_gravity="center_horizontal"
            android:text="button"/>
    
    </LinearLayout>
    

    right_fragment.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:background="#00ffbb"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:textSize="20sp"
            android:text="This is a fragment"/>
    
    </LinearLayout>
    

    新建leftFragment和rightFragment类

    public class LeftFragment extends Fragment {
    
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.left_fragment, container, false);
            return view;
        }
    }
    
    public class RightFragment extends Fragment {
    
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.right_fragment, container, false);
            return view;
        }
    }
    

    inflater.inflate()

    在主活动的界面中添加两个碎片

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <fragment
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:name="org.nuaa.fragmenttest.LeftFragment"
            android:id="@+id/left_fragment"/>
    
        <fragment
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:name="org.nuaa.fragmenttest.RightFragment"
            android:id="@+id/right_fragment"/>
        
    
    </LinearLayout>
    

    使用name指定要添加的碎片类名

    动态添加碎片

    新建一个another_right_fragment.xml,内容与right_fragment.xml类似
    AnotherRightFragment类也是与RightFragment类似,也是重写onCreateView

    修改主活动的布局,将右边改成FragmentLayout

        <FrameLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:id="@+id/right_layout"/>
    

    修改主活动

    public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Button button = (Button) findViewById(R.id.button);
            button.setOnClickListener(this);
            replaceFragment(new RightFragment());
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.button:
                    replaceFragment(new AnotherRightFragment());
                    break;
    
                    default: break;
            }
        }
    
        private void replaceFragment(Fragment fragment) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            FragmentTransaction transaction = fragmentManager.beginTransaction();
            transaction.replace(R.id.right_layout, fragment);
            transaction.commit();
        }
    }
    

    新建repalceFragment方法,修改FragmentLayout中的碎片
    初始化replaceFragment(new RightFragment()),点击按钮后repalceFragment(new AnotherRightFragent())替换

    动态添加碎片的步骤:

    1. 创建待添加的碎片实例replaceFragment(new XXXXX())
    2. 获取FragmentManager,在活动中可以直接通过调用getSupportFragmentManager()方法获取
    3. 开启一个事务,通过调用beginTransaction()方法开启
    4. 向容器内添加或替换碎片,使用replace(),传入容器的id和代添加的碎片实例
    5. 提交事务,commit()

    在碎片中模拟返回栈

    在commit()之前添加一句transaction.addToBackStack(null),参数是String名字,用于描述返回栈的状态。

    碎片和活动之间通信

    活动中调用碎片

    RightFragment rightFragment = (RightFragment) getSupportFragmentManager().findFragmentById(R.id.right_fragment);
    

    碎片中调用活动

    MainActivity activity = (MainActivity) getActivity();
    

    有活动实例后,调用活动中的方法就容易了。另外当碎片中使用Context对象时,也可以用getActivity(),因为活动本身就是一个Context对象

    碎片生命周期

    运行,暂停,停止,销毁

    1. 运行
      碎片可见,关联的活动处于运行状态,碎片也处于运行
    2. 暂停
      活动进入暂停状态时(由于另外一个未占满屏幕的活动被添加到栈顶),相关联的碎片就会进入暂停
    3. 停止
      当活动进入暂停状态,关联的碎片就会进入停止状态,或,
      通过调用FragmentManager.remove()、repalce()方法将碎片从活动中移除,如果事务在提交前调用addToBackStack(),碎片也会进入停止状态,对用户完全不可见,有可能被系统回收
    4. 销毁
      碎片总是依附于活动,活动销毁,碎片也会销毁,或,
      通过调用FragmentManager.remove()、repalce()方法将碎片从活动中移除,事务在提交前没有调用addToBackStack(),碎片会进入销毁状态

    Fragment类的回调方法

    一般的活动有的方法,碎片都有,还有一些附加的

    • onAttach():当碎片和活动建立关联时
    • onCreateView():碎片创建视图,加载布局时调用
    • onActivityCreate():确保与碎片关联的活动一定已经创建完毕的时候调用
    • onDestroyView():与碎片关联的试图被移除的时候调用
    • onDetach():碎片与活动解除关联时使用

    生命周期
    添加一个碎片
    |
    onAttach
    |
    onCreat
    |
    onCreateView
    |
    onActivityCreate
    |
    onStart
    |
    onResume
    |
    碎片激活
    |
    onPause
    |
    onStop
    |
    onDestroyView
    |
    onDestroy
    |
    onDetach
    |
    碎片已销毁

    动态加载布局的技巧

    使用限定符

    判断时是使用单页还是双页模式,借助限定符Qualifiers

    屏幕大小 描述
    small 小屏幕
    normal 中等屏幕
    large 大屏幕
    xlarge 超大屏幕
    分辨率 描述
    ldpi 低分辨率120dpi以下
    mdpi 中等分辨率120dpi - 160dpi
    hdpi 高分辨率160dpi - 240dpi
    xhdpi 超高分辨率240dpi - 320dpi
    xxhdpi 超超高分辨率320dpi - 480dpi
    方向 描述
    land 横屏
    port 竖屏

    最小宽度限定符

    手动选择布局
    最小宽度限定符运行对屏幕的宽度指定一个最小值,以dp为单位,作为临界点
    例如新建一个layout-sw600dp的文件夹,说明在屏幕宽度大于600dp的设备上,会加载该文件夹下的文件,否则加载默认的layout下的布局文件

    碎片实践 - 新闻应用

    新建新闻类News

    public class News {
    
        private String title;
    
        private String content;
    
        public String getTitle() {
            return title;
        }
    
        public String getContent() {
            return content;
        }
    
        public void setTitle(String title) {
            this.title = title;
        }
    
        public void setContent(String content) {
            this.content = content;
        }
    
    }
    

    News中,title标题,content内容

    新建布局文件news_content_frag.xml,作为新闻内容布局

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:visibility="invisible"
            android:id="@+id/visibility_layout">
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:padding="10dp"
                android:textSize="25sp"
                android:id="@+id/news_title"/>
    
            <View
                android:layout_width="match_parent"
                android:layout_height="1dp"
                android:background="#000"/>
    
            <TextView
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:padding="15dp"
                android:textSize="18sp"
                android:id="@+id/news_content"/>
    
        </LinearLayout>
    
        <View
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:layout_alignParentLeft="true"
            android:background="#000"/>
    
    </RelativeLayout>
    

    黑色横线是用View实现的,颜色设置为黑色,宽或高设置为1dp

    新建一个NewsContentFragment类,继承自Fragment

    public class NewsContentFragment extends Fragment {
    
        private View view;
    
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            view = inflater.inflate(R.layout.news_content_frag, container, false);
            return view;
        }
    
        public void refresh(String newsTitle, String newsContent) {
            View visibilityLayout = view.findViewById(R.id.visibility_layout);
            visibilityLayout.setVisibility(View.VISIBLE);
    
            TextView newsTitleText = (TextView) view.findViewById(R.id.news_title);
            TextView newsContentText = (TextView) view.findViewById(R.id.news_content);
            newsTitleText.setText(newsTitle);
            newsContentText.setText(newsContent);
        }
    }
    

    加载的是news_content_frag.xml布局,refresh方法是每次点击后将新闻的标题和内容显示在fragment中。
    以上都是双页模式中使用的内容

    创建一个新的活动NewsContentActivity,布局名为news_content.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <fragment
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:name="org.nuaa.fragmentbestpractice.NewsContentFragment"
            android:id="@+id/news_content_fragment"/>
    
    </LinearLayout>
    

    这里直接复用NewsContentFragment
    修改NewsContentActivity代码

    public class NewsContentActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.news_content);
    
            String newsTitle = getIntent().getStringExtra("news_title");
            String newsContent = getIntent().getStringExtra("news_content");
    
            NewsContentFragment newsContentFragment = (NewsContentFragment)
                    getSupportFragmentManager().findFragmentById(R.id.news_content_fragment);
            newsContentFragment.refresh(newsTitle, newsContent);
        }
    
        public static void actionStart(Context context, String newsTitle, String newsContent) {
            Intent intent = new Intent(context, NewsContentActivity.class);
            intent.putExtra("news_title", newsTitle);
            intent.putExtra("news_content", newsContent);
            context.startActivity(intent);
        }
    }
    

    这是在小屏手机应用的活动,actionStart是static方法,用于启动活动。onCreate中初始化fragment,使用getSupportFragmentManager获取fragment,再调用refrash。

    创建用于显示新闻列表的布局news_title_frag.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <androidx.recyclerview.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/news_title_recycler_view"/>
    
    </LinearLayout>
    

    还有子项布局news_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/news_title"
        android:maxLines="1"
        android:ellipsize="end"
        android:textSize="18sp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="15dp"
        android:paddingBottom="15dp" />
    

    ellipsize是设定当文本内容超出宽度时,文本缩略方式
    新建NewsTitleFragment类

    public class NewsTitleFragment extends Fragment {
    
        private boolean isTwoPane;
    
        class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
    
            private List<News> mNewsList;
    
            class ViewHolder extends RecyclerView.ViewHolder {
    
                TextView newsTitleText;
    
                public ViewHolder(View view) {
                    super(view);
                    newsTitleText = (TextView) view.findViewById(R.id.news_title);
                }
            }
    
            public NewsAdapter(List<News> newsList) {
                mNewsList = newsList;
            }
    
            @NonNull
            @Override
            public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
                View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.news_item, parent, false);
                final ViewHolder holder = new ViewHolder(view);
                view.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        News news = mNewsList.get(holder.getAdapterPosition());
                        if (isTwoPane) {
                            NewsContentFragment newsContentFragment = (NewsContentFragment)
                                    getFragmentManager().findFragmentById(R.id.news_content_fragment);
                            newsContentFragment.refresh(news.getTitle(), news.getContent());
                        } else {
                            NewsContentActivity.actionStart(getActivity(), news.getTitle(), news.getContent());
                        }
                    }
                });
                return holder;
            }
    
    
            @Override
            public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
                News news = mNewsList.get(position);
                holder.newsTitleText.setText(news.getTitle());
            }
    
            @Override
            public int getItemCount() {
                return mNewsList.size();
            }
        }
    
    
    
        @Nullable
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.news_title_frag, container ,false);
    
            RecyclerView newsTitleRecyclerView = (RecyclerView) view.findViewById(R.id.news_title_recycler_view);
            LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
            newsTitleRecyclerView.setLayoutManager(layoutManager);
            NewsAdapter adapter = new NewsAdapter(getNews());
            newsTitleRecyclerView.setAdapter(adapter);
            return view;
        }
    
        private List<News> getNews() {
            List<News> newsList = new ArrayList<>();
            for (int i = 1; i <= 50; i++) {
                News news = new News();
                news.setTitle("This is news title" + i);
                news.setContent(getRandomLengthContent("This is news content " + i + "."));
                newsList.add(news);
            }
            return newsList;
        }
    
        private String getRandomLengthContent(String content) {
            Random random = new Random();
            int length = random.nextInt(20) + 1;
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < length; i++) {
                builder.append(content);
            }
    
            return builder.toString();
        }
    
    
        @Override
        public void onActivityCreated(@Nullable Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
    
            if (getActivity().findViewById(R.id.news_content_layout) != null) {
                isTwoPane = true;
            } else {
                isTwoPane = false;
            }
        }
    }
    

    修改layout/activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/news_title_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <fragment
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:name="org.nuaa.fragmentbestpractice.NewsTitleFragment"
            android:id="@+id/news_title_fragment"/>
    
    </FrameLayout>
    

    再新建layout_large/activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="horizontal" android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <fragment
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:name="org.nuaa.fragmentbestpractice.NewsTitleFragment"
            android:id="@+id/news_title_fragment"/>
    
        <FrameLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="3"
            android:id="@+id/news_content_layout">
    
            <fragment
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:name="org.nuaa.fragmentbestpractice.NewsContentFragment"
                android:id="@+id/news_content_fragment"/>
    
        </FrameLayout>
    
    </LinearLayout>
    

    在onActivityCreated方法中,使用if(getActivity().findViewById(R.id.news_content.layout) != null)即可判断是双页还是单页

    第五章

    广播机制简介

    Android有一套完整的API,可以自由发送和接收广播
    发送使用Intent,接收使用接收器Broadcast Receiver
    广播有两种类型:标准广播和有序广播

    • 标准广播:完全异步执行,广播发出后,所有接收器几乎会在同一时刻收到,没有先后顺序,无法截断
    • 有序广播:同步执行,广播发出后,同一时间只有一个能接收到,当该广播接收器中的逻辑执行完毕,才会继续传递,有先后顺序,优先级高的先收到,还可以截断

    接收系统广播

    注册的方式有两种:

    • 动态注册:在代码中注册
    • 静态注册:AndroidManifest.xml注册

    动态注册监听网络变化

    广播接收器,继承Broadcast类,并重写onReceive方法,具体接收到广播后的处理逻辑就写在里面

    
    public class MainActivity extends AppCompatActivity {
    
        private IntentFilter intentFilter;
    
        private NetworkChangeReceiver networkChangeReceiver;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            intentFilter = new IntentFilter();
            intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
            networkChangeReceiver = new NetworkChangeReceiver();
            registerReceiver(networkChangeReceiver, intentFilter);
        }
    
        class NetworkChangeReceiver extends BroadcastReceiver {
    
            @Override
            public void onReceive(Context context, Intent intent) {
                Log.d("TAG", "changed");
    
                ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
                Network network = connectivityManager.getActiveNetwork();
                if (network == null) {
                    Toast.makeText(context, "network is unavailable", Toast.LENGTH_LONG).show();
                } else {
                    Toast.makeText(context, "network is available", Toast.LENGTH_LONG).show();
                }
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unregisterReceiver(networkChangeReceiver);
        }
    }
    

    创建NetworkChangeReceiver类
    在onCreate中新建IntentFilter实例,添加一个值android.net.conn.CONNECTIVITY_CHANGE的action,因为当网络状态变化时,会发出这么一个广播,这里注册的意思就是接收这个广播
    registerReceiver(networkChangeReceiver, intentFilter)
    还有在onDestroy方法中取消注册。
    还有获取网络状态需要申请权限,在AndroidManifest.xml文件中添加<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    静态注册开机启动

    动态注册很灵活,但是程序必须启动后才能接收到广播,静态注册可以在未启动就能接受广播
    新建一个BootCompleteReceiver,在AndroidManifest.xml文件中注册,如果是用Android Studio快捷方式新建的类已经注册好了,在Application标签下

            <receiver
                android:name=".BootCompleteReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED"/>
                </intent-filter>
            </receiver>
    

    还需要声明权限<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    这样就可以自启动了

    在广播的onReceive方法中不要写太多的逻辑和耗时的操作,不允许开启线程,运行较长时间没结束会报错
    所以广播的作用大多是创建一条通知栏,开启一个服务等

    发送标准广播

    定义一个接收器MyBroadcastReceiver

    public class MyBroadcastReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_LONG).show();
        }
    }
    

    注册

            <receiver
                android:name=".MyBroadcastReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="org.nuaa.broadcasttest.MY_BROADCAST"/>
                </intent-filter>
            </receiver>
    

    主活动中添加一个按钮,点击发送广播

            Button button = (Button) findViewById(R.id.send);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent("org.nuaa.broadcasttest.MY_BROADCAST");
                    sendBroadcast(intent);
                }
            });
    

    注意,在高版本的Android系统中,静态广播诸多限制,建议改成动态注册广播,或者加上intent.setComponent(new ComponentName("pckname", "receiver path"));,不过这样的话就只能针对一个广播接收器发送了,目前暂不知道解决方案

    发送有序广播

    改成sendOrderBroadcast,并且在静态注册处添加优先级<intent-filer priority="100">
    在接收器代码添加abortBroadcast()可以截断广播

    本地广播

    似乎没有该机制了,暂时不写

    广播实践 -- 强制下线功能

    一个ActivityCollector管理所有活动

    public class ActivityCollector {
    
        public static List<Activity> activities = new ArrayList<>();
    
        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();;
                }
            }
            activities.clear();
        }
    
    }
    

    创建BaseActivity基类作为所有活动的父类

    public class BaseActivity extends AppCompatActivity {
    
        private ForceOfflineReceiver receiver;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            ActivityCollector.addActivity(this);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            ActivityCollector.removeActivity(this);
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction("org.nuaa.broadcasttest2.FORCE_OFFLINE");
            receiver = new ForceOfflineReceiver();
            registerReceiver(receiver, intentFilter);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            if (receiver != null) {
                unregisterReceiver(receiver);
                receiver = null;
            }
        }
    
        class ForceOfflineReceiver extends BroadcastReceiver {
    
            @Override
            public void onReceive(final Context context, Intent intent) {
                AlertDialog.Builder builder = new AlertDialog.Builder(context);
                builder.setTitle("Warning");
                builder.setMessage("You are forced to be offline");
                builder.setCancelable(false);
                builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ActivityCollector.finishAll();
                        Intent intent = new Intent(context, LoginActivity.class);
                        context.startActivity(intent);
                    }
                });
                builder.show();
            }
        }
    }
    

    在基类中创建强制下线广播接收器,onReceive方法中代码逻辑是弹出一个对话框,setCacleable为false即不可取消,OK按钮点击后关闭所有活动,并重新启动登录活动
    新建LoginActivity类,继承BaseActivity

    public class LoginActivity extends BaseActivity {
    
        private EditText accountEdit;
    
        private EditText passwdEdit;
    
        private Button login;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
    
            accountEdit = (EditText) findViewById(R.id.account);
            passwdEdit = (EditText) findViewById(R.id.passwd);
            login = (Button) findViewById(R.id.login);
            login.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    String account = accountEdit.getText().toString();
                    String passwd = passwdEdit.getText().toString();
                    if (account.equals("admin") && passwd.equals("123")) {
                        Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                        startActivity(intent);
                        finish();
                    } else {
                        Toast.makeText(LoginActivity.this, "error", Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    }
    

    界面布局如下

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <LinearLayout
            android:layout_marginLeft="15dp"
            android:layout_marginRight="15dp"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:orientation="horizontal">
    
            <TextView
                android:layout_width="90dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:textSize="18sp"
                android:text="Account:"/>
    
            <EditText
                android:id="@+id/account"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:layout_gravity="center_vertical"/>
    
        </LinearLayout>
    
        <LinearLayout
            android:layout_marginLeft="15dp"
            android:layout_marginRight="15dp"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:orientation="horizontal">
    
            <TextView
                android:layout_width="90dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:textSize="18sp"
                android:text="Password:"/>
    
            <EditText
                android:id="@+id/passwd"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:hint="textPassword"
                android:layout_gravity="center_vertical"/>
    
        </LinearLayout>
    
        <Button
            android:id="@+id/login"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="@string/action_sign_in" />
    
    </LinearLayout>
    

    主界面只有一个按钮,点击强制下线

    public class MainActivity extends BaseActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Button offline = (Button) findViewById(R.id.offline);
            offline.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent("org.nuaa.broadcasttest2.FORCE_OFFLINE");
                    sendBroadcast(intent);
                }
            });
        }
    }
    

    最后把主活动改成LoginActivity

                <intent-filter>
                    <action android:name="android.intent.action.MAIN"/>
                    <category android:name="android.intent.category.LAUNCHER"/>
                </intent-filter>
    
  • 相关阅读:
    Hbase架构与原理(转)
    Hbase的表结构中rowkey的设计---避免热点问题
    mysql之my.cnf详解
    MongoDB CPU利用率很高,怎么破(转)
    数据库设计(2/9):域,约束和默认值(Domains, Constraints and Defaults)
    数据库设计(1/9):数据元(Data Elements)
    SQL Server安全(11/11):审核(Auditing)
    VARCHAR列上的索引
    SQL Server 2016里的sys.dm_exec_input_buffer
    在SQL Server里禁用聚集索引——真的好么?
  • 原文地址:https://www.cnblogs.com/burymyname/p/12321281.html
Copyright © 2020-2023  润新知