一路繁花似锦绣前程
失败的越多,成功才越有价值

导航

 

安卓入门

十、组件学习

1、Activity
a、activity跳转和数据传输
  • MainActivity
public class MainActivity extends AppCompatActivity {
    EditText et;
    RadioGroup rg;

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

        et = findViewById(R.id.et);
        rg = findViewById(R.id.rg);
    }

    public void submit(View view) {
        String name = et.getText().toString().trim();
        int gender = 0;
        if (rg.getCheckedRadioButtonId() == R.id.rb1) {
            gender = 1;
        } else if (rg.getCheckedRadioButtonId() == R.id.rb2) {
            gender = 2;
        } else if (rg.getCheckedRadioButtonId() == R.id.rb3) {
            gender = 3;
        }

        if ("".equals(name)) {
            Toast.makeText(this, "姓名不能为空", Toast.LENGTH_SHORT).show();
        } else if (gender == 0) {
            Toast.makeText(this, "性别为必选项", Toast.LENGTH_SHORT).show();
        } else {
            Intent intent = new Intent(this, ResultActivity.class);
            intent.putExtra("name", name);
            intent.putExtra("gender", gender);
            startActivity(intent);
        }
    }
}
  • ResultActivity
public class ResultActivity extends AppCompatActivity {
    EditText etName;
    EditText etGender;

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

        etName = findViewById(R.id.name);
        etGender = findViewById(R.id.gender);

        Intent intent = getIntent();
        String name = intent.getStringExtra("name");
        int gender = intent.getIntExtra("gender", 0);

        etName.setText(name);
        if (gender == 1) {
            etGender.setText("男");
        } else if (gender == 2) {
            etGender.setText("女");
        } else if (gender == 3) {
            etGender.setText("人妖");
        }
    }
}
b、跳转短信应用并填充内容
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ListView lv = findViewById(R.id.lv);
        String[] list = {"孟美岐", "黄婷婷", "佟丽娅"};
        ArrayAdapter<String> adapter = new ArrayAdapter<>(this, R.layout.item, list);
        lv.setAdapter(adapter);

        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Intent intent = new Intent();
                intent.setAction("android.intent.action.SEND");
                intent.addCategory("android.intent.category.DEFAULT");
                intent.setType("text/plain");
                intent.putExtra("sms_body", list[position]);
                startActivity(intent);
            }
        });
    }
}
c、调用发送短信接口
  • 权限
<uses-permission android:name="android.permission.SEND_SMS" />
  • MainActivity
public class MainActivity extends AppCompatActivity {
    private EditText etPhone;
    private EditText etMsg;

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

        etPhone = findViewById(R.id.et_phone);
        etMsg = findViewById(R.id.et_msg);
    }

    public void insertPerson(View view) {
        /**
         * 视图1跳转视图2,视图2返回视图1并携带数据的步骤:
         * 1、视图1:startActivityForResult(意图对象, 请求码);
         * 2、视图2:setResult(响应码, 意图对象);
         * 3、视图2:finish();
         * 4、视图1:onActivityResult(请求码,响应码,意图对象)
         *
         * 意图对象感觉像可以携带数据的URL
         */
        Intent intent = new Intent(this, ContactActivity.class);
        startActivityForResult(intent, 1);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        String phone = data.getStringExtra("phone");
        etPhone.setText(phone);
    }

    public void sendMessage(View view) {
        String phone = etPhone.getText().toString().trim();
        String msg = etMsg.getText().toString().trim();
        // 分条发送短信
        SmsManager smsManager = SmsManager.getDefault();
        ArrayList<String> divideMessage = smsManager.divideMessage(msg);
        for (String div : divideMessage) {
            smsManager.sendTextMessage(phone, null, div, null, null);
        }
    }
}
  • ContactActivity
public class ContactActivity extends AppCompatActivity {
    List<Person> pList;

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

        pList = new ArrayList<Person>();
        for (int i = 0; i < 20; i++) {
            pList.add(new Person("黄婷婷" + i, 10000 + i));
        }

        ListView lv = findViewById(R.id.lv);
        lv.setAdapter(new MyAdapter());

        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                String phone = pList.get(position).getPhone() + "";
                Intent intent = new Intent();
                intent.putExtra("phone", phone);
                setResult(10, intent);
                finish();
            }
        });
    }

    private class MyAdapter extends BaseAdapter {
        @Override
        public int getCount() {
            return pList.size();
        }

        @Override
        public Object getItem(int position) {
            return pList.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = View.inflate(getApplicationContext(), R.layout.contact_item, null);
            }
            TextView tvName = convertView.findViewById(R.id.tv_name);
            tvName.setText(pList.get(position).getName());
            TextView tvPhone = convertView.findViewById(R.id.tv_phone);
            tvPhone.setText(pList.get(position).getPhone() + "");
            return convertView;
        }
    }
}
d、activity生命周期
onCreate(->onRestart)->onStart->onResume->onPause->onStop->onDestroy
2、Service
a、进程的概念
1、进程概念介绍
    * Android下四大组件都是运行在主线程中
    * 服务是在后台运行,没有界面
2、进程的优先级
    * Foregrount process(前台进程):优先级最高,相当于activity执行了onResume方法,用户正在交互
    * Visible process(可视进程):一直影响用户看得见,相当于activity执行了onPause方法
    * Service process(服务进程):通过startService方法开启了一个服务
    * Background process(后台进程):相当于activity执行了onStop方法,界面不可见,但是activity并没有销毁
    * Empty process(空进程):不会维持任何组件运行
b、startService和bindService
  • 清单文件注册
<application>
    <service android:name=".MyService" />
</application>
  • MainActivity
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void startServiceBtn(View view) {
        startService(new Intent(this, MyService.class));
    }

    public void stopServiceBtn(View view) {
        stopService(new Intent(this, MyService.class));
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            System.out.println("服务连接成功");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            System.out.println("服务断开连接");
        }
    };

    public void bindServiceBtn(View view) {
        bindService(new Intent(this, MyService.class), connection, Context.BIND_AUTO_CREATE);
    }

    public void unBindServiceBtn(View view) {
        unbindService(connection);
    }

    @Override
    protected void onDestroy() {
        unbindService(connection);
        super.onDestroy();
    }
}
  • activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="startService"
        android:textSize="32sp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="center_horizontal">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginHorizontal="10dp"
            android:onClick="startServiceBtn"
            android:text="startServiceBtn" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginHorizontal="10dp"
            android:onClick="stopServiceBtn"
            android:text="stopServiceBtn" />
    </LinearLayout>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="bindService"
        android:textSize="32sp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="center_horizontal">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginHorizontal="10dp"
            android:onClick="bindServiceBtn"
            android:text="bindServiceBtn" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginHorizontal="10dp"
            android:onClick="unBindServiceBtn"
            android:text="unBindServiceBtn" />
    </LinearLayout>
</LinearLayout>
  • MyService
public class MyService extends Service {
    /**
     * 开启服务执行此方法,只执行一次
     */
    @Override
    public void onCreate() {
        Log.e("--->", "onCreate");
        super.onCreate();
    }

    /**
     * 每次执行startService方法,都会执行此方法
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e("--->", "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onStart(Intent intent, int startId) {
        Log.e("--->", "onStart");
        super.onStart(intent, startId);
    }

    /**
     * 1、第一次点击绑定服务按钮,会执行服务的onCreate方法和onBind方法
     * 2、当onBind方法返回为null的时候,onServiceConnected方法是不执行的
     * 3、第二次点击绑定服务按钮,服务没有响应
     * 4、活动页(activity)销毁的时候,绑定的服务也会销毁
     * 5、服务不可以多次解绑,多次解绑会报异常
     * 6、通过bind方式开启服务,服务不能在设置页面找到,相当于是一个隐形的服务
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e("--->", "onBind");
        return null;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.e("--->", "onUnbind");
        return super.onUnbind(intent);
    }

    /**
     * 手动停止服务执行此方法
     */
    @Override
    public void onDestroy() {
        Log.e("--->", "onDestroy");
        super.onDestroy();
    }
}
c、电话听窃器案例
  • 清单文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.wuxi.myandroid">

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/meinv"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.我的安卓">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <!--当只需要服务(service)启动,无需活动页(activity)显示时,可注销intent-filter标签-->
            <!--<intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <service android:name=".MyService" />

        <receiver
            android:name=".MyReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
    </application>
</manifest>
  • MyReceiver
public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent it = new Intent(context, MyService.class);
        context.startService(it);
    }
}
  • MyService
public class MyService extends Service {
    private MediaRecorder recorder;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        // 获取TelephonyManager实例
        TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
        // 注册电话监听
        tm.listen(new MyPhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE);
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    private class MyPhoneStateListener extends PhoneStateListener {
        @Override
        public void onCallStateChanged(int state, String phoneNumber) {
            switch (state) {
                case TelephonyManager.CALL_STATE_IDLE://空闲状态
                    if (recorder != null) {
                        recorder.stop();//停止录音
                        recorder.reset();//重置
                        recorder.release();//释放资源
                    }
                    break;
                case TelephonyManager.CALL_STATE_OFFHOOK://接听状态
                    if (recorder != null) {
                        recorder.start();//开始录音
                    }
                    break;
                case TelephonyManager.CALL_STATE_RINGING://响铃状态
                    //创建MediaRecorder实例
                    recorder = new MediaRecorder();
                    //设置音频的来源
                    recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
                    //设置输出的格式
                    recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                    //设置存放的路径
                    recorder.setOutputFile("/mnt/sdcard/luyin.3gp");
                    try {
                        //准备录
                        recorder.prepare();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    break;
            }
            super.onCallStateChanged(state, phoneNumber);
        }
    }
}
d、通过bindService方式调用服务的方法
  • MainActivity
public class MainActivity extends AppCompatActivity {
    private IMyBinder myBinder;
    private ServiceConnection connection;

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

        Intent intent = new Intent(this, MyService.class);
        connection = new MyServiceConnection();
        bindService(intent, connection, BIND_AUTO_CREATE);
    }

    public void callServiceMethod(View view) {
        myBinder.callServiceMethod("调用服务的方法");
    }

    @Override
    protected void onDestroy() {
        unbindService(connection);
        super.onDestroy();
    }

    private class MyServiceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myBinder = (IMyBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    }
}
  • MyService
public class MyService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    public void serviceMethod(String msg) {
        Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_SHORT).show();
    }

    // 接口方式调用服务方法
    private class MyBinder extends Binder implements IMyBinder {
        public void callServiceMethod(String msg) {
            // 调用服务的方法
            serviceMethod(msg);
        }
    }
}
  • IMyBinder
public interface IMyBinder {
    void callServiceMethod(String msg);
}
e、百度音乐盒案例(混合方式开启服务)
步骤:startService->bindService->unBindService->stopService。案例在多媒体章节,音频案例
f、调用远程服务
  • 清单文件(远程服务)
<service
    android:name=".MyService"
    android:exported="true">
    <intent-filter>
        <action android:name="com.wuxi.myandroid" />
    </intent-filter>
</service>
  • MyService(远程服务)
public class MyService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    public void serviceMethod(String msg) {
        Log.e("--->", msg);
    }

    private class MyBinder extends IMyBinder.Stub {
        public void callServiceMethod(String msg) {
            serviceMethod(msg);
        }
    }
}
  • IMyBinder.aidl(远程服务和本地调用者)
// 不能使用public修饰
// 远程服务和本地调用者使用相同aidl,包名必须一致,由远程服务提供
interface IMyBinder {
    void callServiceMethod(String msg);
}
  • MainActivity(本地调用者)
public class MainActivity extends AppCompatActivity {
    private IMyBinder myBinder;
    private ServiceConnection connection;

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

        Intent intent = new Intent();
        intent.setAction("com.wuxi.myandroid");
        connection = new MyServiceConnection();
        bindService(intent, connection, BIND_AUTO_CREATE);
    }

    public void callServiceMethod(View view) {
        try {
            myBinder.callServiceMethod("调用远程服务的方法");
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {
        unbindService(connection);
        super.onDestroy();
    }

    private class MyServiceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myBinder = IMyBinder.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    }
}
g、通知和服务连用,可以提升进程的优先级
public class MyService extends Service {
    @Override
    public IBinder onBind(Intent intent) {
        throw null;
    }

    @Override
    public void onCreate() {
        //通知和服务连用,可以提升进程的优先级
        //startForeground(id,notification);
        super.onCreate();
    }
}
3、Receiver
a、发送动态无序广播(广播无需在清单文件中注册)
  • MainActivity
public class MainActivity extends AppCompatActivity {
    MyReceiver myReceiver;

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

        myReceiver = new MyReceiver();
        IntentFilter itFilter = new IntentFilter();
        // 解锁屏广播必须是动态注册,且需要被注销
        // itFilter.addAction("android.intent.action.SCREEN_OFF");
        // itFilter.addAction("android.intent.action.SCREEN_ON");
        itFilter.addAction("com.wuxi.myandroid");
        registerReceiver(myReceiver, itFilter);
    }

    @Override
    protected void onDestroy() {
        unregisterReceiver(myReceiver);
        super.onDestroy();
    }

    public void sendReceiver(View view) {
        Intent intent = new Intent();
        intent.setAction("com.wuxi.myandroid");
        intent.putExtra("name", "黄婷婷");
        sendBroadcast(intent);
    }
}
  • activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="sendReceiver"
        android:text="发送广播" />

</LinearLayout>
  • MyReceiver
public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String name = intent.getStringExtra("name");
        Log.e("--->", "接收动态无序广播:" + name);
    }
}
b、打电话广播
  • 权限
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
  • 清单文件注册广播(application标签下)
<receiver
    android:name=".MyReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
    </intent-filter>
</receiver>
  • MainActivity
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        SharedPreferences sp = getSharedPreferences("info", 0);
        SharedPreferences.Editor edit = sp.edit();
        edit.putString("ipNumber", "17950");
        edit.apply();
    }
}
  • MyReceiver
public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        SharedPreferences sp = context.getSharedPreferences("info", 0);
        String ipNumber = sp.getString("ipNumber", "");
        String resultData = getResultData();
        Log.e("--->", ipNumber);
        Log.e("--->", resultData);
        setResultData(ipNumber + resultData);
    }
}
c、sd卡状态广播
  • 清单文件注册广播(application标签下)
<receiver
    android:name=".MyReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MEDIA_MOUNTED" />
        <action android:name="android.intent.action.MEDIA_UNMOUNTED" />

        <data android:scheme="file" />
    </intent-filter>
</receiver>
  • MyReceiver
public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if ("android.intent.action.MEDIA_MOUNTED".equals(action)) {
            Log.e("--->", "sd卡装载了");
        } else if ("android.intent.action.MEDIA_UNMOUNTED".equals(action)) {
            Log.e("--->", "sd卡卸载了");
        }
    }
}
d、短信接收广播
  • 权限
<uses-permission android:name="android.permission.RECEIVE_SMS" />
  • 清单文件注册广播(application标签下)
<receiver
    android:name=".MyReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
</receiver>
  • MyReceiver
public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Object[] pdus = (Object[]) intent.getExtras().get("pdus");
        for (Object pdu : pdus) {
            SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdu);
            String messageBody = smsMessage.getMessageBody();
            String address = smsMessage.getOriginatingAddress();
            Log.e("--->", address + ":" + messageBody);
        }
    }
}
e、应用装卸载广播
  • 清单文件注册广播(application标签下)
<receiver
    android:name=".MyReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.PACKAGE_ADDED" />
        <action android:name="android.intent.action.PACKAGE_REMOVED" />

        <data android:scheme="package" />
    </intent-filter>
</receiver>
  • MyReceiver
public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if ("android.intent.action.PACKAGE_ADDED".equals(action)) {
            Log.e("--->", intent.getData() + "安装了");
        } else if ("android.intent.action.PACKAGE_REMOVED".equals(action)) {
            Log.e("--->", intent.getData() + "卸载了");
        }
    }
}
f、手机重启广播
  • 权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
  • 清单文件注册广播(application标签下)
<receiver
    android:name=".MyReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>
  • MyReceiver
public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent newIntent = new Intent(context, MainActivity.class);
        // 广播中开启activity,需加任务栈标记
        newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(newIntent);
    }
}
g、有序广播
  • 清单文件注册广播(application标签下)
<receiver
    android:name=".MyReceiver1"
    android:exported="true">
    <!--android:priority:数字越大优先级越高,范围1000~-1000-->
    <intent-filter android:priority="1000">
        <action android:name="com.wuxi.myandroid" />
    </intent-filter>
</receiver>
  • MainActivity
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void sendReceiver(View view) {
        Intent intent = new Intent();
        intent.setAction("com.wuxi.myandroid");
        MyReceiver myReceiver = new MyReceiver();
        /**
         * 参数1:意图对象
         * 参数3:广播最终接收者
         * 参数5:初始码
         * 参数6:初始数据,可被接收者的getResultData()方法获取
         */
        sendOrderedBroadcast(intent, null, myReceiver, null, 1, "黄婷婷", null);
    }
}
  • MyReceiver1
public class MyReceiver1 extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String resultData = getResultData();
        Log.e("--->", resultData);
        // 无序广播不可使用此方法终止广播
        abortBroadcast();
        // 无序广播和广播最终接收者,不可使用此方法设置数据
        setResultData("鞠婧祎");
    }
}
4、Provider
a、基本使用
  • 清单文件(远程服务)
<provider
    android:name=".MyContentProvider"
    android:authorities="com.wuxi.other" />
  • MySQLiteOpenHelper(远程服务)
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
    public MySQLiteOpenHelper(Context context) {
        super(context, "wuxi.db", null, 1);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("create table person(id integer primary key autoincrement,name varchar(20),age integer)");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }
}
  • MyContentProvider(远程服务)
public class MyContentProvider extends ContentProvider {
    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    private MySQLiteOpenHelper mySQLiteOpenHelper;

    private static final int QUERYSUCCESS = 1;
    private static final int INSERTSUCCESS = 2;
    private static final int DELETESUCCESS = 3;
    private static final int UPDATESUCCESS = 4;

    static {
        sURIMatcher.addURI("com.wuxi.other", "query", QUERYSUCCESS);
        sURIMatcher.addURI("com.wuxi.other", "insert", INSERTSUCCESS);
        sURIMatcher.addURI("com.wuxi.other", "delete", DELETESUCCESS);
        sURIMatcher.addURI("com.wuxi.other", "update", UPDATESUCCESS);
    }

    @Override
    public boolean onCreate() {
        mySQLiteOpenHelper = new MySQLiteOpenHelper(getContext());
        return false;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, 
                        @Nullable String[] selectionArgs, @Nullable String sortOrder) {
        int code = sURIMatcher.match(uri);
        if (code == QUERYSUCCESS) {
            SQLiteDatabase db = mySQLiteOpenHelper.getReadableDatabase();
            Cursor cursor = db.query("person", projection, selection, selectionArgs, null, null, sortOrder);
            getContext().getContentResolver().notifyChange(uri, null);
            return cursor;
        } else {
            throw new IllegalArgumentException("查询路径参数不匹配");
        }
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        int code = sURIMatcher.match(uri);
        if (code == INSERTSUCCESS) {
            SQLiteDatabase db = mySQLiteOpenHelper.getWritableDatabase();
            long numb = db.insert("person", null, values);
            db.close();
            getContext().getContentResolver().notifyChange(uri, null);
            Uri res = Uri.parse("com.wuxi.other/insert/" + numb);
            return res;
        } else {
            throw new IllegalArgumentException("新增路径参数不匹配");
        }
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        int code = sURIMatcher.match(uri);
        if (code == DELETESUCCESS) {
            SQLiteDatabase db = mySQLiteOpenHelper.getWritableDatabase();
            int numb = db.delete("person", selection, selectionArgs);
            db.close();
            getContext().getContentResolver().notifyChange(uri, null);
            return numb;
        } else {
            throw new IllegalArgumentException("删除路径参数不匹配");
        }
    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        int code = sURIMatcher.match(uri);
        if (code == UPDATESUCCESS) {
            SQLiteDatabase db = mySQLiteOpenHelper.getWritableDatabase();
            int numb = db.update("person", values, selection, selectionArgs);
            db.close();
            getContext().getContentResolver().notifyChange(uri, null);
            return numb;
        } else {
            throw new IllegalArgumentException("修改路径参数不匹配");
        }
    }
}
  • MainActivity(本地调用者)
public class MainActivity extends AppCompatActivity {
    private TextView tv;
    private EditText etName;
    private EditText etAge;
    private EditText etId;

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

        tv = findViewById(R.id.tv);
        etName = findViewById(R.id.et_name);
        etAge = findViewById(R.id.et_age);
        etId = findViewById(R.id.et_id);
    }

    // 点击添加按钮的事件
    public void insertHandler(View view) {
        Uri uri = Uri.parse("content://com.wuxi.other/insert");
        String name = etName.getText().toString().trim();
        int age = Integer.parseInt(etAge.getText().toString().trim());
        ContentValues values = new ContentValues();
        values.put("name", name);
        values.put("age", age);
        getContentResolver().insert(uri, values);
    }

    // 点击删除按钮的事件
    public void deleteHandler(View view) {
        Uri uri = Uri.parse("content://com.wuxi.other/delete");
        String id = String.valueOf(Integer.parseInt(etId.getText().toString().trim()));
        getContentResolver().delete(uri, "id=?", new String[]{id});
    }

    // 点击修改按钮的事件
    public void updateHandler(View view) {
        String id = String.valueOf(Integer.parseInt(etId.getText().toString().trim()));
        String name = etName.getText().toString().trim();
        int age = Integer.parseInt(etAge.getText().toString().trim());
        ContentValues values = new ContentValues();
        values.put("name", name);
        values.put("age", age);
        Uri uri = Uri.parse("content://com.wuxi.other/update");
        getContentResolver().update(uri, values, "id=?", new String[]{id});
    }

    // 点击查询按钮的事件
    public void selectHandler(View view) {
        // 通过通过内容解析者操作数据库
        Uri uri = Uri.parse("content://com.wuxi.other/query");
        Cursor cursor = getContentResolver().query(uri, null, null, null, null);
        StringBuffer sb = new StringBuffer();
        if (cursor != null && cursor.getCount() > 0) {
            while (cursor.moveToNext()) {
                int id = cursor.getInt(0);
                String name = cursor.getString(1);
                int age = cursor.getInt(2);
                sb.append(String.format(Locale.CHINA, "{id:%d,name:%s,age:%d}\n", id, name, age));
            }
            cursor.close();
        }
        tv.setText(sb);
    }
}
  • activity_main.xml(本地调用者)
<?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"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <EditText
        android:id="@+id/et_id"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="id" />

    <EditText
        android:id="@+id/et_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="name" />

    <EditText
        android:id="@+id/et_age"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="age" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="insertHandler"
        android:text="添加" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="deleteHandler"
        android:text="删除" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="updateHandler"
        android:text="修改" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="selectHandler"
        android:text="查看" />

    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="24sp" />
</LinearLayout>
  • MainActivity(观察者)
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Uri uri = Uri.parse("content://com.wuxi.other");
        //如果是确切的URI,则参数2为false
        getContentResolver().registerContentObserver(uri, true, new MyContentObserver(new Handler()));
    }

    private class MyContentObserver extends ContentObserver {
        public MyContentObserver(Handler handler) {
            super(handler);
        }

        //当内容提供者执行getContext().getContentResolver().notifyChange()操作,观察者就会执行此方法
        @Override
        public void onChange(boolean selfChange) {
            System.out.println("当内容提供者发生改变时调用");
            super.onChange(selfChange);
        }
    }
}
b、操作短信数据库案例
  • 清单文件
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
  • MainActivity
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void selectHandler(View view) {
        Uri uri = Uri.parse("content://sms/");
        Cursor cursor = getContentResolver().query(uri, new String[]{"address", "date", "body"}, null, null, null);
        if (cursor != null && cursor.getCount() > 0) {
            while (cursor.moveToNext()) {
                String address = cursor.getString(0);
                String date = cursor.getString(1);
                String body = cursor.getString(2);
                System.out.printf(Locale.CHINA, "{address:%s,date:%s,body:%s}%n", address, date, body);
            }
        }
    }

    public void insertHandler(View view) {
        Uri uri = Uri.parse("content://sms/");
        ContentValues values = new ContentValues();
        values.put("address", "110");
        values.put("date", System.currentTimeMillis());
        values.put("body", "孟美岐,黄婷婷,鞠婧祎");
        getContentResolver().insert(uri, values);
    }
}
c、操作联系人数据库案例
  • 清单文件
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
  • MainActivity
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void selectHandler(View view) {
        Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
        Uri dataUri = Uri.parse("content://com.android.contacts/data");
        Cursor cursor = getContentResolver().query(uri, new String[]{"contact_id"}, null, null, null);
        while (cursor.moveToNext()) {
            String contact_id = cursor.getString(0);
            if (contact_id != null) {
                System.out.println("id:" + contact_id);
                Cursor dataCursor = getContentResolver().query(dataUri, new String[]{"data1", "mimetype"}, "raw_contact_id=?", 
                        new String[]{contact_id}, null);
                while (dataCursor.moveToNext()) {
                    String data1 = dataCursor.getString(0);
                    String mimetype = dataCursor.getString(1);
                    if ("vnd.android.cursor.item/name".equals(mimetype)) {
                        System.out.println("姓名:" + data1);
                    } else if ("vnd.android.cursor.item/phone_v2".equals(mimetype)) {
                        System.out.println("电话号码:" + data1);
                    } else if ("vnd.android.cursor.item/email_v2".equals(mimetype)) {
                        System.out.println("邮箱:" + data1);
                    }
                }
            }
        }
    }

    public void insertHandler(View view) {
        Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
        Uri dataUri = Uri.parse("content://com.android.contacts/data");
        //查询raw_contacts表中一共有几条数据,行数+1就是contact_id的值
        Cursor cursor = getContentResolver().query(uri, null, null, null, null);
        int count = cursor.getCount();
        int contact_id = count + 1;
        //插入raw_contacts表
        ContentValues values = new ContentValues();
        values.put("contact_id", contact_id);
        getContentResolver().insert(uri, values);
        //name插入data表
        ContentValues nameValues = new ContentValues();
        nameValues.put("data1", "姓名");
        nameValues.put("raw_contact_id", contact_id);
        nameValues.put("mimetype", "vnd.android.cursor.item/name");
        getContentResolver().insert(dataUri, nameValues);
        //phone插入data表
        ContentValues phoneValues = new ContentValues();
        phoneValues.put("data1", "18120078605");
        phoneValues.put("raw_contact_id", contact_id);
        phoneValues.put("mimetype", "vnd.android.cursor.item/phone_v2");
        getContentResolver().insert(dataUri, phoneValues);
        //email插入data表
        ContentValues emailValues = new ContentValues();
        emailValues.put("data1", "865094624@qq.com");
        emailValues.put("raw_contact_id", contact_id);
        emailValues.put("mimetype", "vnd.android.cursor.item/email_v2");
        getContentResolver().insert(dataUri, emailValues);
    }
}
d、观察短信数据库案例
  • MainActivity
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Uri uri = Uri.parse("content://sms");
        getContentResolver().registerContentObserver(uri, true, new MyContentObserver(new Handler()));
    }

    private class MyContentObserver extends ContentObserver {
        public MyContentObserver(Handler handler) {
            super(handler);
        }

        @Override
        public void onChange(boolean selfChange) {
            System.out.println("短信数据库发生了改变");
            super.onChange(selfChange);
        }
    }
}
5、清单文件
  • AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.wuxi.myandroid">

    <uses-permission android:name="android.permission.SEND_SMS" /> // 权限
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.VIBRATE" /> // 手机振动权限

    <application
        android:allowBackup="true"
        android:icon="@drawable/meinv" // 应用图标
        android:label="@string/app_name" // 应用名
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        /**
         * 样式和主题:可在res/values目录下任意xml内定义。样式一般用于控件,主题一般用于activity或application节点下。
         * <resources xmlns:tools="http://schemas.android.com/tools"><style name="样式或主题名"><item name="属性名">值</item></style></resources>
         */
        android:theme="@style/Theme.我的安卓">
        <activity
            android:name=".ContactActivity"
            android:exported="false" // 是否支持其他应用调用当前组件。默认值:有intent-filter默认为true,没有默认为false。
            /**
             * standard:标准栈;
             * singleTop:栈顶不可重复;
             * singleTask:不重复的栈任务,复用之前同样的栈任务,复用的栈任务之后的栈任务全部销毁;
             * singleInstance:新建一个栈且只有一个栈任务。当前活动栈是哪个,哪个就先进行出栈操作。
             */
            android:launchMode="standard" 
            android:screenOrientation="portrait" /> // portrait:竖屏;landscape:横屏。
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter> // 主入口:一般一个应用只有一个
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
6、备注
a、注意点
* 四大组件必须在清单文件里面注册
* 国际化:在res目录下创建不同国家语言环境集,目录是固定写法values-en、values-zh...
b、屏蔽返回键
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public void onBackPressed() {
        // 注销super.onBackPressed();即可屏蔽返回键
        super.onBackPressed();
    }
}
posted on 2021-12-20 13:26  一路繁花似锦绣前程  阅读(55)  评论(0编辑  收藏  举报