Android中的Activity

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區(qū)別

  • 顯示意圖更加安全一些,因為不能直接通過action、category、data等訪問到。(壓根沒指定) ,只能通過上下文來使用。所以一般用來開啟自己應用的界面。
  • 隱式意圖一般開啟系統(tǒng)應用(電話撥號器 短信的發(fā)送器等等)的界面,用于應用和應用之間。

一個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);
        // 設置子項點擊事件,跳轉到短信發(fā)送界面
        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--向上一個活動傳遞數據

寫一個自定義短信發(fā)送的功能。

可以從聯(lián)系人中選擇號碼,可以選擇短信模板。點擊發(fā)送就會發(fā)送短信。

主布局

<?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="發(fā)送"/>
    </RelativeLayout>

</LinearLayout>

點擊添加按鈕,就可跳轉到聯(lián)系人界面

聯(lián)系人布局,這里簡化為一個包含姓名和號碼的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封裝聯(lián)系人信息。

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;
    }
}

然后是聯(lián)系人的子項布局

<?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>

聯(lián)系人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;
    }
}

看下聯(lián)系人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;
        // 初始化聯(lián)系人數據
        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();
                // 只需發(fā)送號碼就行
                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("我在開會,請稍后聯(lián)系"+i);
            smsList.add("我在吃飯,請稍后聯(lián)系"+i);
            smsList.add("我在忙,請稍后聯(lián)系"+i);
            smsList.add("我在工作,請稍后聯(lián)系"+i);
        }
    }
}

最后來看MainActivity,由于在Android6.0后發(fā)送短信也需要申請運行時權限。所以在一進應用就申請權限。

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();
//                如果短信內容過過多 發(fā)不出去。分條發(fā)送
                List<String> divideMessages = smsManager.divideMessage(smsBody);
                for (String div : divideMessages) {
                    // 發(fā)送短信數據,第一個參數是目的地,第三個參數是發(fā)送的String。其他參數先不用管
                    smsManager.sendTextMessage(number, null, div, null, null);
                }
                break;
            default:
        }
    }


    // 當ContactActivity銷毀,會回調上一個活動(本活動)。將那個活動的setResult發(fā)送來的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:
        }
    }
}

手動填寫

點擊發(fā)送,確實發(fā)送成功!

再看從聯(lián)系人中選擇,短信模板的使用

點擊某一個子項后,返回到主界面。此時聯(lián)系人和短信內容已填充好。

Activity生命周期

oncreate //  當Activity第一次啟動的時候調用
onDestroy // 當Activity銷毀的時候調用
onStrat() // 當Activity變成可見的時候調用 
onStop() //  當activity 不可見的時候調用
onResume() //當activity可以獲取焦點的時候  當界面的按鈕可以被點擊了
onPause()//  當失去焦點的時候調用 當按鈕不了可以被點擊的時候調用
onRestart()//當界面重新啟動的時候調用

橫豎屏切換

橫豎屏切換,生命周期會變化。從onPause -> onStop -> onDestyoy -> onCreate -> onStrat -> onResume先銷毀,再重新create。

為了防止橫豎屏切換,生命周期會發(fā)生變化,可把Activity配置如下。在AndroidManifest.xml里面的activity標簽里寫

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

或者這樣寫

android:configChanges="orientation|keyboardHidden|screenSize"

任務棧

棧--先進后出

打開一個Activity叫進棧,關閉一個Activity出棧

我們操作的Activity永遠是任務棧的棧頂的Activity

說應用程序退出了,實際上是指任務棧清空了。

四種啟動模式

通過activity的android:launchMode指定

standard(默認)

每啟動一個活動,就會處于棧頂。假設一個intent自己開啟自己,點擊了兩次共三個活動,則每次啟動都會創(chuàng)建新的實例,要點擊三次才能完全退出。

singleTop

還是上面的情況,自己開啟自己時候,點擊兩次,只會開啟一個活動(剛進入的拿個),此時返回一次就退出程序了。和上面不同的是,這個模式先檢查任務棧的棧頂,若棧頂已經存在這個要開啟的activity,不會重新的創(chuàng)建activity實例,而是復用已經存在的activity。保證棧頂如果存在,不會重復創(chuàng)建。

應用場景:瀏覽器的書簽

singleTask

singetask 單一任務棧,在當前任務棧里面只能有一個實例存在。

當開啟activity的時候,就去檢查在任務棧里面是否有實例已經存在,如果有實例存在就復用這個已經存在的activity,并且把這個activity上面的所有的別的activity都清空,復用這個已經存在的activity。保證整個任務棧里面只有一個實例存在。

舉個例子:A指定為singleTask,假如剛進入應用是活動A,點擊按鈕1進入活動B, 在B中點擊按鈕2, 回到活動A。回到A的過程,此時B在棧頂,A在B下方。發(fā)現A活動已經有實例存在,直接onRestart,同時把A上面的所有活動(這里只有B)銷毀,此時A處于棧頂,且棧頂只有一個A了。可以發(fā)現這樣節(jié)約資源。

應用場景:瀏覽器的activity。如果一個activity的創(chuàng)建需要占用大量的系統(tǒng)資源(cpu,內存)一般配置這個activity為singletask的啟動模式。

singleInstance

指定為singleInstance的活動,會為其開啟一個單獨的任務棧,不管哪個應用程序來訪問這個活動,都是用的同一個任務棧。如果你要保證一個activity在整個手機操作系統(tǒng)里面只有一個實例存在,使用singleInstance。

舉個例子:ABC三個活動,B指定為singleInstance,進入時為活動A,點擊進入B,在點擊進入C。此時若返回,不是C -> B -> A的順序,而是從C -> A -> B,因為A和C是默認模式,在同一個任務棧里面,而B是在單獨的任務棧里面,等當前的任務棧清空了,于是顯示另外一個返回棧,這時才顯示B。

應用場景: 來電頁面。


by @sunhaiyu

2017.5.7

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容