android从放弃到坚持放弃第二课(上)

[第二课 探究活动]

[重来]

close projects;

我们这次重新新建一个项目,这次选择Add No Activity,准备手动创建活动。

将项目结构改成project模式。此时app/src/main/java下的。。。activity目录应该就是空的。右键→NEW→Activity→Empty Activity,弹出窗口中,不妨将活动命名为FirstActivity,不要勾选Generate Layout File(自动创建一个对应的布局文件)和Launcher Activity(设置为当前项目的主活动).因为我们第一次应该手写。

项目中的任何活动都应该重写Activity 的onCreate()方法,AS已经自动完成了。

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}

可以看出只是调用了父类的onCreate()方法,后面需要我们添加我们自己的逻辑。

[创建布局文件]

app/src/main/res目录→Directory,创建一个名为layout的目录,接着右键layout→Layout resource file,在弹出的窗口中,将这个布局文件命名为first_layout,根元素默认为LinearLayout

可以发现左下角有Design和Text两个切换卡。

切换到Text,我们发现有一个LinearLayout元素。

我们稍作修改,增加一个子元素Button

<?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"
    android:weightSum="1">

    <Button
        android:id="@+id/button_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button one"
        />

</LinearLayout>

Button 元素中有四个属性。

如果你需要在XML中引用一个id,使用@id/id_name这样的语法,如果想定义一个id,使用@+id/id_name这种语法。

match_parent表示和当前元素和父元素一样宽。wrap_content表示能刚好包含里面的内容就可以。

第一个指定了元素显示的内容。

布局已经写完,现在只要在活动中加载这个布局就可以了。

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_layout);
    }
}

我们增加了一行。

这里调用了setContentView()方法来给当前的活动加载一个布局。调用R.layout.first_layout可以返回first_layout.xml的id,然后传入这个方法里面。

[注册活动]

打开app/src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.wrjjrw.activitytest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".FirstActivity"></activity>
    </application>

</manifest>

发现FirstActivity已经注册过,AS真人性化。

在标签中我们使用的 android:name 来指定具体注册的活动。这里的.FirstActivity其实就是com.example.wrjjrw.FirstAcitivity的缩写(每个人电脑上可能不同)。由于外层的标签中已经通过package属性指定了程序的包名,因此在注册活动时可以省略。

不过,注册了活动也没用,因为还没为程序配置主活动。

所以只要添加标签

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.wrjjrw.activitytest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".FirstActivity"
            android:label="This is huchi's FirstActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

        </activity>
    </application>
</manifest>

android:label 指定 活动标题栏的内容。

给主活动添加的label不仅会成为标题栏的内容,还会成为Launcher(启动器)中应用程序显示的名称。

这样,FirstActivity就成为了我们程序段 主活动,点击图标时首先打开的就是这个活动。

attention:如果你的应用程序中没有声明任何一个活动作为主活动,这个程序可以安装,但无法在Launcher中打开或者看到这个程序。这种程序一般都是作为第三方服务供其它应用在内部进行调用的,如支付宝快捷支付服务。

run

[使用Toast]

Toast 是Android系统提供的一种提醒方式,在程序中可以使用它将一些短小都信息通知给用户,在一段时间后消失,并且不会占占用任何屏幕空间,let’s try.

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.first_layout);

        Button button1 = (Button) findViewById(R.id.button_1);
        button1.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Toast.makeText(FirstActivity.this, "You click me", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

在活动中,通过findViewById()方法获取布局文件中定义的元素,这里我们传入R.id.button1得到这个按钮的实例,之歌值由first_layout.xml中android:id属性指定。findViewById()方法返回的是View对象,我们需要向下转化到Button对象。得到按钮的实例后,通过调用setOnClickListner()方法为按钮注册一个监听器,点击按钮就会执行监听器中的onClick()方法。

Toast用法也很简单,通过静态方法makeText()创建Toast对象,然后调用show()将Toast显示出来。

三个参数:

  1. Context,也就是Toast要求的上下文。活动本身就是一个Context对象。故

  2. 文本内容

  3. 显示时长(两个内置常量:
    1. Toast.LENGTH_SHORT
    2. Toast.LENGTH_LONG)

问题:我没有import android.widget.Button;产生了一些小问题

[使用Menu]

手机屏幕有限,如果你的活动有大量的菜单需要显示,这个时候就可以使用这个。

res→New→Directory新建menu文件夹→New→Menu resource file新建main

编写:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/add_item"
        android:title="Add" />

    <item
        android:id="@+id/remove_item"
        android:title="Remove"/>

    <item
        android:id="@+id/huchi_item"
        android:title="I Love huchi"/>

</menu>

回到FirstActivity重写onCreateOptionsMenu()方法,重写方法可以使用ctrl+o,然后输入那个方法。

编写如下

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

通过getMenuInflater()方法可以得到MenuInflater对象,再调用它的inflate()方法就可以给当前活动创建菜单。两个参数:1.资源文件 2.添加的menu对象。这里直接使用传入的参数。return true 表示允许创建的菜单显示,false则不能。

下面定义菜单响应时间。重写onOptionsItemSelected()方法

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.add_item:
                Toast.makeText(this, "You clicked Add", Toast.LENGTH_SHORT).show();
                break;
            case R.id.remove_item:
                Toast.makeText(this, "You clicked Remove" ,Toast.LENGTH_SHORT).show();
                break;
            case R.id.huchi_item:
                Toast.makeText(this, "I love huchi,too", Toast.LENGTH_LONG).show();
                break;
            default:
        }
        return true;
    }

//hhhhhhh特别好玩

[销毁活动]

我们再增加一个Button

layout

first_layout.xml

    <Button
        android:id="@+id/button_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Finsh"
        />

activity

FirstActivity:

        Button button2 = (Button) findViewById(R.id.button_2);
        button2.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                finish();
            }
        });

点击以后你的程序就关掉了,哈哈哈。

[使用Intent在活动之间穿梭]

[使用显式Intent]

想必你已经十分熟练了(为什么你这么熟练呀)

com.example.wrjjrw.activity→new→Activity→Empty Actiivity;

命名为SecondActivity勾选Generate Activity不要勾选Launcher Activity

更改activity_second.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"
    android:weightSum="1">

    <Button
        android:id="@+id/button_3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button three"
        ></Button>


</LinearLayout>

回到secondActivity,这时已经帮我们修改好了。

同样AndroidManifest中也自动帮我们注册好了。

因为SecondActivity不是主活动,因此不用配置标签里面的内容。

Intent是android程序中个各组件之间进行交互的一种重要方式,它不仅可以指明组件想要执行的动作,还可以在不同组件之间传递数据。

一般用于启动活动,启动服务,发送广播等场景。目光先放在启动活动吧

Intent可以分为显示Intent和隐式Intent。

[先看显示]:

Intent有多个构造函数的重载,Intent(Context packageContext, Class

        Button button2 = (Button) findViewById(R.id.button_2);
        button2.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intentSecond = new Intent(FirstActivity.this, SecondActivity.class);
                startActivity(intentSecond);
            }
        });
    }

构建了一个Intent, 传入本活动作为上文,传入SecondActivity.class。这样我们的“意图”生成了。即在FirstActivity这个活动的基础上打开SecondActivity这个活动。然后通过startActivity()方法来执行这个Intent意图。

这么明显的意图,自然成为显式Intent。

顺带再写个返回的吧:SecondActivity

        Button button3 = (Button) findViewById(R.id.button_3);
        button3.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intentFirst = new Intent(SecondActivity.this, FirstActivity.class);
                startActivity(intentFirst);
            }
        });

老子很想配图,可是配图很麻烦。

[来看看隐式:]

隐式Intent就比较含蓄了,它并不明确指明我们想要启动哪一个活动,而是指定了一系列更为抽象的action和category等信息,然后由系统去分析来分析这个Intent来帮我们找出适合的活动去启动。???

啥适合的活动?:也就是可以响应我们这个隐式Intent的活动,那么SecondActivity可以响应怎么样的隐式Intent呢。马上就有了:

回到AndroidManifest:改一下:blue_heart:

        <activity android:name=".SecondActivity">
            <intent-filter>
                <action android:name="com.example.wrjjrw.activitytest.ACTION_START" />

                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
        </activity>

//包名自己改一下//

在标签中我们指明了当前活动可以响应的action,中则包含了一些附加信息,指明当前活动能够响应的Intent中还可能带有category。只有 和中的内容能够匹配上Intent中指定的action和category时,这个活动才能响应Intent。

回到FirstActivity

        Button button4 = (Button) findViewById(R.id.button_4);
        button4.setOnClickListener(new View.OnClickListener(){
            @Override
            public  void onClick(View v){
                Intent intentSecond = new Intent("com.example.wrjjrw.activitytest.ACTION_START");
                startActivity(intentSecond);
            }
        });

可以测试一下,隐式Intent也成功了。

这里使用了Intent另一个构造器,传入的是action的字符。表明我们想要启动的是。。。这个活动。但是不是说好了要同时匹配的么。因为上面的category是默认的category,在调用startActivity()方法时会自动将这个category添加到Intent中。

每个intent中只能指定一个action,但可以指定多个category。我们再来增加一个category:

        Button button4 = (Button) findViewById(R.id.button_4);
        button4.setOnClickListener(new View.OnClickListener(){
            @Override
            public  void onClick(View v){
                Intent intentSecond = new Intent("com.example.wrjjrw.activitytest.ACTION_START");
                intentSecond.addCategory("com.example.wrjjrw.activitytest.MY_CATEGORY");
                startActivity(intentSecond);
            }
        });

没错,你上当了。程序崩溃了吧。不过问题不大。去logcat上看看错误日志吧。

03-27 06:19:33.852 11380-11380/com.example.wrjjrw.activitytest E/AndroidRuntime: FATAL EXCEPTION: main
                                                                                 Process: com.example.wrjjrw.activitytest, PID: 11380
                                                                                 android.content.ActivityNotFoundException: No Activity found to handle Intent { act=com.example.wrjjrw.activitytest.ACTION_START cat=[com.example.wrjjrw.activitytest.MY_CATEGORY] }
                                                                                     at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1809)
                                                                                     at android.app.Instrumentation.execStartActivity(Instrumentation.java:1523)
                                                                                     at android.app.Activity.startActivityForResult(Activity.java:4224)
                                                                                     at android.support.v4.app.BaseFragmentActivityJB.startActivityForResult(BaseFragmentActivityJB.java:50)
                                                                                     at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:79)
                                                                                     at android.app.Activity.startActivityForResult(Activity.java:4183)
                                                                                     at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:859)
                                                                                     at android.app.Activity.startActivity(Activity.java:4507)
                                                                                     at android.app.Activity.startActivity(Activity.java:4475)
                                                                                     at com.example.wrjjrw.activitytest.FirstActivity$3.onClick(FirstActivity.java:43)
                                                                                     at android.view.View.performClick(View.java:5610)
                                                                                     at android.view.View$PerformClick.run(View.java:22265)
                                                                                     at android.os.Handler.handleCallback(Handler.java:751)
                                                                                     at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                                     at android.os.Looper.loop(Looper.java:154)
                                                                                     at android.app.ActivityThread.main(ActivityThread.java:6077)
                                                                                     at java.lang.reflect.Method.invoke(Native Method)
                                                                                     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
                                                                                     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

可以看到No Activity found to handle Intent { act=com.example.wrjjrw.activitytest.ACTION_START cat=[com.example.wrjjrw.activitytest.MY_CATEGORY] }就是这里出了错。

so why?我们好像忘记去AndroidManifest.xml中去声明这个category了。。。。。。。

        <activity android:name=".SecondActivity">
            <intent-filter>
                <action android:name="com.example.wrjjrw.activitytest.ACTION_START" />
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="com.example.wrjjrw.activitytest.MY_CATEGORY" />
            </intent-filter>
        </activity>

声明完,跑路。

[隐式Intent的其他用法]

你似乎已经知道了隐式Intent的用法,只可惜那只是冰山一角。

隐式Intent不仅可以启动活动中的方法,还可以启动其他程序的活动。因而Android多个应用程序间的功能共享成为了可能。比如说你的应用程序中需要展示一个网页。但你无需自己实现一个浏览器。只需要调用系统的浏览器打开这个网页就ok了

修改button4或者再写一个button5:

        Button button5 = (Button) findViewById(R.id.button_5);
        button5.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intentToBaidu = new Intent(Intent.ACTION_VIEW);
                intentToBaidu.setData(Uri.parse("http://www.baidu.com"));
                startActivity(intentToBaidu);
            }
        });

这里我们传入的action是Intent.ACTION_VIEW,这是android系统内置的动作,其常量值为android.intent.action.VIEW。然后通过Uri.parse()方法将网址解析成Uri对象,再掉用setData()方法。

运行后,我们打开了百度。。。。。。

intentsetData(Uri data)
set the Data this intent is operating on.

//我就顺便贴一下。。。

回到AndroidManifest.xml,我们还可以在标签中再配置一个标签。用于指定当前活动能够响应什么类型的数据。

android:scheme用于指定数据的协议部分,如http部分
android:host用于指定数据的主机名部分,如www.baidu.com
android:port用于指定数据的端口部分,一般紧随在主机名之后
android:path用于指定主机名和端口之后的部分
android:mimeTtye用于指定可以处理的数据类型,允许使用通配符的方式

只有标签中指定的内容和Intent中携带的Data完全一致时,才可以响应Intent.不过一般中不会指定过多的内容。

我们来新建ThirdActivity。

只改一下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"
    android:weightSum="1">

    <Button
        android:id="@+id/button_7"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="return"
        ></Button>


</LinearLayout>

去AndroidManifest.xml改一下

        <activity android:name=".ThirdActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:scheme="http"/>
            </intent-filter>
        </activity>

跑路。

然后点击刚刚的百度的那个,你会惊奇的发现,咦怎么有一个ThirdActivity。点完之后发现到了那个页面。当然百度是没有打开啦。这个活动并不能加载并显示网页。只会误导用户的行为。

除http协议,还有很多其他的协议,比如geo→地理位置,tel→拨打电话。

来ThirdActivity试试拨打电话:

        Button button7 = (Button) findViewById(R.id.button_7);
        button7.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intentTel = new Intent(Intent.ACTION_DIAL);
                intentTel.setData(Uri.parse("tel:10086"));
                startActivity(intentTel);
            }
        });

继续跑路

首先指定了Intent的action是Intent.ACTION_DIAL,这是一个android内置动作。然后data部分指定了协议是tel,号码是10086.。

[向下一个活动传递数据]

启动活动传递数据同样简单,Intent中提供了一系列putExtra()方法的重载,可以把我们想要传递的数据暂时存在Intent中,启动另一个活动后,只需把这些数据再取出来就可以了。

FirstActivity传递字符串:

        Button button2 = (Button) findViewById(R.id.button_2);
        button2.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                String data = "Hello huchi";
                Intent intentString = new Intent(FirstActivity.this, SecondActivity.class);
                intentString.putExtra("extra_data",data);
                startActivity(intentString);
            }
        });

这里用显式Intent启动活动,并通过putExtra()传递字符串。第一个参数是键,第二个参数是值(即真正要传递的数据)。

我们需要将传递的值取出来并答应出来。

SecondActivity:


public class SecondActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        Button button3 = (Button) findViewById(R.id.button_3);
        button3.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intentFirst = new Intent(SecondActivity.this, FirstActivity.class);
                startActivity(intentFirst);
            }
        });

        Intent intent = getIntent();
        String data = intent.getStringExtra("extra_data");
        Log.d("SecondActivity",data);

    }

}

首先通过getIntent()方法获得用于启动SecondActivity,然后调用getString Extra()方法,传入相应的键值,就可以得到传递的数据。这里由于我们传递的是字符串,所以使用getStringExtra()方法来获取,也有getIntExtra()等等之类的方法。

跑路后发现logcat里面有hello huchi.

[返回数据给上一个活动]

返回上一个活动只需按一下

        Button button2 = (Button) findViewById(R.id.button_2);
        button2.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                String data = "Hello huchi";
                Intent intentString = new Intent(FirstActivity.this, SecondActivity.class);
                intentString.putExtra("extra_data",data);
                //startActivity(intentString);
                startActivityForResult(intentString, 1);
            }
        });

activity_second.xml中改一下:

    <Button
        android:id="@+id/button_finish"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="finish"
        ></Button>

SecondActivity中改一下:

        Button buttonFinishSecond = (Button) findViewById(R.id.button_finish);
        buttonFinishSecond.setOnClickListener(new View.OnClickListener(){
            @Override
            public  void onClick(View v){
                Intent intent = new Intent();
                intent.putExtra("data_return","byebye huchi");
                setResult(RESULT_OK, intent);
                finish();
            }
        });

这里吧数据存放在了Intent中,然后调用了setResult()方法,第一个参数用于向上一个活动返回处理结果(RESULT_OK,RESULT_CANCELED),第二个参数则把带有数据的Intent传递回去,然后调用了finish()方法来销毁当前活动。

由于使用了startActivityResult()方法启动的SecondActivity,所以在活动销毁后会返回上一个活动的onActivityResult()方法。因此我们需要重写这个方法来获得返回的数据。

在FirstActivity中ctrl+O输入这个函数名

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode){
            case 1:
                if(resultCode == RESULT_OK){
                    String returnedData = data.getStringExtra("data_return");
                    Log.d("FirstActivity",returnedData);
                }
                break;
            default:
        }
    }

onActivityResult()方法带有三个参数,第一个参数requestCode,即我们在启动活动时传入的请求码。第二个参数resultCode, 即我们在返回数据时传入的处理结果。第三个参数是data,即携带者返回数据的Intent。由于在一个活动中可能调用很多startActivityForResult()方法去启动很多不同的活动,每个活动返回的数据都会回调到onActivityResult()这个方法中,因此我们首先要做的就是通过检查requestCode的值来判断数据来源.然后再通过resultCode的值来判断处理结果是否成功。最后在从中取值打印出来。完成一个活动向上返回数据的工作。

跑路,看看logcat,如果用户在SecondActivity中通过

    @Override
    public void onBackPressed() {
        Intent intent = new Intent();
        intent.putExtra("data_return", "back_to_firstActivity");
        setResult(RESULT_OK, intent);
        finish();
    }

这样的话就ok了。

[问题]:

上下文Context到底是个鬼?

答:Click me

Intent里面的到底是个鬼啊?

答:Click me

容我存个网址:intent

问:Uri是啥,和Url有什么区别。

答:Uri分为Url和Urn,都唯一的标识了资源,但前者还定义了如何获取这个资源。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值