读一读

Android运行一些东西都是需要权限的,以前都会在AndroidManifest.xml里面事先声明好所有的权限,但是这样的话可能会让一些程序申请太多的权限,从而造成安全隐患。所以可以写成动态申请权限。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView((R.layout.first_layout));
    
    Button button12 = (Button)findViewById(R.id.button12);
    button12.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view) {
            if(ContextCompat.checkSelfPermission(Main2Activity.this, Manifest.permission.CALL_PHONE)
                    != PackageManager.PERMISSION_GRANTED)//先检查权限
            {
                //检查是否可以弹出权限授权窗口,注意:第一次没弹过或点击了不再授权会返回false
                if (ActivityCompat.shouldShowRequestPermissionRationale(AndroidPlugin.instance, Manifest.permission.CALL_PHONE)) {
                    ActivityCompat.requestPermissions(instance, new String[]{Manifest.permission.CALL_PHONE}, SdkConst.CALL_PHONE);
                }
                else
                {
                    //因为第一次访问也是返回false,所以也需要请求授权,可以添加返回值区别,业务层 记录是否为第一次以决定是否弹出提示去设置开启权限
                    ActivityCompat.requestPermissions(instance, new String[]{Manifest.permission.CALL_PHONE}, SdkConst.CALL_PHONE);
                }
            }else
            {
                call();
            }
        }
    });
}

private void  call()
{
    try{
        Intent intent = new Intent(Intent.ACTION_CALL);
        intent.setData(Uri.parse("tel:10086"));
        startActivity(intent);
    }
    catch (SecurityException e)
    {
        Toast.makeText(Main2Activity.this,"没有权限",Toast.LENGTH_LONG).show();
        e.printStackTrace();
    }
}

@Override//申请权限回调
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode)
    {
        case 1:
            if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
            {
                call();
            }else
            {
                Toast.makeText(Main2Activity.this,"没有权限" ,Toast.LENGTH_LONG).show();
            }
        break;
    }
}

SharedPreferences是使用键值对的方式来存储数据的。

一、存储

Button button10 = (Button)findViewById(R.id.button10);
button10.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View view) {
        SharedPreferences.Editor editor = getSharedPreferences("data",MODE_PRIVATE).edit();
        editor.putString("name","tingting");
        editor.putInt("age",18);
        editor.apply();
    }
});


二、读取

Button button11 = (Button)findViewById(R.id.button11);
button11.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View view) {
        SharedPreferences share = getSharedPreferences("data",MODE_PRIVATE);
        StringBuilder str = new StringBuilder();
        str.append(share.getString("name",""));
        str.append(share.getInt("age",100));
        str.append("了");
        Toast.makeText(Main2Activity.this,str.toString(),Toast.LENGTH_LONG).show();
    }
});

一、将数据存储到文件中

Context类中提供了一个openFileOutput()方法,可以将数据存储到指定的文件中。接受两个参数,第一个是文件名,第二个是文件的操作模式,主要有两种可选,MODE_PRIVATE和MODE_APPEND。MODE_ORIVATE表示覆盖内容,MODE_APPEND表示追加内容。两种模式都会在文件不存在的时候闯将文件。

public void Save(String inputText)
{
    FileOutputStream out = null;
    BufferedWriter writer = null;
    try {
        out = openFileOutput("data", Context.MODE_PRIVATE);
        writer = new BufferedWriter(new OutputStreamWriter(out));
        writer.write(inputText);
    }catch (IOException e)
    {
        e.printStackTrace();
    }
    finally {
        try{
            if(writer != null)
                writer.close();
        }catch (IOException e)
        {
            e.printStackTrace();
        }
    }
}

protected void onDestroy() {
    super.onDestroy();
    Save(edit.getText().toString());
}


二、从文件中读取数据

Context类中提供了一个openFileInput()方法,用于从文件中读取数据,接受一个文件名参数。

public String load()
{
    FileInputStream in = null;
    BufferedReader reader = null;
    StringBuilder content = new StringBuilder();
    try{
        in = openFileInput("data");
        reader = new BufferedReader(new InputStreamReader(in));
        String line = "";
        while((line = reader.readLine()) != null)
        {
            content.append(line);
        }
    }catch (IOException e)
    {
        e.printStackTrace();
    }
    finally {
        try{
            reader.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    return content.toString();
}

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

    edit = (EditText) findViewById(R.id.edit);
    String inputText = load();
    if(!TextUtils.isEmpty(inputText))
    {
        edit.setText(inputText);
        edit.setSelection(inputText.length());
        Toast.makeText(Main2Activity.this,"加载数据成功",Toast.LENGTH_SHORT).show();
    }
}

使用本地广播可以避免广播被其他任何应用程序接收到,同时广播接收器也只能接收来自本应发出的广播,这样就可以避免其他应用程序广播的污染了。

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView((R.layout.first_layout));
    
    localBroadcastManager = LocalBroadcastManager.getInstance(Main2Activity.this);
    rece = new BootCompleteReceiver();
    IntentFilter iF = new IntentFilter();
    iF.addAction("group.chicai.study.JJJ");
    localBroadcastManager.registerReceiver(rece,iF);

    Button button9 = (Button)findViewById(R.id.button9);
    button9.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent intent = new Intent("group.chicai.study.JJJ");
            localBroadcastManager.sendBroadcast(intent);
        }
    });
}

protected void onDestroy() {
    super.onDestroy();
    localBroadcastManager.unregisterReceiver(rece);
}


public class BootCompleteReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"啦啦啦空间啊沙发哈会计法哈克金凤凰",Toast.LENGTH_LONG).show();
    }
}

一、多个广播接收器

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {

        Toast.makeText(context,"接受到我的广播",Toast.LENGTH_SHORT).show();
        abortBroadcast();//截断消息广播
    }
}

public class MyReceiver2 extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"接受自定义2",Toast.LENGTH_SHORT).show();
    }
}

二、注册广播接收器,并指定接收顺序。android:priority越高表示优先通知

<receiver
    android:name=".MyReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter android:priority="100">
        <action android:name="group.chicai.study.MYBOASTCASE" />
    </intent-filter>
</receiver>
<receiver
    android:name=".MyReceiver2"
    android:enabled="true"
    android:exported="true"
    >
    <intent-filter android:priority="99">
        <action android:name="group.chicai.study.MYBOASTCASE" />
    </intent-filter>
</receiver>

三、发送有序广播

Button button8 = (Button)findViewById(R.id.button8);
button8.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent intent = new Intent("group.chicai.study.MYBOASTCASE");
        sendOrderedBroadcast(intent,null);//就是换了个方法发送
    }
});

标准广播是一种完全异步执行的广播,广播发出后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息。无法被截断。

一、新建广播接收器,右键New->Other->Broadcast Receiver,就会创建一个广播接收器

package group.chicai.study;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        Toast.makeText(context,"接受到我的广播",Toast.LENGTH_SHORT).show();
        abortBroadcast();

    }
}

二、注册这个广播接收器的触发行为

<receiver
    android:name=".MyReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter ><!-- 静态注册 -->
            <action android:name="group.chicai.study.MYBOASTCASE" />
    </intent-filter>
</receiver>
//动态注册
intentFilter = new IntentFilter();
intentFilter.addAction("group.chicai.study.MYBOASTCASE");
MyReceiver my = new MyReceiver();
registerReceiver(my,intentFilter);

三、发送广播

Button button8 = (Button)findViewById(R.id.button8);
button8.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent intent = new Intent("group.chicai.study.MYBOASTCASE");
        sendBroadcast(intent);
    }
});


同样的,系统上定义了很多检查状态改变的action,可以让接收器去注册这个行为,这样当系统的某些状态改变时,就会触发这些接收器了。例如:网络改变的监督-android.net.conn.CONNECTIVITY_CHANGE


public class SystemUtil {
    /*
    *获取电量 context为UnityPlayer.currentActivity 。
     */
    public static float MonitorBatteryState(Context context)
    {
        IntentFilter iFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        Intent intent = context.registerReceiver(null, iFilter);
        int rawLevel = intent.getIntExtra("level", 0);      //获得当前电量
        int scale = intent.getIntExtra("scale", 0);         //获得总电量
        //int status = intent.getIntExtra("status", 0);       //电池充电状态
        return (float)rawLevel / (float)scale;
    }

    //获取Wifi信号强度 context为UnityPlayer.currentActivity 。
    @SuppressWarnings("deprecation")
    public static int ObtainWifiInfo(Context context)
    {
        int strength = 0;
        WifiManager wifiManager = (WifiManager)context.getSystemService(WIFI_SERVICE);
        WifiInfo info = wifiManager.getConnectionInfo();
        if(info.getBSSID() != null)
        {
            //链接信号强度
            strength = WifiManager.calculateSignalLevel(info.getRssi(), 5);
        }
        return  strength;
    }

    //获取手机网络信号 context为UnityPlayer.currentActivity 。
    public static int getMobileSignLevel(Context context)
    {
        int dbm = -1;
        int level = 0;
        TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
        List<CellInfo> cellInfoList = tm.getAllCellInfo();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
        {
            if (null != cellInfoList)
            {
                for (CellInfo cellInfo : cellInfoList)
                {
                    if (cellInfo instanceof CellInfoGsm)
                    {
                        CellSignalStrengthGsm cellSignalStrengthGsm = ((CellInfoGsm)cellInfo).getCellSignalStrength();
                        level = cellSignalStrengthGsm.getLevel();
                    }
                    else if (cellInfo instanceof CellInfoCdma)
                    {
                        CellSignalStrengthCdma cellSignalStrengthCdma = ((CellInfoCdma)cellInfo).getCellSignalStrength();
                        level = cellSignalStrengthCdma.getLevel();
                    }
                    else if (cellInfo instanceof CellInfoWcdma)
                    {
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2)
                        {
                            CellSignalStrengthWcdma cellSignalStrengthWcdma = ((CellInfoWcdma)cellInfo).getCellSignalStrength();
                            level =  cellSignalStrengthWcdma.getLevel();
                        }
                    }
                    else if (cellInfo instanceof CellInfoLte)
                    {
                        CellSignalStrengthLte cellSignalStrengthLte = ((CellInfoLte)cellInfo).getCellSignalStrength();
                        level = cellSignalStrengthLte.getLevel();
                    }
                }
            }
        }

        return level;
    }
}

可以在AndroidManifiest.xml文件中设置活动的启动模式

<activity android:name=".Main23Activity"
    android:launchMode="singleTop">
</activity>


一共有四种启动模式:

一、standard,Android默认的启动模式,对于这种活动,每次启动都会创建一个新的实例到返回栈中。

二、singleTop,对于这种模式的活动,启动时会先去返回栈栈顶中检查是否是这个活动,是的话就直接使用它,否则就会创建新的实例。

三、singleTask,对于这种模式的活动,只要返回栈中存在这个活动,都会启用它,如果没有才会创建新的实例。

四、singleInstance,对于这种模式的活动,会使用一个单独的返回栈来管理这种活动。

图片.png


Android的活动是可以层叠的。Android使用任务(Task)来管理活动,一个任务就是一组存放在栈里的活动的集合,这个栈叫做返回栈。

图片.png


活动类中定义了7个回调方法,覆盖了活动生命周期的每一个环节。

onCreate(),它会在活动第一次被创建的时候调用,在这里完成活动的初始化操作,比如加载布局、绑定事件等。

onStart(),它会在活动由不可见变为可见的时候调用。

onResume(),它会在活动准备好和用户交互的时候调用。此时活动一定位于返回栈的栈顶,并且处于运行状态。

onPause(),这个方法在系统准备去启动或恢复另一个活动的时候调用。通常做一些释放资源和保存关键数据的操作,执行速度要快。

onStop(),这个方法在活动完全不可见的时候调用,和onPause的主要区别在于,启动的活动为对话框时,onPause会执行,onStop不会执行

onDestroy(),这个方法在活动被销毁之前调用,之后活动的状态将变为销毁状态。

onRestart(),这个方法在活动由停止状态变为运行状态之前调用,也就是活动被重新启动了。

图片.png


一、向下一个活动传递数据

Button button3 = (Button) findViewById(R.id.button3);
button3.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent intent = new Intent(Main2Activity.this,Main23Activity.class);
        intent.putExtra("name","chicai");//向intent添加参数,key,value形式
        startActivity(intent);
    }
});
public class Main23Activity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main23);
        Intent intent = getIntent();
        TextView text = (TextView) findViewById(R.id.textView);
        text.setText(intent.getStringExtra("name"));
    }
}



二、向上一个活动传递数据

Button button3 = (Button) findViewById(R.id.button3);
button3.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent intent = new Intent(Main2Activity.this,Main23Activity.class);
        intent.putExtra("name","chicai");
        startActivityForResult(intent,1);//意思了开启一个活动用来获取结果的,1是用来辨识不同的这种Activity
    }
});
//用这个活动设置返回结果,然后结束就会传递到上一个活动了
public class Main23Activity extends AppCompatActivity {
    @Override
    protected void onStart() {
        super.onStart();
        Button button = (Button)findViewById(R.id.button7);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                intent.putExtra("return_val","memeda");
                setResult(RESULT_OK,intent);//设置结果
                finish();
            }
        });
    }
}
//返回上一个活动,通过onActivityResult接收
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch(requestCode)
    {
        case 1:
            if(resultCode == RESULT_OK)
            {
                String str = data.getStringExtra("return_val");
                TextView text = (TextView) findViewById(R.id.textView2);
                text.setText(str);
            }
            break;

    }
}