移动终端应用开发上机3组件通信与广播

一、题目:设计一个APP。

1.设计一个APP。
(1)APP中有两个界面。
(2)主界面(MainActiivity)上有“登录”和“广播”两个按钮。点击“登录”按钮,可以打开一个新界面(NewActiivity)。点击“广播”按钮,可以发出广播消息。
(3)新界面(NewActiivity)上可以输入学生姓名、学号、专业班级等信息,另外有“确认”和“取消”两个按钮。当点击“确认”按钮后,可以将学生姓名和学号传递回主界面,并且在主界面上显示传递过来的信息。当点击“取消”按钮后,返回主界面,不带回任何数据信息。
2. 在主界面(MainActiivity)中添加选项菜单,菜单的点击逻辑和按钮的点击逻辑一致(跳转到新界面(NewActiivity))。

二、界面显示

移动终端应用开发上机3组件通信与广播
移动终端应用开发上机3组件通信与广播
移动终端应用开发上机3组件通信与广播

三、主页面详解

本次的代码实现有些复杂,但是好在网上的案例还是很多的,只是脑子转不过来,然后做了一个星期,但是完全做出来之后发现是自己当时智障了。
这个APP的内容可以主要分为三个部分:页面跳转、Intent传送数据、广播。
移动终端应用开发上机3组件通信与广播
如上图所示,我们要创建4个Java文件,主页面MainActivity、子页面1NextActivity、子页面2Ne2Activity和广播接收BroadcastActivity。在这里,只有主页面MainActivity、子页面1NextActivity、子页面2Ne2Activity这三个是会当作页面显示用的,广播接收BroadcastActivity是为了作获取子页面2的数据然后显示弹窗返回的。

在主页面中,我们首先要设置两个静态全局变量作为子页面对主页面的返回标志。

    private static final int SUBACTIVITY1 = 1;
    private static final int SUBACTIVITY2 = 2;

然后建立两个按键的监听器,分别控制“登录”按钮和“广播”按钮,在监听器中写需要传值代码和返回主页面的代码,这里的传值我们用到了向上传值,startActivityForResult()带数据返回主页面。

//假设有一个MainActivity 和 NextActivity ,现在MainActivity启动NextActivity后,我们希望NextActivity给MainActivity传值(这个传值过程就叫向上传值)
Intent intent = new Intent(MainActivity.this, NextActivity.class);//首先在MainActivity里发送数据请求码
startActivityForResult(intent, SUBACTIVITY1);//第二个值是请求码Key

除此之外,我们还要在主页面的代码中写相关代码使子页面的数据成功返回到主页面。这里有两个方法,一个是利用回调函数onActivityResult()实现、另一个是直接在onCreate()函数下实现数据的获取,但这两者的使用都用到Intent(意图),其主要功能是解决 Android 中各项组件之间的通讯 。
方法一:onActivityResult()实现

 /**
     * requestCode和startActivityForResult中的requestCode相对应
     * resultCode和Intent由SubActivity通过其setResult()方法返回
     **/
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        switch(requestCode){
            case SUBACTIVITY1:
                if (resultCode == RESULT_OK){
                    Uri uriData = data.getData();
                    textView.setText(uriData.toString());
                break;
            case SUBACTIVITY2:
                break;
        }
    }

代码含义:当页面收到SUBACTIVITY1这个请求码时,如果子页面中的结果码等等于RESULT_OK,这个时候我们用Uri定义一个uriData,并将子页面中的数据赋值给uriData,再用setText在主页面上显示数据,并用toString()将数据转成String类型;如果请求码为SUBACTIVITY2,就认为是RESULT_CANCELED,此时不带回数据返回主页面。
这里的onActivityResult()函数要继承onActivityResult父类,并需要请求码requestCode、结果码resultCode和数据data这三个参数。
在书上和网上都告诉我们这三个参数的含义,这里我引用一篇博客的文字,链接见文末《Android onActivityResult()的属性与用法》:

这三个参数的含义如下:
requestCode:请求码,用于启动子Activity
resultCode:子Activity设置的结果码,用于指示操作结果。可以是任何整数值,但通常是resultCode = =
RESULT_OK或resultCode==RESULT_CANCELED
Data:用于打包返回数据的Intent,可以包括用于表示所选内容的URI。子Activity也可以在返回数据Intent时,添加一些附加消息。

方法二:onCreate()实现

public class MainActivity extends Activity {
@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = getIntent();
        String name = intent.getStringExtra("editText");
        String num = intent.getStringExtra("editText2");
        String proclass = intent.getStringExtra("editText3");
        textView.setText(String.valueOf(name));
        textView2.setText(String.valueOf(num));
        textView3.setText(String.valueOf(proclass));
    }
}

在方法二中,我们直接用getIntent()来获取数据,并将获取到的数据返回到我们定义的Intent中,接着用到getStringExtra获得同意工程下其他Java文件的数据,这里引号内的内容是我们要获取其数据的键名。
后面的String.valueOf()的意思是将name(num 、proclass)里的内容转成String类。
个人感觉跟第一种toString()方法相比,String.valueOf()像是一个间接寻址的过程。

四、子页面1详解

从题目可以看出,我们要从子页面1中输入学生的姓名、学号和专业班级,这说明要用到EditText控件,读取和撤销则要用到Button按钮。
移动终端应用开发上机3组件通信与广播
关于子页面1的Java文件,button照常是要用到监听器去监听的。因为读取的按钮负责要把我们输入的数据传回到主页面去,所以要在读取的按钮监听器中添加Intent()方法,然后放数据进intent里。
在这里我们要用到putExtra(name,value)把数据放进去。
这里的putExtra相当于可以把数据放在可以发送到别的Java文件中的函数,如果只有put的话,说明就只能在当前的Java文件下get(获取)我们存入的数据。name是键名,相当于一个“暗号”,当我们在别的Java文件下输入这个键名,就可以跟这里的内容“对上暗号”,value是键值,用来存放我们输入的数据,当我们从别的Java文件中对上暗号,就可以传送键值中的数据。
子页面1局部Java代码如下(注意:这里的代码对应上面主页面详解的方法二):

 btnSign.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                String uriString = editText.getText().toString();
                String uriString2 = editText2.getText().toString();
                String uriString3 = editText3.getText().toString();
                Intent intent = new Intent();
                intent.putExtra("editText",uriString);
                intent.putExtra("editText2",uriString2);
				intent.putExtra("editText3",uriString3);
				intent.setClass(SubActivity1.this,MainActivity.class);
                startActivity(intent);
            }
        });

那么对应主页面方法一的代码怎么写呢?
代码如下所示,下面的代码我们定义了一个Uri类型去存放我们的数据,利用parse方法访问我们的本地资源,这里的资源名字定义为uriString。

btnSign.setOnClickListener(new View.OnClickListener(){
        public void onClick(View view){
                String uriString = editText.getText().toString()+"   "+editText2.getText().toString()+"   "+editText3.getText().toString();
                //parse方法返回的是一个Uri类型,通过这个Uri可以访问一个网络上或者是本地的资源
                Uri data = Uri.parse(uriString);
                Intent result = new Intent(null, data);
                setResult(RESULT_OK, result);//第一个参数是系统的KEY ,判断传值是否成功
                finish();
            }
        });

这两个方法到最后的输出显示有什么区别呢?
如下图:

移动终端应用开发上机3组件通信与广播
↑ ↑ ↑这是用putExtra方法传送数据的页面显示。

移动终端应用开发上机3组件通信与广播
↑ ↑ ↑这是用parse方法传送数据的页面显示。
可以看出来,我们可以用①去分别返回我们我们的三个数据;而②则是用下面这行代码去把我们的三个数据连起来存放到一个data中,这样输出其实是一个data,但是我们可以用空格来将它们分开,让我们看起来的时候变成了三个数据(就是说我们看上去是三个数据,但在代码中它其实只是一个数据)。

String uriString = editText.getText().toString()+"   "+editText2.getText().toString()+"   "+editText3.getText().toString();

当我们不想要传回任何数据要主页时,我们则点击撤销按钮。
撤销的按钮不带回任何数据,所以我们在监听器里写上RESULT_CANCELED结果码就好了,返回的是空值(null)。

        btnRe.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                setResult(RESULT_CANCELED, null);
                finish();
            }
        });

五、 子页面2详解

子页面2用到了广播去发送数据,在这里,我们需要创建两个Java文件,一个是用来发送广播,一个是用来接收广播。
我们一般用Intent发送广播消息,广播消息的内容可以是应用程序密切相关的数据信息,也可以是Android的系统信息,当应用程序注册了BroadcastReceiver,则可以接收指定的广播消息。
在我所学的教材中有这么一段话:

使用Intent发送广播消息非常简单,只需创建一个Intent,并调用sendBroadcast()函数就可把Intent携带的信息广播出去。但需要注意的是,在构造Intent时必须定义一个全局唯一的字符串,用来标识其要执行的动作,通常使用应用程序包的名称。如果要在Intent传递额外数据,可以用Intent的putExtra()方法。

如教材中所述,我们需要在按键的监听器中定义一个全局唯一的字符串,用来标识其要执行的动作,并用到putExtra发送数据。
代码如下:

btnbro.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                Intent intent = new Intent("com.mwt.mwtclass3rd");
                intent.putExtra("showmess",ent2.getText().toString());
                sendBroadcast(intent);
            }
        });

而在接收广播消息时,我们则需要继承BroadcastReceiver类,并重载onReceive()方法。
在这次的APP中,返回的广播用到浮窗来显示。
广播接收的代码:

public class BroActivity extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent)
    {
        //TODO Auto-generated method stub
        String msg=intent.getStringExtra("showmess");
        Toast.makeText(context,msg,Toast.LENGTH_LONG).show();
    }
}

广播消息这就结束了吗?不然,我们还要在AndroidMani.xml文件中注册一个BroadcastReceiver,否则我们是收不到我们要发送的消息的。
这里的广播注册用到了<intent-filter>去注册静态广播,也有动态广播,感兴趣的可以去找找动态广播的使用案例。
但是,用到静态广播的话,我们必须要在Android8.0以下的系统去运行,因为自Android8.0开始,谷歌为了提高用户的系统性能,取消了大部分的静态广播功能。

        <receiver
            android:name=".BroActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="com.mwt.mwtclass3rd"/>
            </intent-filter>
        </receiver>

同时,我们还要在该文件下的manifest控件中写入<uses-sdk android:maxSdkVersion="14"/>。在这里,uses-sdk是用来设置APP对Android系统的兼容性的,这里的14则能够保证我们的APP能在所有Android系统内100%兼容。

六、Java代码

主页面Java代码1

package com.mwt.testmaxing;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.net.DatagramPacket;

public class MainActivity extends Activity {
    private static final int SUBACTIVITY1 = 1;
    private static final int SUBACTIVITY2 = 2;

    TextView textView,textView2,textView3;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView)findViewById(R.id.label1);
        textView2 = (TextView) findViewById(R.id.label2);
        textView3 = (TextView) findViewById(R.id.label3);
        final Button btn1 = (Button)findViewById(R.id.btn1);
        final Button btn2 = (Button)findViewById(R.id.btn2);

        btn1.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                //假设有一个MainActivity 和 NextActivity ,现在MainActivity启动NextActivity后,我们希望NextActivity给MainActivity传值(这个传值过程就叫向上传值)
                //首先在MainActivity里发送数据请求码
                Intent intent = new Intent(MainActivity.this, NextActivity.class);
                startActivityForResult(intent, SUBACTIVITY1https://blog.csdn.net/kiro_1023?spm=1001.2101.3001.5343);//第二个值是请求码Key
            }
        });

        btn2.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                Intent intent = new Intent(MainActivity.this, Ne2Activity.class);
                startActivityForResult(intent, SUBACTIVITY2);
            }
        });

    }
    /**
     * requestCode和startActivityForResult中的requestCode相对应
     * resultCode和Intent由SubActivity通过其setResult()方法返回
     **/
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        switch(requestCode){
            case SUBACTIVITY1:
                if (resultCode == RESULT_OK){
                    Uri uriData = data.getData();
                    textView.setText(uriData.toString(https://blog.csdn.net/kiro_1023?spm=1001.2101.3001.5343));
                }
                break;
            case SUBACTIVITY2:
                break;
        }
    }
}

子页面Java代码1

package com.mwt.testmaxing;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class NextActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_next);https://blog.csdn.net/kiro_1023?spm=1001.2101.3001.5343
        final EditText editText = (EditText)findViewById(R.id.entry1);
        final EditText editText2 = (EditText)findViewById(R.id.entry2);
        final EditText editText3 = (EditText)findViewById(R.id.entry3);
        Button btnSign = (Button)findViewById(R.id.get);
        Button btnRe = (Button)findViewById(R.id.cancel);

        btnSign.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                String uriString = editText.getText().toString()+"   "+editText2.getText().toString()+"   "+editText3.getText().https://blog.csdn.net/kiro_1023?spm=1001.2101.3001.5343toString();
                //parse方法返回的是一个Uri类型,通过这个Uri可以访问一个网络上或者是本地的资源
                Uri data = Uri.parse(uriString);
                Intent result = new Intent(null, data);https://blog.csdn.net/kiro_1023?spm=1001.2101.3001.5343
                setResult(RESULT_OK, result);//第一个参数是系统的KEY ,判断传值是否成功
                finish();
            }
        });
        btnRe.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                setResult(RESULT_CANCELED, null);
                finish();
            }
        });
    }
}

主页面Java代码2

package com.mwt.mwtclass3rd;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;


public class MainActivity extends Activity {
    private static final int SUBACTIVITY1 = 1;
    private static final int SUBACTIVITY2 = 2;

    TextView textView,textView2,textView3;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView)findViewById(R.id.label1);
        textView2 = (TextView) findViewById(R.id.label2);
        textView3= (TextView) findViewById(R.id.label3);

        final Button btn1 = (Button)findViewById(R.id.btn1);
        final Button btn2 = (Button)findViewById(R.id.btn2);

        Intent intent = getIntent();
        String name = intent.getStringExtra("editText");
        String num = intent.getStringExtra("editText2");
        String proclass = intent.getStringExtra("editText3");
        textView.setText(String.valueOf(name));
        textView2.setText(String.valueOf(num));
        textView3.setText(String.valueOf(proclass));

        btn1.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                //向上传值
                Intent intent = new Intent(MainActivity.this, SubActivity1.class);https://blog.csdn.net/kiro_1023?spm=1001.2101.3001.5343
                //页面跳转
                startActivityForResult(intent, SUBACTIVITY1);
            }
        });

        btn2.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                Intent intent = new Intent(MainActivity.this, SubActivity2.https://blog.csdn.net/kiro_1023?spm=1001.2101.3001.5343class);

                startActivityForResult(intent, SUBACTIVITY2);
            }
        });
	}
    }

子页面1Java代码2

package com.mwt.mwtclass3rd;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class SubActivity1 extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sub1);
        final EditText editText = (EditText)findViewById(R.id.entry1);
        final EditText editText2 = (EditText)findViewById(R.id.entry2);
        final EditText editText3 = (EditText)findViewById(R.id.entry3);
        Button btnSign = (Button)findViewById(R.id.get);
        Button btnRe = (Button)findViewById(R.id.cancel);
        btnSign.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                String uriString = editText.getText().toString();
                String uriString2 = editText2.getText().toString();
                String uriString3 = editText3.getText().toString();
                Intent intent = new Intent();
                intent.putExtra("editText",uriString);
                intent.putExtra("editText2",uriString2);
                intent.putExtra("editText3",uriString3);
                intent.setClass(SubActivity1.this,MainActivityhttps://blog.csdn.net/kiro_1023?spm=1001.2101.3001.5343.class);
                startActivity(intent);
            }
        });

        btnRe.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                setResult(RESULT_CANCELED, null);
                finish();
            }
        });
    }
}

子页面2代码

package com.mwt.mwtclass3rd;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class SubActivity2 extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sub2);
        Button btnbro = (Button)findViewById(R.id.btn_Bro);
        EditText ent2 = (EditText) findViewById(R.id.writemes);
        Button btnReturn = (Button)findViewById(R.id.btn_return);

        btnbro.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                Intent intent = new Intent("com.mwt.mwtclass3rd");
                intent.putExtra("showmess",ent2.getText().toString()https://blog.csdn.net/kiro_1023?spm=1001.2101.3001.5343);
                sendBroadcast(intent);
            }
        });
        btnReturn.setOnClickListener(new View.OnClickListener(){
            public void onClick(View view){
                setResult(RESULT_CANCELED, null);
                finish();
            }
        });
    }
}

广播接收页面Java代码

package com.mwt.mwtclass3rd;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class BroActivity extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent)
    {
        //TODO Auto-generated method stub
        String msg=intent.https://blog.csdn.net/kiro_1023?spm=1001.2101.3001.5343getStringExtra("showmess");
        Toast.makeText(context,msg,Toast.LENGTH_LONG).show();
    }
}

七、演示

移动终端应用开发上机3组件通信与广播

移动终端应用开发上机3组件通信与广播
移动终端应用开发上机3组件通信与广播
移动终端应用开发上机3组件通信与广播

八、流水账

这次的上机课难度确实上来了,当时一直卡在子页面1的数据回传功能这块上,老师给的是书上的代码,也就是用请求码、结果码和数据来返回我们输入的数据,而网上大多是直接重载onCreate()来getIntent()我们的数据,个人感觉后者比较好用。
当时首先是被BroadcastReceiver卡了一下,怎么也收不到发出去的广播,后面查了相关资料才知道谷歌为了提高用户的系统性能,自Android8.0开始,取消了大部分的静态广播功能,而课上讲的刚好是要用静态广播去发送广播的,为了节省时间,我也没有去学习动态广播的使用方法,而是直接将模拟器中最开始的Android11.0系统设置为Android5.0系统。然后便是漫长地找为什么子页面1不能传回多个数据到主页面上的解决方法。
后来终于解决了这个问题:因为我一开始是直接抄老师课堂上讲的代码用的是onActivityResult方法,但是网上是直接用getIntent方法的,本来想要把网上的方法直接放到onActivityResult里面去,但是不行,问了老师后老师让我用putExtra方法和getExtra,但是用了它后无论输入数据主页面都只能返回“null”,就这样null了一天,我又去问了老师,老师说我代码没错,按道理来说不应该会只返回“null”,无奈之下让我把三个数据放到一个data里面。我也试了,但是返回的数据会连起来,不太好看,我把这件事情告诉了班上的同学,同学给我示范了一下——他把连起来的数据之间加了个+“ ”+,这样输出确实好看点了,但我还是觉得怪怪的。
昨晚无聊继续看网上的方法,直接把抄老师的代码删掉,再写一遍,就好了… …
挺难过的,因为这八天来我像个弱智。

参考

android studio将一个页面信息传送到另一个页面并显示
Android四大组件——BroadcastReceiver(原理篇)
Android 8.0新特性-取消大部分静态注册广播
Android 8.0 行为变更
Android BroadcastReceiver:接收广播
配置 Android Studio
Android onActivityResult()的属性与用法
Android数据存储之SharedPreferences
android 开发 Intent使用技巧点
【Android开发】intent.putExtra()方法参数详解及示例

上一篇:Android 多线程-IntentService详解


下一篇:Android APP开机自启动