Android 官网Train阅读记录——2

LZ阅读的是中文翻译版本:http://hukai.me/android-training-course-in-chinese/basics/activity-lifecycle/recreating.html,试验机系统版本7.1。

1.5 使用Fragment建立动态的UI

1.5.1 创建Fragment

创建Fragment要继承自Fragment,一般,为了兼容低版本,要继承v4包中的Fragment。

有两种方式向Activity的视图中添加Fragment:

1、直接在Activity的布局xml文件中通过标签(fragment)的方式,通过android:name属性指明引用的是哪个Fragment,其值是要引用的Fragment的全类名。

2、在Activity的代码中通过FragmentManager添加。


1.5.2 建立灵活动态的UI

在小屏幕的设备上,如手机,通常需要替换Fragment来达到较好的user experience,而大屏幕,如平板,或者是横屏的设备上,则可以一次横放两个,甚至更能多的Fragment。

所以,如果一个App要适配不同尺寸的设备,就要通过 Android 官网Train阅读记录——1提到的各种适配方法来适配了。

如果一个新闻app想同时运行在手机和平板上,并保持很好的用户体验,达到在手机上单屏单窗,在平板上单屏双窗的效果,就需要为同一个Activity建立两个xml布局文件,例如:

其中在手机上的布局文件名为res/layout/news.xml,而在平板上的布局文件名为res/layout-large/news.xml。

在前一个布局文件中可以只有一个FrameLayout作为动态替换Fragment的容器,而在后面的文件中,可以固定的添加两个<Fragment>标签。

在Activity的代码中可以动态的通过查询FrameLayout容器是否存在,判断该设备是小屏幕还是大屏幕,这样在不同的布局中做不同的操作,就可以达到在手机上单屏单窗,在平板上单屏双窗的效果。


如果要让Fragment想Activity一样存入backstack,必须手动调用addToBackStack方法,此方法由FragmentTransaction所有,并且需要在FragmentTransaction调用commit之前调用才行。


1.5.3 Fragments之间以及Fragment和Activity之间的交互

Fragments之间不提倡直接进行交互,这样耦合性严重,可复用性差。所以,Fragments之间的交互通常通过Fragment与Activity之间的交互来完成。

Fragment和Activity之间的交互:

Activity可以通过Fragment的setArguments方法向Fragment传递消息。

Fragment可以通过自定义回调接口,让包含它的Activity实现,来完成向Activity传递消息。Fragment通过onAttach方法或者getActivity方法获取Activity的引用然后转换成相应的接口对象,这样在Fragment中调用接口的方法,通过向该方法传递参数,以达到向Activity传递消息的目的。


Fragment可以向ActionBar中添加Menu Item,实现方式为:复写onCreateOptionsMenu方法,并在onCreate方法中调用setHasOptionsMenu(true),来达到目的,然后通过复写onOptionsItemSelected方法监听按钮的点击事件。



1.6 数据保存

1.6.2 保存到文件

数据可以保存到internal storage或者external storage,保存到external storage需要WRITE_EXTERNAL_STORAGE权限。

保存到internal可以

File file = new File(context.getFilesDir(), filename);
或者

String filename = "myfile";
String string = "Hello world!";
FileOutputStream outputStream;

try {
  outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
  outputStream.write(string.getBytes());
  outputStream.close();
} catch (Exception e) {
  e.printStackTrace();
}
保存到internal的文件在app卸载的时候,会被系统随之移除。


保存到external之前需要验证external storage是否可用

 /* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}

/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) ||
        Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}

保存到external分两种:

不想让文件随app卸载而被系统移除可以

File file = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), albumName);

其中DIRECTORY_PICTURES表示该目录存放的是照片,其他还有音乐,铃声等等类型,具体可以自行查阅。

要让文件随app卸载而被系统移除可以

 File file = new File(context.getExternalFilesDir(
            Environment.DIRECTORY_PICTURES), albumName);


若文件是保存在internal storage的,可以用下面的方式删除文件

myContext.deleteFile(fileName);


1.6.3 保存到数据库

通过实现BaseColumns接口,创建包含表名和列名的类,其他的关于表的创建、增删改查操作使用该类即可

public final class FeedReaderContract {
    // To prevent someone from accidentally instantiating the contract class,
    // give it an empty constructor.
    public FeedReaderContract() {}

    /* Inner class that defines the table contents */
    public static abstract class FeedEntry implements BaseColumns {
        public static final String TABLE_NAME = "entry";
        public static final String COLUMN_NAME_ENTRY_ID = "entryid";
        public static final String COLUMN_NAME_TITLE = "title";
        public static final String COLUMN_NAME_SUBTITLE = "subtitle";
        ...
    }
}


1.7 与其他应用的交互

1.7.1 Intent的发送

拨号

Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
看网页

Uri webpage = Uri.parse("http://www.android.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
创建日历事件

Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30);
Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 10, 30);
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis());
calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis());
calendarIntent.putExtra(Events.TITLE, "Ninja class");
calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");


验证是否有app接受Intent

PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isIntentSafe = activities.size() > 0;
如果接受Intent的app不止一个,强制用户选择

Intent intent = new Intent(Intent.ACTION_SEND);
...

// Always use string resources for UI text. This says something like "Share this photo with"
String title = getResources().getText(R.string.chooser_title);
// Create and start the chooser
Intent chooser = Intent.createChooser(intent, title);
startActivity(chooser);

1.7.3 Intent过滤

如果要让其他app能够调用我们自己写的app,我们需要为被调用的Activity添加Intent-filter。若Activity中的intent-filter满足以下Intent对象的标注,系统就能够把特定的Intent发送给Activity:

Action:一个想要执行的动作的名称。通常是系统已经定义好的值,如ACTION_SEND或ACTION_VIEW。在Intent-filter中通过<action>标签指定它的值,值的类型必须为字符串。

Data:Intent附带数据的描述。在Intent-filter中通过<data>指定它的值,可以使用一个或者多个属性,我们可以只定义MIME type或者是只指定URI prefix,也可以只定义一个URI scheme,或者是它们综合使用。

Category:提供一个附加的方法来标识这个Activity能够handle的Intent。通常与用户的手势或者是启动位置有关。系统有支持几种不同的Category,但是大多数都很少用到。而且,所有的implicit intents都默认是CATEGORY_DEFAULT类型的。在Intent-filter中用<category>指定它的值。

例子

<activity android:name="ShareActivity">
    <intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain"/>
        <data android:mimeType="image/*"/>
    </intent-filter>
</activity>
一个Intent-filter可以有多个action、category或者data。一个Activity可以有多个Intent-filter。

在Activity中Handle发送过来的Intent

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    // Get the intent that started this activity
    Intent intent = getIntent();
    Uri data = intent.getData();

    // Figure out what to do based on the intent type
    if (intent.getType().indexOf("image/") != -1) {
        // Handle intents with image data ...
    } else if (intent.getType().equals("text/plain")) {
        // Handle intents with text ...
    }
}
返回Result

 // Create intent to deliver some kind of result data
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri");
setResult(Activity.RESULT_OK, result);
finish();


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值