Android开发者文档笔记(一)

Android开发者文档学习笔记
******************************************************************


**支持不同的语言:


*要使app兼容多种语言的设备,可以在res文件夹下建立不同的values子文件夹,在里面放置你的string,color,dimensions等xml文件
不同语言的values命名格式详见:
http://blog.csdn.net/lllkey/article/details/9350977


工程目录结构如下:
MyProject/
    res/
       values/
           strings.xml
       values-es/
           strings.xml
       values-fr/
           strings.xml


******************************************************************


**支持不同的屏幕:


*要使app兼容不同的屏幕,可以在res文件夹下建立不同的layout子文件夹,如layout(默认竖屏-portrait),layout-large,layout-land(横屏布局),layout-large-land

结构如下:


MyProject/
    res/
        layout/              # default (portrait)
            main.xml
        layout-land/         # landscape
            main.xml
        layout-large/        # large (portrait)
            main.xml
        layout-large-land/   # large landscape
            main.xml




******************************************************************
**支持不同的设备:


*在使用Android Support Library时,必须检查系统版本,代码如下:

private void setUpActionBar() {
    // Make sure we're running on Honeycomb or higher to use ActionBar APIs
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        ActionBar actionBar = getActionBar();
        actionBar.setDisplayHomeAsUpEnabled(true);
    }
}




这样做了,不会因为系统版本不对,而导致程序崩溃


*在AndroidManifest.xml中可以修改themes和styles

******************************************************************
**管理Activity生命周期


*在AnroidManifest.xml中申明的启动器Activity中必须申明intent.action.MAIN和intent.category.LAUNCHER过滤,不然的话,将不会显示桌面图标且在程序列表中不会显示,意味着没有入口


*Activity的生命周期中,只有onResumed,onStopped,onPaused中有长时间的过程,称之为静态,而created,started,destroyed这三个阶段都是瞬间过程
继续
在这种状态下,Activity处于前台,且用户可以与其交互。(有时也称为“运行”状态。)
暂停
在这种状态下,Activity被在前台中处于半透明状态或者未覆盖整个屏幕的另一个Activity—部分阻挡。 暂停的Activity不会接收用户输入并且无法执行任何代码。
停止
在这种状态下,Activity被完全隐藏并且对用户不可见;它被视为处于后台。 停止时,Activity实例及其诸如成员变量等所有状态信息将保留,但它无法执行任何代码。




*Activity解决的问题:
如果用户在使用您的应用时接听来电或切换到另一个应用,它不会崩溃。
在用户未主动使用它时不会消耗宝贵的系统资源。
如果用户离开您的应用并稍后返回,不会丢失用户的进度。
当屏幕在横向和纵向之间旋转时,不会崩溃或丢失用户的进度。


*Activity中,如果把密度度高的操作放在pause阶段,可能影响系统对下一个Acitity的过度速度。且resume,start,pause(大多数情况下)是可视化的。


*Activity中,created阶段处理的问题:
创建一个实例,实现生命周期中出现一次的基本应用启动逻辑(用户界面,实例化某些变量,配置UI以及一些需要响应UI的监听业务逻辑)


*Activity中,started阶段处理的问题:
在这个方法中,实例化那些需要在Stopped方法中销毁的可能导致内存泄漏的资源。还须注意的是,在内存紧张的情况下,系统可能也不会执行onStop()方法,这个跟使用finish()直接结束Activity的情况有些类似。


*Activity中,resumed阶段处理的问题:
在这个方法中,由于只有从started开始才可能是可视化的,而started这个阶段又是瞬间的,所以可以在这个阶段有关以View界面为基础的那些关于UI的效果,比如动画。打开独立设备(照相机),最后在paused阶段释放;


*Activity中,paused阶段处理的问题:
使用的场景:前台Activity有时会被其他导致Activity暂停的可视组件阻挡。 例如,当半透明Activity打开时(比如对话框样式中的Activity),上一个Activity会暂停。 只要Activity仍然部分可见但目前又未处于焦点之中,它会一直暂停。
处理的业务:
*a.停止不应在暂停时继续的进行之中的操作(比如视频)或保留任何应该永久保存的信息,以防用户坚持离开应用;


*b.停止动画或其他可能消耗 CPU 的进行之中的操作。
*c.提交未保存的更改,但仅当用户离开时希望永久性保存此类更改(比如电子邮件草稿)。
*d.释放系统资源,比如广播接收器、传感器手柄(比如 GPS) 或当您的Activity暂停且 用户不需要它们时仍然可能影响电池寿命的任何其他资源。


*Activity中,stopped阶段处理的问题:
调用onStopped方法后,它就不再可见,并且释放用户不使用时不需要的资源,解放可能导致内存泄漏的资源。比如:将草稿笔记本的内容永久保存在内存中




*Activity中,destroyed阶段处理的问题:
Activity包含您在 onCreate() 期间创建的后台线程或其他如若未正确关闭可能导致内存泄露的长期运行资源,您应在 onDestroy() 期间终止它们。




*思维拓展:
看到这几个生命周期的阶段,会发现,有好几个地方的业务似乎是有重叠的。深究了下,其实,重叠是必然的,举个例子,如果你仅仅是把当前的Acitivity压栈了,实例化的对象其实还是存在于内存中,这时,这个Activity并没有调用onDestroyed()方法,如果你只是在onDestroyed()方法释放那些可能导致内存泄漏的资源,就有可能执行不了代码而引发内存泄漏的风险。同理,created对应destroyed,started对应stopped。之前开发时,一直不是很理解,什么样的业务要放在onStart()方法中进行,现在其实显而易见,因为你的那些可能导致内存泄漏的资源,在不销毁Activity实例的前提下,会在onStopped()方法中被销毁,如果你onRestart这个Activity,必然会使这些资源找不到,因此,需要在onStart()中重新实例化,重新引用。而且,假设在onCreate()方法中,你直接是这个Activity finished了,那么系统是不会调用下面三个阶段,而是直接进入onDestroy()方法中,所以,在销毁阶段,也需要对可能导致内存泄漏的资源进行销毁。这样想想, 这五个阶段是非常科学的。之前,是因为没有接触到这种必要资源的把控,所以,对这个概念不是很清楚,特此记录。




*Activity重新创建:


如果要使每个View可以在系统恢复中恢复状态,每个视图就必须要有唯一id。其次是,除了View需要保存的状态信息,还有一些变量也需要保存,这就在销毁是用onSaveInstanceState()——默认保存View的状态,将需要保存的信息以键值对的方式存入Bundle;在后面需要重新创建Activity对象时,将相同的Bundle对象同时传递给onRestoreInstanceState()和onCreate()方法:

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...


@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
    
    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}





如果要在onCreate()方法中恢复数据时,必须先判断Bundle是否为null,然后在手动加载:


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first
   
    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        // Restore value of members from saved state
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance
    }
    ...
}





而onRestoreInstanceState()是在onStart()方法后进行,并且只有在需要恢复数据状态的情况下才会被调用,所以不需要检验Bundle对象是否为null:

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);
   
    // Restore state members from saved instance
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}




******************************************************************
**使用Fragment创建动态UI


*在高于API11的系统版本中,可以直接使用框架中的Fragment类,反之可以使用位置支持库中的FragmentActivity这个类




*对于Fragment切换后的重新实例化,必须从新加载数据问题:
*a.通过使用add,hide,show等方法,进行切换,这种是利用容器的内容可以重叠的原理实现的,不过我个人认为,这种方法,只能用于切换的Fragment比较少的情况下,并且碎片内容不复杂的情况,因为覆盖意味着资源并没有释放。


   public void switchContent(Fragment from, Fragment to) {
        if (mContent != to) {
            mContent = to;
            FragmentTransaction transaction = mFragmentMan.beginTransaction().setCustomAnimations(
                    android.R.anim.fade_in, R.anim.slide_out);
            if (!to.isAdded()) {    // 先判断是否被add过
                transaction.hide(from).add(R.id.content_frame, to).commit(); // 隐藏当前的fragment,add下一个到Activity中
            } else {
                transaction.hide(from).show(to).commit(); // 隐藏当前的fragment,显示下一个
            }
        }
    }



*b.通过重写onSavedInstanceState()方法,保存数据,但是不需要继承超类


*c.把Fragment的UI和数据分离,在切换Fragment时,只是后端服务的不同




public class UIFragment extends Fragment{


  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment,
        container, false);
    return view;
  }
  ...
}


public class HeadlessFragment extends Fragment{


  @Override
  public void onCreate(Bundle savedInstanceState) {
    setRetainInstance(true);
  }
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    return null;
  }
  ...
}





前者是指一般的定义了UI的Fragment,后者则是无UI的Fragment,即在onCreateView()中返回的是null。将与UI处理无关的异步任务都可以放到后者中,而且一般地都会在onCreate()中加上setRetainInstance(true),故而可以在横竖屏切换时不被重新创建和重复执行异步任务。
这样做了之后,便可以不用管UI Fragment的重新创建与否了,因为数据和异步任务都在无UI的Fragment中,再通过Activity 的 FragmentManager 交互即可。
只需记得在Headless Fragment销毁时将持有的数据清空、停止异步任务。




*当你执行替换或移除 Fragment 等 Fragment 事务时,最好能让用户向后导航和“撤消”所做更改。要通过 Fragment 事务允许用户向后导航,你必须调用 addToBackStack(),然后再执行 FragmentTransaction。因为当你移除或替换 Fragment 并向返回堆栈添加事务时,已移除的 Fragment 会停止(而不是销毁)。如果用户向后导航,还原该 Fragment,它会重新启动。如果你没有向返回堆栈添加事务,那么该 Fragment 在移除或替换时就会被销毁。




*Activity与Fragment进行通信:
通过使用回调接口的方式,在Fragment中声明一个需要重写的接口,然后在Activity中重写


public class HeadlinesFragment extends ListFragment {
    OnHeadlineSelectedListener mCallback;


    // Container Activity must implement this interface
    public interface OnHeadlineSelectedListener {
        public void onArticleSelected(int position);
    }


    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        
        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mCallback = (OnHeadlineSelectedListener) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnHeadlineSelectedListener");
        }
    }
    
    ...
}








public static class MainActivity extends Activity
        implements HeadlinesFragment.OnHeadlineSelectedListener{
    ...


    public void onArticleSelected(int position) {
        // The user selected the headline of an article from the HeadlinesFragment
        // Do something here to display that article


        ArticleFragment articleFrag = (ArticleFragment)
                getSupportFragmentManager().findFragmentById(R.id.article_fragment);


        if (articleFrag != null) {
            // If article frag is available, we're in two-pane layout...


            // Call a method in the ArticleFragment to update its content
            articleFrag.updateArticleView(position);
        } else {
            // Otherwise, we're in the one-pane layout and must swap frags...


            // Create fragment and give it an argument for the selected article
            ArticleFragment newFragment = new ArticleFragment();
            Bundle args = new Bundle();
            args.putInt(ArticleFragment.ARG_POSITION, position);
            newFragment.setArguments(args);
        
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();


            // Replace whatever is in the fragment_container view with this fragment,
            // and add the transaction to the back stack so the user can navigate back
            transaction.replace(R.id.fragment_container, newFragment);
            transaction.addToBackStack(null);


            // Commit the transaction
            transaction.commit();
        }
    }

//ListView的Item监听事件
    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        // Send the event to the host activity
        mCallback.onArticleSelected(position);
    }




}




******************************************************************
**数据保存


*使用Sharedpreference保存数据

//reference
Context context = getActivity();
SharedPreferences sharedPref = context.getSharedPreferences(
        getString(R.string.preference_file_key), Context.MODE_PRIVATE);


//write
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt(getString(R.string.saved_high_score), newHighScore);
editor.commit();


//read
SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
int defaultValue = getResources().getInteger(R.string.saved_high_score_default);
long highScore = sharedPref.getInt(getString(R.string.saved_high_score), defaultValue);




*存储器保存数据时,内部存储的数据在应用卸载时会删除,而外部存储不会。当用户卸载您的应用时,只有在您通过 getExternalFilesDir() 将您的应用的文件保存在目录中时,系统才会从此处删除您的应用的文件。




*标准I/O流的文件操作:
//get file
getFilesDir()
返回表示您的应用的内部目录的 File 。
getCacheDir()
返回表示您的应用临时缓存文件的内部目录的 File 。 务必删除所有不再需要的文件并对在指定时间您使用的内存量实现合理大小限制,比如,1MB。 如果在系统即将耗尽存储,它会在不进行警告的情况下删除您的缓存文件。
File file = new File(context.getFilesDir(), filename);




//write
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();
}


//create tempCacheFile
public File getTempFile(Context context, String url) {
    File file;
    try {
        String fileName = Uri.parse(url).getLastPathSegment();
        file = File.createTempFile(fileName, null, context.getCacheDir());
    catch (IOException e) {
        // Error while creating file
    }
    return file;
}




*SQL数据库:
http://developer.android.com/intl/zh-cn/training/basics/data-storage/databases.html


*判断Intent所指向的Activity是否存在:
要确认是否存在可响应意向的可用Activity,请调用 queryIntentActivities() 来获取能够处理您的Intent 的Activity列表。 如果返回的 List 不为空,您可以安全地使用该意向。例如:


PackageManager packageManager = getPackageManager();
List activities = packageManager.queryIntentActivities(intent,
        PackageManager.MATCH_DEFAULT_ONLY);
boolean isIntentSafe = activities.size() > 0;






// Build the intent
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);


// Verify it resolves
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);
boolean isIntentSafe = activities.size() > 0;


// Start an activity if it's safe
if (isIntentSafe) {
    startActivity(mapIntent);
}





*显示应用选择器:
使用场景:在一个URL链接点击时,如果你的系统有多个浏览器,此时,选择器就会提供列表

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().getString(R.string.chooser_title);
// Create intent to show chooser
Intent chooser = Intent.createChooser(intent, title);


// Verify the intent will resolve to at least one activity
if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(chooser);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值