3.App Resources-Handling Runtime Changes

Reference : http://blog.csdn.net/aliaooooo/article/details/23606179

 

1. Handling Runtime Changes

  Some device configurations can change during runtime (such as screen orientation, keyboard availability, and language). When such a

    change occurs, Android restarts the running Activity(onDestroy() is called, followed by onCreate()). The restart behavior is designed to

    help your application adapt to new configurations by automatically reloading your application with alternative resources that match the

    new device configuration.

  To properly handle a restart, it is important that your activity restores its previous state through the normal Activity lifecycle, in which

    Android calls onSaveInstanceState() before it destroys your activity so that you can save data about the application state. You can then

    restore the state during onCreate() or onRestoreInstanceState().

  However, you might encounter a situation in which restarting your application and restoring significant amounts of data can be costly and

    create a poor user experience. In such a situation, you have two other options:

  <1>Retaining an Object During a Configuration Change

  <2>Handle the configuration change yourself

 

2. Retaining an Object During a Configuration Change

  If restarting your activity requires that you recover large sets of data, re-establish a network connection, or perform other intensive

    operations, then a full restart due to a configuration change might be a slow user experience.

  Also, it might not be possible for you to completely restore your activity state with the Bundle that the system saves for you with the

    onSaveInstanceState() callback—it is not designed to carry large objects (such as bitmaps) and the data within it must be serialized then

    deserialized, which can consume a lot of memory and make the configuration change slow.

  In such a situation, you can alleviate the burden of reinitializing your activity by retaining a Fragment when your activity is restarted due to a   

    configuration change. This fragment can contain references to stateful objects that you want to retain.

  When the Android system shuts down your activity due to a configuration change, the fragments of your activity that you have marked to

    retain are not destroyed. You can add such fragments to your activity to preserve stateful objects.

 

  To retain stateful objects in a fragment during a runtime configuration change:

  <1> Extend the Fragment class and declare refrences to your stateful objects

  <2> Call setRetainInstance(boolean) when the fragment is created

  <3> Add the fragment to your activity

  <4> Use FragmentManager to retrieve the fragment when the activity is restarted

//ConfigurationChangeHandlerTest.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="mirror.android.configurationchangehandlertest.ConfigurationChangeHandlerTest" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="点击按钮启动线程模拟网络耗时操作,获取新闻详情显示在按钮下面" />
    
    <Button
        android:id="@+id/btn_createthread"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="获取娱乐新闻"/>
    
    <TextView
        android:id="@+id/tv_shownews"
        android:layout_width="match_parent"  
        android:layout_height="match_parent"
        android:textColor="@android:color/holo_green_dark"  />

</LinearLayout>
//ConfigurationChangeHandlerTest.java
package mirror.android.configurationchangehandlertest;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;


public class ConfigurationChangeHandlerTest extends Activity implements OnClickListener {

    private final String TAG = "ConfiguartionTest";
    private String newsInfo;
    
    private Button button;
    private TextView showNewsTextView;
    private ProgressDialog progressDialog;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_configuration_change_handler_test);
        
        button = (Button)findViewById(R.id.btn_createthread);
        button.setOnClickListener(this);
        showNewsTextView = (TextView)findViewById(R.id.tv_shownews);
        
        if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
            Log.i( TAG ,"----onCreate - landscape---");
        }
        else if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
            Log.i(TAG, "----onCreate - portrait ---");  
        } 
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.btn_createthread:
            excuteLongTimeOperation();
            break;
        }
    }

    private void excuteLongTimeOperation() {
        progressDialog = ProgressDialog.show(ConfigurationChangeHandlerTest.this
                                            , "Load Info"
                                            , "Loading"
                                            , true 
                                            , true);
        Thread workerThread = new Thread(new MyNewThread());
        workerThread.start();
    }
    
    class MyNewThread extends Thread{

        @Override
        public void run() {
            try {
                sleep(5000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            newsInfo = "10月20日,周杰伦御用作词人方文山在微博发声表示,周杰伦的第十三张专辑的所有歌曲已经录制完毕," +
                    "此次专辑会收录超过十首歌曲,预计12月发行。网友纷纷表示期待“小十三等待实在太不易了”。" +
                    "还有部分网友就之前蔡依林[微博]的新专辑《呸》调侃:杰伦新专辑名字是不是<<爱呸不呸>> ?";
            Message message = handler.obtainMessage();
            Bundle bundle = new Bundle();
            bundle.putString("message", newsInfo);
            message.setData(bundle);
            handler.sendMessage(message);
        }
    }
    
    private Handler handler = new Handler(){

        @Override
        public void handleMessage(Message msg) {
            progressDialog.dismiss();
            showNewsTextView.setText(newsInfo);
        }
    };

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.i(TAG, "----onConfigurationChanged---");  
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.i(TAG, "----onStart---");
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Log.i(TAG, "----onRestart---");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.i(TAG, "----onResume---");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.i(TAG, "----onPause---");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.i(TAG, "----onStop---");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "----onDestroy---");
    }
    
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.i(TAG, "----onSaveInstanceState---"); 
    }
}

  Run this appliction, then after sleep 5 seconds, show the news about "周杰伦". Then, change the Phone to landspace

     

  LogCat to observe

  

  This way works, but when we change the screen orientation not until the sleep time ends, we will see

  

  To solve this problem, change code like this

  

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="mirror.android.configurationchangehandlertest.ConfigurationChangeHandlerTest" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="点击按钮启动线程模拟网络耗时操作,获取新闻详情显示在按钮下面" />
    
    <Button
        android:id="@+id/btn_createthread"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="获取娱乐新闻"/>
    
    <ProgressBar
        android:id="@+id/progressbarId"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        style="@android:style/Widget.ProgressBar.Small"
        />
    
    <TextView
        android:id="@+id/tv_shownews"
        android:layout_width="match_parent"  
        android:layout_height="match_parent"
        android:textColor="@android:color/holo_green_dark"  />

</LinearLayout>
package mirror.android.configurationchangehandlertest;

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

public class RetainedFragment extends Fragment {
    
    private OnFragmentInteractionListener mListener;    

    //This interface must be implemented by activities that contain this 
    //fragment to allow an interaction in this fragment to be communicated 
    //to the activity and potentially other fragments contained in that 
    //activity.
    public interface OnFragmentInteractionListener{
        public void onFragmentInteraction(String string);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // retain this fragment
        setRetainInstance(true);
    }
    
    void excuteLongTimeOperation() {
        Thread workerThread = new Thread(new MyNewThread());
        workerThread.start();
    }
    
    class MyNewThread extends Thread{
        @Override
        public void run() {
            try {
                sleep(5000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            String newsInfo = "10月20日,周杰伦御用作词人方文山在微博发声表示,周杰伦的第十三张专辑的所有歌曲已经录制完毕," +
                    "此次专辑会收录超过十首歌曲,预计12月发行。网友纷纷表示期待“小十三等待实在太不易了”。" +
                    "还有部分网友就之前蔡依林[微博]的新专辑《呸》调侃:杰伦新专辑名字是不是<<爱呸不呸>> ?";
            Message message = handler.obtainMessage();
            Bundle bundle = new Bundle();
            bundle.putString("message", newsInfo);
            message.setData(bundle);
            handler.sendMessage(message);
        }
    }
    
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if(mListener != null){
                mListener.onFragmentInteraction(msg.getData().getString("message"));
            }
        }
    };

    @Override
    public void onAttach(Activity activity) {
        // Called when a fragment is first attached to its activity. onCreate(Bundle) will be called after this.
        super.onAttach(activity);
        mListener = (OnFragmentInteractionListener)activity;
    }
}
package mirror.android.configurationchangehandlertest;

import mirror.android.configurationchangehandlertest.RetainedFragment.OnFragmentInteractionListener;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.ProgressDialog;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;


public class ConfigurationChangeHandlerTest extends Activity implements OnClickListener,OnFragmentInteractionListener {

    private final String TAG = "ConfiguartionTest";
    private TextView        showNewsInfoTxt;   
    private ProgressBar     progressBar;  
    private String          newsInfo;  
    private RetainedFragment dataFragment;  
    private static final String KEY_CURRENT_NEWSDATA = "current_nesdata";  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_configuration_change_handler_test);  
        Log.i(TAG, "----onCreate---");  

        Button anrBtn = (Button) findViewById(R.id.btn_createthread);  
        anrBtn.setOnClickListener(this);  
        showNewsInfoTxt = (TextView) findViewById(R.id.tv_shownews);  
        progressBar = (ProgressBar) findViewById(R.id.progressbarId);  
        if(null != savedInstanceState){  
            refreshNewsInfo((String) savedInstanceState.get(KEY_CURRENT_NEWSDATA));  
        }  
  
        //在activity重启时获取到保留的fragment对象  
        FragmentManager fm = getFragmentManager();  
        dataFragment = (RetainedFragment) fm.findFragmentByTag("data");  
        if(null == dataFragment){  
            //添加fragment  
            dataFragment = new RetainedFragment();  
            fm.beginTransaction().add(dataFragment, "data").commit();  
            //从网上下载数据  
              
        }  
    }  
  
    @Override  
    public void onClick(View view) {  
        switch (view.getId()){  
            case R.id.btn_createthread:  
                progressBar.setVisibility(View.VISIBLE);   
                dataFragment.excuteLongTimeOperation();  
                break;  
        }  
    }  
  
    @Override  
    public void onFragmentInteraction(String newsInfo) {  
        this.newsInfo = newsInfo;  
        refreshNewsInfo(newsInfo);  
    }  
  
    /** 
     * 更新界面内容 
     */  
    private void refreshNewsInfo(String newsInfo) {  
        progressBar.setVisibility(View.GONE);  
        showNewsInfoTxt.setText(newsInfo);  
    }  
  
    @Override  
    protected void onSaveInstanceState(Bundle outState) {
        //This method is called before an activity may be killed 
        //so that when it comes back some time in the future it can restore its state. 
        super.onSaveInstanceState(outState);  
        outState.putString(KEY_CURRENT_NEWSDATA,showNewsInfoTxt.getText().toString());//注意不要直接传newsInfo,否则在异步操作执行完成后旋转屏幕,内容还是会消失。因为该值只有在屏幕旋转的时候才赋值,  
        Log.i(TAG, "----onSaveInstanceState---");  
    }  
  
    @Override  
    public void onConfigurationChanged(Configuration newConfig) {  
        super.onConfigurationChanged(newConfig);  
        Log.i(TAG, "----onConfigurationChanged---");  
    }  
  
    @Override  
    protected void onDestroy() {  
        super.onDestroy();  
        Log.i(TAG, "====onDestroy====");  
    }  
  
    @Override  
    protected void onStart() {  
        super.onStart();  
        Log.i(TAG, "----onStart---");  
    }  
  
    @Override  
    protected void onResume() {  
        super.onResume();  
        Log.i(TAG, "----onResume---");  
    }  
  
    @Override  
    protected void onRestart() {  
        super.onRestart();  
        Log.i(TAG, "----onRestart---");  
    }  
  
    @Override  
    protected void onPause() {  
        super.onPause();  
        Log.i(TAG, "----onPause---");  
    }  
  
    @Override  
    protected void onStop() {  
        super.onStop();  
        Log.i(TAG, "----onStop---");  
    }  
    
}

 

 

3. Handling the Configuration Change Yourself

  If your application doesn't need to update resources during a specific configuration change and you have a performance limitation

    that requires you to avoid the activity restart, then you can declare that your activity handles the configuration change itself,

    which prevents the system from restarting your activity.  

  Handling the configuration change yourself can make it much more difficult to use alternative resources, because the system does not

    automatically apply them for you. This technique should be considered a last resort when you must avoid restarts due to a

    configuration change and is not recommended for most applications.

  For example, the following manifest code declares an activity that handles both the screen orientation change and keyboard

    availability change:

<activity android:name=".MyActivity"
          android:configChanges="orientation|keyboardHidden"
          android:label="@string/app_name">

 

转载于:https://www.cnblogs.com/iMirror/p/4069719.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值