美文网首页
Android中的Activity

Android中的Activity

作者: sunhaiyu | 来源:发表于2017-05-07 16:19 被阅读131次

    Android四大组件

    • 活动(Activity)
    • 广播接收者(BroadCastReceiver)
    • 服务(Service)
    • 内容提供者(Contentprovider)

    Activity

    先来看AndroidManifest.xml文件,新建工程后默认是下面的样子。

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.activitytest">
    <!--  android:icon应用程序的图标,android:label应用程序的名称 -->
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    

    application 标签表示整个应用,可以看到里面有这么几行

    <activity android:name=".MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    

    每一个Activity都需要在里面注册,<activity android:name=".MainActivity"></activity>必须是完整路径,因为package属性已经指定过包名了,这里用.表示包名就行了。<intent-filter>标签可选。里面的action指定为MAIN,同时category指定为LAUNCHER,该注册的活动作为应用程序进入后,显示的第一个Activity

    android.intent.action.MAIN与android.intent.category.LAUNCHER

    如果存在多个activity都声明了android.intent.action.MAIN与android.intent.category.LAUNCHER会出现什么情况呢?将会有多个图标显示在桌面上。

    如果这两个属性只指定一个呢?

    • 第一种情况:有MAIN,无LAUNCHER,程序列表中无图标。原因:android.intent.category.LAUNCHER决定应用程序是否显示在程序列表里
    • 第二种情况:无MAIN,有LAUNCHER,程序列表中无图标。原因:android.intent.action.MAIN决定应用程序最先启动的Activity,如果没有Main,则不知启动哪个Activity,故也不会有图标出现

    android.intent.action.MAIN与android.intent.category.LAUNCHER必须同时指定才有意义。而且一般只有一个活动需要注册为默认启动。(没有应用是有两个图标可进入同一个应用的)*

    Intent

    隐式Intent

    通过指定一组action、data、category等

    我想启动另外一个Activity,在这个Activity中进行了如下设置

    <activity android:name=".Main2Activity">
      <intent-filter>
        <action android:name="com.example.activitytest.ACTION_START"/>
         <action android:name="com.example.activitytest.ACTION_XXX"/>
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.MY_CATEGORY" />
        <data android:mimeType="aa/bb" />
        <data android:scheme="https" />
      </intent-filter>
    </activity>
    

    可以看到我们自定义了action、category、和data。我们需要匹配以上属性,才能启动这个Activity。注意,action和category可以指定多个,与其中任意一个匹配就可以。但data则不是匹配一个就行。比如上面匹配了上面的mimeType也是不能启动活动的。

    另外,一个活动想要被隐式启动,必须加上<category android:name="android.intent.category.DEFAULT" />, 除了第一个被启动的活动指定为LAUNCHER,若是不加这句,即使匹配了其他所有category,也不会被启动。intent.addCategory这句只要匹配任何一个category就行,如果不指定category,在startActivity时默认使用android.intent.category.DEFAULT

    在MainActivity中,写如下代码

    // intent.setAction("com.example.activitytest.ACTION_START");
    // 下面这句相当于上面那句,匹配了action
    Intent intent = new Intent("com.example.activitytest.ACTION_START");
    // setData和setType会清除另外一个设置的内容,要想同时设置这俩,使用setDataAndType
    //        intent.setData(Uri.parse("https:" + "Www.baidu.com"));
    //        intent.setType("aa/bb");
    // 匹配了data里面的scheme和mimeType
    intent.setDataAndType(Uri.parse("https:" + "Www.baidu.com"), "aa/bb");
    // 匹配了category,至此xml配置的所有都匹配完成。才可以启动活动,不然会报错
    intent.addCategory("android.intent.category.MY_CATEGORY"); // 如果不指定category也是可以的,startActivity时候默认传入android.intent.category.DEFAULT
    startActivity(intent);
    

    如果一个活动配置了多个<intent-filter>呢?那么只需匹配成功任意一个intent-filter里面的全部属性就可以了

    显式Intent

    通过指定packageContext和类名.class,一般是当前的Activity和类名.class

    显式Intent比较便捷,xml只需配置<activity android:name=".Main2Activity"></activity>

    // 这句相当于下面的setClass
    Intent intent = new Intent(MainActivity.this, Main2Activity.class);
    startActivity(intent);
    

    这样就可以启动新的Activity。

    显式和隐式Intent区别

    • 显示意图更加安全一些,因为不能直接通过action、category、data等访问到。(压根没指定) ,只能通过上下文来使用。所以一般用来开启自己应用的界面。
    • 隐式意图一般开启系统应用(电话拨号器 短信的发送器等等)的界面,用于应用和应用之间。

    一个Intent小例子

    输入姓名选择性别,分析今日运势。

    主布局,这里选择性别用到了单选框。RadioButton的使用必须搭配着RadioGroup才能实现一个组只能选中一个。想指定某一项默认选中时,那个子项必须填写id属性,才能实现互斥,不然会造成多个单选框被选中。一般说来,每个子项都应该设置id

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.example.radiogrouptest.MainActivity"
        android:layout_margin="16dp">
    
        <EditText
            android:id="@+id/et_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入您的姓名" />
    
        <RadioGroup
            android:orientation="horizontal"
            android:id="@+id/rg_gender"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            >
            <!-- 要实现事先就默认选中一个,该单选框必须有id属性。一般可以将所有RadioButton都设置id -->
            <!-- 多个单选框如果同时指定了id,且设置了checked为true,虽然多个单选框设置默认选中,但他们是互斥的,只以最后一个设置了true的单选框为默认选中 -->
            <!-- 关键就是,一定要设置id -->
            <RadioButton
                android:id="@+id/rb_male"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="男"
                android:checked="true"
                />
    
            <RadioButton
                android:id="@+id/rb_female"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="女"
                android:checked="true"
    
                />
        </RadioGroup>
    
        <Button
            android:id="@+id/bt_guess"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="点我查看今日运势"/>
    
    </LinearLayout>
    
    

    MainActivity

    package com.example.radiogrouptest;
    
    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.text.TextUtils;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.RadioGroup;
    import android.widget.Toast;
    
    public class MainActivity extends AppCompatActivity {
       private EditText editText;
       private RadioGroup radioGroup;
       private Context mContext;
    
       @Override
       protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.activity_main);
           mContext = this;
    
           editText = (EditText) findViewById(R.id.et_name);
           radioGroup = (RadioGroup) findViewById(R.id.rg_gender);
           Button btGuess = (Button) findViewById(R.id.bt_guess);
    
           btGuess.setOnClickListener(new View.OnClickListener() {
               @Override
               public void onClick(View v) {
                   // 获得输入的名字
                   String name = editText.getText().toString().trim();
                   if (TextUtils.isEmpty(name)) {
                       Toast.makeText(mContext, "您还没有输入名字", Toast.LENGTH_SHORT).show();
                       // 用户输入了名字才进行下面的处理
                   } else {
                       // 得到被选中的哪个单选框的id,默认选中“男”
                       int sexId = radioGroup.getCheckedRadioButtonId();
                       String sex;
                       switch (sexId) {
                           case R.id.rb_male:
                               sex = "男";
                               break;
                           case R.id.rb_female:
                               sex = "女";
                               break;
                           default:
                               sex = "NONE";
                       }
    
                       Intent intent = new Intent(mContext, Main2Activity.class);
                       // 向下一个活动传递数据
                       intent.putExtra("name", name);
                       intent.putExtra("gender", sex);
                       startActivity(intent);
                   }
               }
           });
       }
    }
    
    

    另外一个Activity的界面,很简单,都是TextView

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.radiogrouptest.Main2Activity"
        android:layout_margin="16dp">
    
        <TextView
            android:id="@+id/tv_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/tv_gender"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/tv_guess"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
    
    

    另外一个Activity

    package com.example.radiogrouptest;
    
    import android.content.Intent;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.TextView;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    
    public class Main2Activity extends AppCompatActivity {
    
        private List<String> guessList = new ArrayList<>();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main2);
            TextView tvName = (TextView) findViewById(R.id.tv_name);
            TextView tvGender = (TextView) findViewById(R.id.tv_gender);
            TextView tvGuess = (TextView) findViewById(R.id.tv_guess);
    
            initList();
            Random random = new Random();
            // 生成[0, 4),不含4。随机选取一个。
            int index = random.nextInt(4);
            String randomOne = guessList.get(index);
    
            Intent intent = getIntent();
            String name = intent.getStringExtra("name");
            String sex = intent.getStringExtra("gender");
            tvName.setText(name);
            tvGender.setText(sex);
            tvGuess.setText(randomOne);
        }
    
        private void initList() {
            guessList.add("你今天给心爱的女生表白会成功");
            guessList.add("你今天和基友们待在一起会更好");
            guessList.add("你今天最好不要出门");
            guessList.add("你今天外出会有好运");
        }
    }
    

    Intent--向下一个活动传递数据

    用ListView展示一些备用的短信文本,点击则跳转到短信界面,内容已经填充在sms的body里面了。

    先看主布局,就一个listview

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.sendmessagetest.MainActivity">
    
        <ListView
            android:id="@+id/lv_sms"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </ListView>
    
    </LinearLayout>
    
    

    再看子项布局,只有一个textview用于显示短信文本

    <?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"
        >
    
        <TextView
            android:id="@+id/sms_item"
            android:textSize="20sp"
            android:textColor="#000"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
    

    写个Bean封装短信数据

    package com.example.sendmessagetest.bean;
    
    
    public class MySms {
        public String message;
    
        public MySms(String message) {
            this.message = message;
        }
    }
    
    

    再来看适配器,使用了ArrayAdapter,因为构造方法中传入了List所以也不用重写getCount()方法了。

    package com.example.sendmessagetest.adapter;
    
    
    import android.content.Context;
    import android.support.annotation.LayoutRes;
    import android.support.annotation.NonNull;
    import android.support.annotation.Nullable;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.TextView;
    
    import com.example.sendmessagetest.R;
    import com.example.sendmessagetest.bean.MySms;
    
    import java.util.List;
    
    
    public class SmsArrayAdapter extends ArrayAdapter<MySms> {
    
        private int resourceId;
    
        public SmsArrayAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull List<MySms> objects) {
            super(context, resource, objects);
            resourceId = resource;
        }
    
        @NonNull
        @Override
        public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
            MySms sms = getItem(position);
            View view;
            if(convertView != null){//判断converView是否为空,不为空重新使用
                view = convertView;
            }else{
                view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
            }
    
            TextView textView = (TextView) view.findViewById(R.id.sms_item);
            textView.setText(sms.message);
    
            return view;
        }
    }
    

    最后来看MainActivity

    package com.example.sendmessagetest;
    
    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.ListView;
    
    import com.example.sendmessagetest.adapter.SmsArrayAdapter;
    import com.example.sendmessagetest.bean.MySms;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity {
    
        private Context mContext;
        private List<MySms> smsList = new ArrayList<>();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mContext = this;
            // 添加短信数据
            initSms();
            ListView listView = (ListView) findViewById(R.id.lv_sms);
            SmsArrayAdapter arrayAdapter = new SmsArrayAdapter(mContext, R.layout.item, smsList);
            listView.setAdapter(arrayAdapter);
            // 设置子项点击事件,跳转到短信发送界面
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    MySms sms = smsList.get(position);
    
                    /* 过滤器的属性,分别匹配成功就好
                    <intent-filter>
                       <action android:name="android.intent.action.SEND" />
                       <category android:name="android.intent.category.DEFAULT" />
                       <data android:mimeType="text/plain" />
                   </intent-filter>
                   */
                    Intent intent = new Intent("android.intent.action.SEND");
                    intent.addCategory("android.intent.category.DEFAULT");
                    intent.setType("text/plain");
                    // 源码里面写了getStringExtra("sms_body"),填充到短信内容主体
                    intent.putExtra("sms_body", sms.message);
                    startActivity(intent);
                }
            });
        }
    
        private void initSms() {
            for (int i = 0; i < 10; i++) {
                MySms sms1 = new MySms("走出去玩!");
                smsList.add(sms1);
    
                MySms sms2 = new MySms("吃饭了没,今晚吃什么?");
                smsList.add(sms2);
    
                MySms sms3 = new MySms("这周去旅行吧.");
                smsList.add(sms3);
    
                MySms sms4 = new MySms("我过去找你,开始准备饭菜吧。");
                smsList.add(sms4);
            }
        }
    }
    
    

    点击任意一个

    弹出分享界面,不清楚为何会弹出分享界面然后手动选择。选择其他都不能获取到资源,这里只能选择短信,因为intent-filter里写死了。就是不明白为何多此一举,不直接进入短信界面。跟着教程写的,教程是Android4.x。测试的真机是小米5S。

    上面的界面,选择短信。进来了,可以看到。内容确实是传给了sms_body的。

    Intent--向上一个活动传递数据

    写一个自定义短信发送的功能。

    可以从联系人中选择号码,可以选择短信模板。点击发送就会发送短信。

    主布局

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="16dp"
        tools:context="com.example.smssenddemo.MainActivity">
    
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <EditText
                android:id="@+id/et_contact"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:hint="输入手机号"/>
            <Button
                android:id="@+id/bt_select"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="添加"/>
        </LinearLayout>
    
        <EditText
            android:id="@+id/et_sms"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:gravity="top|start"
            android:hint="在这里输入你的短信内容" />
    
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <Button
                android:id="@+id/bt_add"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="选择短信模板" />
            <Button
                android:id="@+id/bt_send"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:text="发送"/>
        </RelativeLayout>
    
    </LinearLayout>
    
    

    点击添加按钮,就可跳转到联系人界面

    联系人布局,这里简化为一个包含姓名和号码的listview。

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.smssenddemo.ContactActivity">
        <ListView
            android:id="@+id/lv_contact"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </ListView>
    </LinearLayout>
    

    新建bean封装联系人信息。

    package com.example.smssenddemo.bean;
    
    
    public class MyContact {
    
        public String name;
        public String phone;
    
        public MyContact(String name, String phone) {
            this.name = name;
            this.phone = phone;
        }
    }
    
    

    然后是联系人的子项布局

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:id="@+id/tv_name"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textSize="20sp"
            android:textColor="#000"
            android:layout_weight="1"/>
        <TextView
            android:id="@+id/tv_phone"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textSize="20sp"
            android:textColor="#000"
            android:layout_weight="1"/>
    
    </LinearLayout>
    

    联系人listview的适配器

    package com.example.smssenddemo.adapter;
    
    
    import android.content.Context;
    import android.support.annotation.LayoutRes;
    import android.support.annotation.NonNull;
    import android.support.annotation.Nullable;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.TextView;
    
    import com.example.smssenddemo.R;
    import com.example.smssenddemo.bean.MyContact;
    
    import java.util.List;
    
    public class MyArrayAdapter extends ArrayAdapter<MyContact> {
    
        private int resourceId;
    
        public MyArrayAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull List<MyContact> objects) {
            super(context, resource, objects);
            resourceId = resource;
        }
    
        @NonNull
        @Override
        public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
            View view;
            if (convertView != null) {
                view = convertView;
            } else {
                view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
            }
    
            TextView tvName = (TextView) view.findViewById(R.id.tv_name);
            TextView tvPhone = (TextView) view.findViewById(R.id.tv_phone);
    
            MyContact contact = getItem(position);
            tvName.setText(contact.name);
            tvPhone.setText(contact.phone);
    
            return view;
        }
    }
    
    

    看下联系人Activity,点击了某一项就会销毁活动。返回数据给MainActivity

    package com.example.smssenddemo;
    
    import android.content.Context;
    import android.content.Intent;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.ListView;
    
    import com.example.smssenddemo.adapter.MyArrayAdapter;
    import com.example.smssenddemo.bean.MyContact;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class ContactActivity extends AppCompatActivity {
    
        private List<MyContact> contactList = new ArrayList<>();
        private Context mContext;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_contact);
            mContext = this;
            // 初始化联系人数据
            initContacts();
            ListView listView = (ListView) findViewById(R.id.lv_contact);
            MyArrayAdapter adapter = new MyArrayAdapter(mContext, R.layout.item, contactList);
            listView.setAdapter(adapter);
            // 子项点击,点击后finish,将被点击子项的数据传给上一个活动
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    MyContact contact = contactList.get(position);
                    Intent intent = new Intent();
                    // 只需发送号码就行
                    intent.putExtra("phone", contact.phone);
                    setResult(RESULT_OK, intent);
                    // 传递过去后,销毁该活动
                    finish();
                }
            });
    
        }
    
        private void initContacts() {
            for (int i = 0; i < 30; i++) {
                MyContact contact = new MyContact("小明"+i, "139901234"+i);
                contactList.add(contact);
            }
        }
    }
    
    

    接着写短信模板的Activity,还是使用ListView和ArrayAdapter,由于子项布局很简单,只有一个TextView,所以这里也不用继承了,直接使用已有的ArrayAdapter的构造方法。可以传入一个TextView的资源id,以及一个List对象,list对象里面的所有内容会显示到指定的TextView上。注意,该构造方法是适用于仅仅有一个TextView的情况。这个例子刚好符合

    ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext, R.layout.sms_item, R.id.tv_sms_body, smsList);
    
    

    SmsBodyActivity

    package com.example.smssenddemo;
    
    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.ArrayAdapter;
    import android.widget.ListView;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class SmsBodyActivity extends AppCompatActivity {
    
        private Context mContext;
        private List<String> smsList = new ArrayList<>();
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_sms_body);
            mContext = this;
            
            initSms();
            ListView listView = (ListView) findViewById(R.id.lv_sms_body);
    
            // 不指定textViewId则将整个子项布局(虽然是LinearLayout)转型为TextView,由于这里LinearLayout里只有一个TextView。可以这样写
    //        ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext, R.layout.sms_item, smsList);
            // 如果子项布局控件很多,不止有一个TextView或者还有其他控件。就需要指定将List里的内容设置到哪个TextView里面了。这个构造方法只适用于只有一个TextView的简单情况
            ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext, R.layout.sms_item, R.id.tv_sms_body, smsList);
            listView.setAdapter(adapter);
    
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    String smsBody = smsList.get(position);
                    Intent intent = new Intent();
                    intent.putExtra("sms_body", smsBody);
                    setResult(RESULT_OK, intent);
                    // 传递过去后,销毁该活动
                    finish();
                }
            });
        }
    
        private void initSms() {
            for (int i = 0; i < 15; i++) {
                smsList.add("我在开会,请稍后联系"+i);
                smsList.add("我在吃饭,请稍后联系"+i);
                smsList.add("我在忙,请稍后联系"+i);
                smsList.add("我在工作,请稍后联系"+i);
            }
        }
    }
    
    

    最后来看MainActivity,由于在Android6.0后发送短信也需要申请运行时权限。所以在一进应用就申请权限。

    package com.example.smssenddemo;
    
    import android.Manifest;
    import android.content.Context;
    import android.content.Intent;
    import android.content.pm.PackageManager;
    import android.support.annotation.NonNull;
    import android.support.v4.app.ActivityCompat;
    import android.support.v4.content.ContextCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.telephony.SmsManager;
    import android.telephony.SmsMessage;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    
        private EditText etName;
        private EditText etSmsBody;
        private Context mContext;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mContext = this;
    
            if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.SEND_SMS}, 1);
            }
    
            etName = (EditText) findViewById(R.id.et_contact);
            etSmsBody = (EditText) findViewById(R.id.et_sms);
            Button btSelectContact = (Button) findViewById(R.id.bt_select);
            Button btSend = (Button) findViewById(R.id.bt_send);
            Button btAdd = (Button) findViewById(R.id.bt_add);
    
            btSelectContact.setOnClickListener(this);
            btSend.setOnClickListener(this);
            btAdd.setOnClickListener(this);
    
        }
    
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.bt_select:
                    Intent intent = new Intent(mContext, ContactActivity.class);
                    //  这个方法期望一个活动销毁后能返回给上个活动。当上个活动销毁,会调用本活动的onActivity
                    startActivityForResult(intent, 1);
                    break;
    
                case R.id.bt_add:
                    Intent intent2 = new Intent(mContext, SmsBodyActivity.class);
                    startActivityForResult(intent2, 2);
                    break;
    
                case R.id.bt_send:
                    String number = etName.getText().toString().trim();
                    String smsBody = etSmsBody.getText().toString().trim();
                    // 获取SmsManager实例
                    SmsManager smsManager = SmsManager.getDefault();
    //                如果短信内容过过多 发不出去。分条发送
                    List<String> divideMessages = smsManager.divideMessage(smsBody);
                    for (String div : divideMessages) {
                        // 发送短信数据,第一个参数是目的地,第三个参数是发送的String。其他参数先不用管
                        smsManager.sendTextMessage(number, null, div, null, null);
                    }
                    break;
                default:
            }
        }
    
    
        // 当ContactActivity销毁,会回调上一个活动(本活动)。将那个活动的setResult发送来的intent传给本活动
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            switch (requestCode) {
                // 上面startActivityForResult(intent, 1);
                case 1:
                    if (resultCode == RESULT_OK) {
                        String phone = data.getStringExtra("phone");
                        etName.setText(phone);
                    }
                    break;
                case 2:
                    if (resultCode == RESULT_OK) {
                        String smsBody = data.getStringExtra("sms_body");
                        etSmsBody.setText(smsBody);
                    }
                    break;
                default:
            }
        }
    }
    
    

    手动填写

    点击发送,确实发送成功!

    再看从联系人中选择,短信模板的使用

    点击某一个子项后,返回到主界面。此时联系人和短信内容已填充好。

    Activity生命周期

    oncreate //  当Activity第一次启动的时候调用
    onDestroy // 当Activity销毁的时候调用
    onStrat() // 当Activity变成可见的时候调用 
    onStop() //  当activity 不可见的时候调用
    onResume() //当activity可以获取焦点的时候  当界面的按钮可以被点击了
    onPause()//  当失去焦点的时候调用 当按钮不了可以被点击的时候调用
    onRestart()//当界面重新启动的时候调用
    

    横竖屏切换

    横竖屏切换,生命周期会变化。从onPause -> onStop -> onDestyoy -> onCreate -> onStrat -> onResume先销毁,再重新create。

    为了防止横竖屏切换,生命周期会发生变化,可把Activity配置如下。在AndroidManifest.xml里面的activity标签里写

    android:screenOrientation="portrait" 表示固定竖屏。

    或者这样写

    android:configChanges="orientation|keyboardHidden|screenSize"

    任务栈

    栈--先进后出

    打开一个Activity叫进栈,关闭一个Activity出栈

    我们操作的Activity永远是任务栈的栈顶的Activity

    说应用程序退出了,实际上是指任务栈清空了。

    四种启动模式

    通过activity的android:launchMode指定

    standard(默认)

    每启动一个活动,就会处于栈顶。假设一个intent自己开启自己,点击了两次共三个活动,则每次启动都会创建新的实例,要点击三次才能完全退出。

    singleTop

    还是上面的情况,自己开启自己时候,点击两次,只会开启一个活动(刚进入的拿个),此时返回一次就退出程序了。和上面不同的是,这个模式先检查任务栈的栈顶,若栈顶已经存在这个要开启的activity,不会重新的创建activity实例,而是复用已经存在的activity。保证栈顶如果存在,不会重复创建。

    应用场景:浏览器的书签

    singleTask

    singetask 单一任务栈,在当前任务栈里面只能有一个实例存在。

    当开启activity的时候,就去检查在任务栈里面是否有实例已经存在,如果有实例存在就复用这个已经存在的activity,并且把这个activity上面的所有的别的activity都清空,复用这个已经存在的activity。保证整个任务栈里面只有一个实例存在。

    举个例子:A指定为singleTask,假如刚进入应用是活动A,点击按钮1进入活动B, 在B中点击按钮2, 回到活动A。回到A的过程,此时B在栈顶,A在B下方。发现A活动已经有实例存在,直接onRestart,同时把A上面的所有活动(这里只有B)销毁,此时A处于栈顶,且栈顶只有一个A了。可以发现这样节约资源。

    应用场景:浏览器的activity。如果一个activity的创建需要占用大量的系统资源(cpu,内存)一般配置这个activity为singletask的启动模式。

    singleInstance

    指定为singleInstance的活动,会为其开启一个单独的任务栈,不管哪个应用程序来访问这个活动,都是用的同一个任务栈。如果你要保证一个activity在整个手机操作系统里面只有一个实例存在,使用singleInstance。

    举个例子:ABC三个活动,B指定为singleInstance,进入时为活动A,点击进入B,在点击进入C。此时若返回,不是C -> B -> A的顺序,而是从C -> A -> B,因为A和C是默认模式,在同一个任务栈里面,而B是在单独的任务栈里面,等当前的任务栈清空了,于是显示另外一个返回栈,这时才显示B。

    应用场景: 来电页面。


    by @sunhaiyu

    2017.5.7

    相关文章

      网友评论

          本文标题:Android中的Activity

          本文链接:https://www.haomeiwen.com/subject/qwnutxtx.html