比赛训练笔记 - Android

编程 · 2023-07-12

屏幕旋转

检测屏幕方向:

int orientation = getResources().getConfiguration().orientation;
boolean landscape = (orientation == Configuration.ORIENTATION_LANDSCAPE);

强制Activity横屏

AndroidManifest里给Activity标签添加属性:

android:screenOrientation="landscape"

切换时自动重建

创建layout时在Qualifier列表中添加Orientation属性。调用R.layout.xxx时会自动根据屏幕方向选择对应的layout。

Orientation Qualifier

切换横竖屏时Activity会自动重建。

  • 保存数据:覆盖onSaveInstanceState(outState:Bundle),往Bundle里写入数据
  • 恢复数据:从onCreate(savedInstanceState:Bundle?)参数中读取数据
    [info]可以把要保留的数据存在模型类中。
    模型类实现Serializable接口,模型类中的其他模型类也要实现。[/info]

切换时不重建

AndroidManifest里给Activity标签添加属性:

android:configChanges="orientation|screenSize"

表明在方向和屏幕大小改变时不要重建Activity,而是调用onConfigChanged方法。

媒体相关

包含拍照、录像、选择文件的操作。

基本流程:启动对应的Intent并startActivityForResult,结果在onActivityResult中返回。

拍照

  • Intent类型:MediaStore.ACTION_IMAGE_CAPTURE
  • 获取结果:

    • 获取拍照缩略图对象:data.getExtras().get("data")
    • 强制转换为Bitmap类型。
// 启动
Intent intent=new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, requestCode);

// 获取结果(在onActivityResult)
Bitmap bitmap = (Bitmap)data.getExtras().get("data");

选择文件:

  • Intent类型:Intent.ACTION_GET_CONTENT
  • 限制文件类型:intent.setType(mimeType)填入MIME类型

    • 图片:image/* image/png image/jpeg ...
    • 视频:video/* video/mp4 ...
  • 获取结果:

    • 获取URI:data.getData()
    • 获取输入流:getContentResolver().openInputStream(uri)
    • 转换为图片:BitmapFactory.decodeStream(inputStream)

选择图片

// 启动
Intent intent=new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, requestCode);

// 获取结果(在onActivityResult)
Uri uri=data.getData();
InputStream is = getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(is);

录像

  • Intent类型:MediaStore.ACTION_VIDEO_CAPTURE
  • 获取结果:

    • 获取URI:data.getData()
    • VideoView播放:videoView.setVideoURI(uri) videoView.start()
    • 获取输入流:getContentResolver().openInputStream(uri)
// 启动
Intent intent=new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
startActivityForResult(intent, requestCode);

// 获取结果(在onActivityResult)
Uri uri=data.getData();
videoView.setVideoURI(uri);
videoView.start();

ListView 点击事件失效

ListView 中某一行如果有按钮,那一行将无法使用 ListView 本身的 OnItemClick 事件。
原因是点击事件被按钮优先吃掉,到达不了 ListView,因此也无法触发 ListView 的 Item 点击事件。

解决方法:

  • 把点击事件做进适配器里,设置 View 的 OnClickListener。(推荐,RecyclerView 也已经移除了 OnItemClick 事件。)
  • (不推荐!hack 做法,可能随时被修复。)在适配器里给每个按钮设置setFocusable(false) setFocusableInTouchMode(false),能保留 ListView 点击动画。

Timer

使用 Timer.cancel() 取消 Timer 之后,这个 Timer 就无法再使用了。
如果要复用 Timer,就储存启动任务时创建的 TimerTask 对象,调用TimerTask.cancel()只取消这一个任务。
TimerTask 取消之后也无法再使用相同的对象了。启动新的任务时也要创建新的 TimerTask 对象。

检测是否联网

需要权限:

  • ACCESS_WIFI_STATE
  • ACCESS_NETWORK_STATE

首先获取ConnectivityManager:

ConnectivityManager cm;

cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);

检查是否连接上任何网络:

NetworkInfo info = cm.getActiveNetworkInfo();
boolean connected = info != null && info.isConnected();

ArrayAdapter相关坑

使用AutoCompleteTextView时,文本框内容改变之后,通过修改原始列表并使用notifyDataSetChanged更新数据,下拉框的自动补全项不会更新。

解决方法:ArrayAdapter中包含和List一样的操作方法(add、remove、clear等)。不要直接操作原始列表,只使用Adapter提供的方法来操作列表。(类似WinForm中的BindingList)

API

  • Json数组类型:JArray

配置请求体限制

Web.config文件中。

<system.web><httpRuntime>标签中添加属性:

  • maxRequestLength="1048576"(单位KiloByte)。
  • (可选)executionTimeout="3600"(单位秒),延长执行时间限制。

    <system.web>
      <httpRuntime targetFramework="4.7.2" maxRequestLength="1048576" executionTimeout="3600" />
    </system.web>

[warning]需要验证:在IIS7之后添加如下配置?上面设置的和下面设置的大小需匹配。[/warning]
<system.webServer><requestFiltering>标签中添加标签:

  • <requestLimits maxAllowedContentLength="1073741824">(单位Byte)

    <system.webServer>
      <security>
          <requestFiltering>
              <requestLimits maxAllowedContentLength="1073741824" />
          </requestFiltering>
      </security>
    </system.webServer>

请求体直接传输二进制

Android端设置好Content-Type,直接把二进制流完整写入outputStream。

API端从Request中提取Content,读取出byte[]。
因为使用到异步方法,所以需要设置方法为async,返回值为Task。await异步方法。

var body = Request.Content;
var bodyBytes = await body.ReadAsByteArrayAsync();

映射服务器路径

var path = HttpContext.Current.Server.MapPath($"~/path");

目录符号:

  • ~:应用程序根目录
  • .:当前页面根目录
  • ..:当前页面的父目录

报错

1

global.asax 报错 Could not load type [Application类型]

是因为项目没有成功编译导致的。

2

The route template separator character '/' cannot appear consecutively. It must be separated by either a parameter or a literal value.

是因为某个函数的路由中包含了连续的(consecutively)两个/。例如某个[Route]路径以/开头了。例如:

[Route("/requested-by/{uid:int}")]

改成

[Route("requested-by/{uid:int}")]

3

The inline constraint resolver of type 'DefaultInlineConstraintResolver' was unable to resolve the following inline constraint: 'uid'.

是因为某个Route中写的路径参数有问题。例如:

[Route("requested-by/{int:uid}")]

改成

[Route("requested-by/{uid:int}")]

Route路劲参数的格式是名称:类型,如果类型是string,就不需要写:类型的部分,只需要写名称。

Android Java 笔记 C#
Theme Jasmine by Kent Liao