N_Android

1.Activity

文档

活动代表了一个具有用户界面的单一屏幕, 如 Java 的窗口或者帧.Android 的活动是 ContextThemeWrapper 类的子类.

如果你曾经用 C,C++ 或者 Java 语言编程, 你应该知道这些程序从 main() 函数开始.很类似的, Android 系统初始化它的程序是通过活动中的 onCreate() 回调的调用开始的.存在有一序列的回调方法来启动一个活动, 同时有一序列的方法来关闭活动,

Activity 是与用户交互的入口点.它表示拥有界面的单个屏幕.例如, 电子邮件应用可能有一个显示新电子邮件列表的 Activity 一个用于撰写电子邮件的 Activity 以及一个用于阅读电子邮件的 Activity.

尽管这些 Activity 通过协作在电子邮件应用中形成一种紧密结合的用户体验, 但每个 Activity 都独立于其他 Activity 而存在.因此, 其他应用可以启动其中任何一个 Activity (如果电子邮件应用允许) . 例如, 相机应用可以启动电子邮件应用内用于撰写新电子邮件的 Activity, 以便用户共享图片.

Android 开发指南 >Activity

注册

AndroidManifest.xml 注册

  <activity
    android:name=".MainActivity"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <action android:name="FROM_BOOT" />
        <!-- 意图过滤 , 从LAUNCHER启动 必须!-->
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
  • 声明 intent 过滤器 Intent 过滤器是 Android 平台的一项非常强大的功能.借助这项功能, 您不但可以根据显式请求启动 Activity, 还可以根据隐式请求启动 Activity.

例如, 显式请求可能会告诉系统”在 Gmail 应用中启动‘发送电子邮件’Activity”, 而隐式请求可能会告诉系统”在任何能够完成此工作的 Activity 中启动‘发送电子邮件’屏幕”.当系统界面询问用户使用哪个应用来执行任务时, 这就是 intent 过滤器在起作用.

代码

public class MainActivity extends AppCompatActivity  {
    private static final String TAG =  "MainActivity";
    public static final String FROM_BOOT = "FROM_BOOT";
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        UncaughtHandler.getInstance().init(this);
        //在锁屏 界面 显示
//        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
//                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
        setContentView(R.layout.activity_main);
        //start
        final Intent intent = new Intent(this, LinstenService.class);
        startService(intent);
 
    //scan
        Button but_scan = (Button) findViewById(R.id.but_scan);
        but_scan.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                IntentIntegrator integrator =  new IntentIntegrator(MainActivity.this);
                // 设置要扫描的条码类型, ONE_D_CODE_TYPES: 一维码, QR_CODE_TYPES-二维码
                integrator.setDesiredBarcodeFormats(IntentIntegrator.ONE_D_CODE_TYPES);
                integrator.setCaptureActivity(ScanActivity.class);
                integrator.setPrompt("请扫描条形码"); //底部的提示文字, 设为""可以置空
                integrator.setCameraId(0); //前置或者后置摄像头
                integrator.setBeepEnabled(true); //扫描成功的「哔哔」声, 默认开启
                integrator.setBarcodeImageEnabled(true);
                integrator.initiateScan();
            }
        });
      
    }
 
 
    @Override
    protected void onStart() {
       
    }
 
    public  void onActivityResult(int requestCode, int resultCode, Intent data) {
//        IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
//        String result = scanResult.getContents();
       // Toast.makeText(this, "TTT result="+result, Toast.LENGTH_SHORT).show();
        /*
        if (result != null) {
            Intent it2 = new Intent(this, SampleViewActivity.class);
            //Toast.makeText(this, "result="+result, Toast.LENGTH_SHORT).show();
            Log.i(TAG, "scan result = "+result);
            it2.putExtra("barCode", result);
            startActivity(it2);
        }*/
    }
 
 
    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
 
}

回调 描述 onCreate() 这是第一个回调, 在活动第一次创建时调用 onStart() 这个回调在活动为用户可见时被调用 onResume() 这个回调在应用程序与用户开始可交互的时候调用 onPause() 被暂停的活动无法接受用户输入, 不能执行任何代码.当前活动将要被暂停, 上一个活动将要被恢复时调用 onStop() 当活动不在可见时调用 onDestroy() 当活动被系统销毁之前调用 onRestart() 当活动被停止以后重新打开时调用

Activity 的交互

一个交互 例子

  • 传递参数 启动
Intent confIntent = new Intent(this, ConfigActivity.class);
confIntent.putExtra("id","123");
startActivity(confIntent);
  • 另外一边 接受 String id = this.getIntent().getStringExtra("id");
  1. 通过一个意图对象(Intent) Intent.putExtra(key,val)传参startActivity(confIntent)启动 Activity (亦可以启动其他组件, 例如服务startService(intent);),
  2. Activity 结束后通过setResult(int resultCode, Intent data)返回结果,
  3. 上一个Activity结束后, 通过onActivityResult(int requestCode, int resultCode, Intent data) 得到结果

使用 Bundle 绑定参数

如果是要从A界面传到B界面, B界面要再传到C界面, Intent就要写两遍添加值的方法 那么 如果我用1个Bundle 直接把值先存里边 然后再存到Intent中 不就更简洁吗?

//传递参数 启动

Intent intent = new Intent(this, ConfigActivity.class);
Bundle bundle = new Bundle();  
bundle.putString("key1", value1);  
bundle.putString("key2", value2);
intent.putExtras(bundle);
startActivity(bundle);
 
///////////////////////////////////////////
Intent resultIntent = new Intent();
resultIntent.putExtra("key", "value"); // 设置需要返回的数据,可根据需要添加数据
 
// 将数据设置到结果Intent中,并指定结果码(RESULT_OK通常表示操作成功)
setResult(Activity.RESULT_OK, resultIntent);
 
// 结束当前Activity并返回结果Intent
finish();

//另外一边 接受

Bundle bundle = this.getIntent().getExtras();  
String v = bundle.getString("key1");

一个调用系统拍照Activity的例子

 
//启动
Intent intentCamer = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);// MediaStore.ACTION_IMAGE_CAPTURE 系统拍照Activity 常量
String filePath = "/sdcard/" + System.currentTimeMillis() + ".jpg";//要保存照片的绝对路径
try {
    ContentValues contentValues = new ContentValues(2);
    contentValues.put(MediaStore.Images.Media.DATA, filePath);
    //如果想拍完存在系统相机的默认目录,改为
    //contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, "111111.jpg");
    contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
 
    Uri mPhotoUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
    intentCamer.putExtra(MediaStore.EXTRA_OUTPUT, mPhotoUri);
    startActivityForResult(intentCamer,0);
}catch(SecurityException e){
    Toast.makeText(MainActivity.this, "没有权限,访问相机.", Toast.LENGTH_LONG).show();
}
 
//接受结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    Bitmap bitmap= null;
    if (data!= null && data.getData() == null) {
        //获取到的是Thumbnail所以会很小.但是你传了output路径进去, output路径在拍完照会被写入图片数据
        bitmap = (Bitmap) data.getExtras().get("data");
        ImageView imageView = (ImageView) findViewById(R.id.imageView);
        imageView.setImageBitmap( bitmap);
        Log.i(TAG, "height="+  bitmap.getHeight()+", width="+ bitmap.getWidth());
    }
}
 

需要 访问相机 和 读写文件权限

新API

在Android SDK 23中,startActivityForResultonActivityResult,已经被官方标记为弃用了,继而推出了名为Activity Result API的组件。

ActivityResultLauncher<Intent> activityLauncher = registerForActivityResult(
    new ActivityResultContracts.StartActivityForResult(),
    result -> {
        if (result.getResultCode() == Activity.RESULT_OK) {
            // 处理返回的数据
            Intent data = result.getData();
            // 可以在这里处理返回的Intent中的数据
        }
    }
);
 
// 启动目标Activity并处理返回结果
Intent intent = new Intent(this, YourSecondActivity.class);
activityLauncher.launch(intent);

自定义组件

  • xml布局指定类名
 <com.journeyapps.barcodescanner.DecoratedBarcodeView
            android:id="@+id/dbv_custom"
            android:layout_width="match_parent"
            android:layout_height="150dp"
            app:zxing_preview_scaling_strategy="fitXY" />
 
  • 然后继承 安卓组件, 它会回调事件以及方法

注意要重写几个有参构造

class DecoratedBarcodeView extends FrameLayout{
 
 
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
    }
}

参考 Android-自定义控件开发

获取xml的属性

public MyImageButton(Context context, AttributeSet attrs) {
    super(context, attrs);
    //第一个参数命名空间, 
    /*取得资源ID号,第一个参数:命名空间名.第二个参数:xml文件里设置的属性名.第三个参数:默认值*/  
    final String xmlns="http://schemas.android.com/apk/res/android";
    int resouceId = attrs.getAttributeResourceValue(xmlns, "text", -1);
    if(resouceId > 0)
        text = context.getResources().getText( resouceId).toString();//xml里 要通过引用的方式 @string/xxx
}
 
 

一个手写面板的自定义控件实现

组件源码

搞活动签名的项目源码

  • 使用
 <com.joinken.group.activity.HandWritePanel
                android:id="@+id/hwp"
                android:layout_width="wrap_content"
                android:layout_height="250dp"
                android:background="@drawable/sign_bg" />
 
HandWritePanel hwp
//找到 实例
hwp = (HandWritePanel) findViewById(R.id.hwp);
 
/**
* 保存图片到SD卡上
*/
protected boolean saveBitmap(String fileName) {
    boolean ret = false;
    FileOutputStream stream = null;
    Bitmap baseBitmap = hwp.getPic();
    try {
        // 保存图片到SD卡上
        File file = new File(fileName);
        stream = new FileOutputStream(file);
        baseBitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
//            Toast.makeText(SignActivity.this, "保存成功", Toast.LENGTH_LONG).show();
        ret = true;
    } catch (Exception e) {
        Toast.makeText(SignActivity.this, "保存失败!"+e.getMessage(), Toast.LENGTH_LONG).show();
    }finally{
        try {
            stream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return ret;
}
 
//清除
  hwp.clean();

Activity 多xml布局 查找控件

 
LayoutInflater layout=this.getLayoutInflater();
View view=layout.inflate(R.layout.layout_sample_view, null);//代码新建布局
setContentView(view);//在设置完布局后
 
//指定在这个view 中查找
EditText editText = view.findViewById(R.id.id_);
editText.setText(bean.getId());