blob: 328b8ec3ad8e91980d8523a1e45a5ee0b67ba130 [file] [log] [blame]
page.title=X lý Thay đổi Thi gian chy
page.tags=hot động,vòng đời
@jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>Trong tài liu này</h2>
<ol>
<li><a href="#RetainingAnObject">Gi li mt Đối tượng trong khi Thay đổi Cu hình</a></li>
<li><a href="#HandlingTheChange">T mình X lý Thay đổi Cu hình</a>
</ol>
<h2>Xem thêm</h2>
<ol>
<li><a href="providing-resources.html">Cung cp Tài nguyên</a></li>
<li><a href="accessing-resources.html">Truy cp Tài nguyên</a></li>
<li><a href="http://android-developers.blogspot.com/2009/02/faster-screen-orientation-change.html">Thay đổi
Hướng Màn hình Nhanh hơn</a></li>
</ol>
</div>
</div>
<p>Mt s cu hình thiết b có th thay đổi trong thi gian chy
(chng hn như hướng màn hình, s sn có ca bàn phím, và ngôn ngữ). Khi s thay đổi như vy din ra,
Android s khi động li vic chy
{@link android.app.Activity} ({@link android.app.Activity#onDestroy()} sẽ được gọi, sau đó là {@link
android.app.Activity#onCreate(Bundle) onCreate()}). Hành vi khởi động lại được thiết kế để giúp
ng dng điu chnh phù hp vi cu hình mi bng cách t động ti li ng dng ca bn bng
các tài nguyên thay thế khp vi cu hình thiết b mi.</p>
<p>Để x lý khi động li cho đúng, điu quan trng là hot động ca bn khôi phc li trng thái trước đó
ca nó thông qua vòng đời <a href="{@docRoot}guide/components/activities.html#Lifecycle">Hot động
thông thường</a>, trong đó Android s gi
{@link android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()} trước khi nó hủy
hot động ca bn sao cho bn có th lưu d liu v trng thái ca ng dng. Khi đó, bn có th khôi phc trng thái
trong khi {@link android.app.Activity#onCreate(Bundle) onCreate()} hoặc {@link
android.app.Activity#onRestoreInstanceState(Bundle) onRestoreInstanceState()}.</p>
<p>Để kim tra xem ng dng ca bn có t khi động li mà gi nguyên trng thái ng dng hay không,
bn cn gi ra các thay đổi cu hình (chng hn như thay đổi hướng màn hình) trong khi thc hin các
tác v khác nhau trong ng dng ca bn. ng dng ca bn s có th khi động li vào bt c lúc nào mà không b mt
d liu ca người dùng hay trng thái để x lý các s kin như thay đổi cu hình hoc khi người dùng nhn được
mt cuc gi đến ri quay li ng dng ca bn mun hơn nhiu sau khi tiến trình
ng dng ca bn có th đã b hy. Để tìm hiu v cách bn có th khôi phc trng thái hot động ca mình, hãy đọc v <a href="{@docRoot}guide/components/activities.html#Lifecycle">Vòng đời ca hot động</a>.</p>
<p>Tuy nhiên, bn có th gp phi mt tình hung trong đó vic khi động li ng dng ca bn và
khôi phc phn ln d liu có th tn kém và to nên tri nghim người dùng kém. Trong
tình hung như vy, bn có hai tùy chn:</p>
<ol type="a">
<li><a href="#RetainingAnObject">Gi li mt đối tượng trong khi thay đổi cu hình</a>
<p>Cho phép hot động ca bn khi động li khi cu hình thay đổi, nhưng mang theo mt
đối tượng có trng thái ti thc th mi ca hot động ca bn.</p>
</li>
<li><a href="#HandlingTheChange">T mình x lý thay đổi cu hình</a>
<p>Ngăn không cho h thng khi động li hot động ca bn trong nhng thay đổi
cu hình nht định, nhưng nhn mt lnh gi li khi cu hình thay đổi, sao cho bn có th cp nht th công
hot động ca mình nếu cn.</p>
</li>
</ol>
<h2 id="RetainingAnObject">Gi li mt Đối tượng trong khi Thay đổi Cu hình</h2>
<p>Nếu vic khi động li hot động ca bn yêu cu bn phi khôi phc nhiu tp hp d liu ln, hãy thiết lp li kết ni
mng, hoc thc hin các thao tác tăng cường khác, khi đó khi động li hoàn toàn do thay đổi cu hình
có th gây ra tri nghim người dùng chm chp. Đồng thi, có th bn s không th hoàn toàn khôi phc được
trng thái hot động ca mình vi {@link android.os.Bundle} mà h thng lưu cho bn bng phương pháp gi li {@link
android.app.Activity#onSaveInstanceState(Bundle) onSaveInstanceState()}&mdash;nó không
được thiết kế để mang các đối tượng ln (chng hn như bitmap) và d liu trong nó phi được ni tiếp hóa ri
b ni tiếp hóa, điu này có th tiêu tn nhiu b nh và khiến vic thay đổi cu hình din ra chm. Trong mt
tình hung như vy, bn có th g b gánh nng khi to li hot động ca mình bng cách gi li {@link
android.app.Fragment} khi hot động ca bn được khi động li do thay đổi cu hình. Phân đon này
có th cha các tham chiếu ti đối tượng có trng thái mà bn mun gi li.</p>
<p>Khi h thng Android tt hot động ca bn do mt thay đổi cu hình, các phân đon
ca hot động mà bn đã đánh du để gi li s không b hy. Bn có th thêm các phân đon này vào
hot động ca mình để gi li các đối tượng có trng thái.</p>
<p>Để gi li các đối tượng có trng thái trong mt phân đon trong khi thay đổi cu hình thi gian chy:</p>
<ol>
<li>M rng lp {@link android.app.Fragment} và khai báo các tham chiếu ti đối tượng
có trng thái ca bn.</li>
<li>Gi {@link android.app.Fragment#setRetainInstance(boolean)} khi phân đoạn được tạo.
</li>
<li>Thêm phân đon vào hot động ca bn.</li>
<li>S dng {@link android.app.FragmentManager} để truy xut phân đon khi hot động
được khi động li.</li>
</ol>
<p>Ví dụ, định nghĩa phân đon ca bn như sau:</p>
<pre>
public class RetainedFragment extends Fragment {
// data object we want to retain
private MyDataObject data;
// this method is only called once for this fragment
&#64;Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// retain this fragment
setRetainInstance(true);
}
public void setData(MyDataObject data) {
this.data = data;
}
public MyDataObject getData() {
return data;
}
}
</pre>
<p class="caution"><strong>Chú ý:</strong> Trong khi bn có th lưu tr bt k đối tượng nào, bn
không nên chuyn mt đối tượng được gn vi {@link android.app.Activity}, chng hn như {@link
android.graphics.drawable.Drawable}, {@link android.widget.Adapter}, {@link android.view.View}
hay bt k đối tượng nào khác đi kèm vi mt {@link android.content.Context}. Nếu bn làm vy, nó s
rò r tt c dng xem và tài nguyên ca thc th hot động gc. (Rò r tài nguyên
có nghĩa là ng dng ca bn duy trì vic lưu gi tài nguyên và chúng không th được thu dn b nh rác, vì thế
rt nhiu b nh có th b mt.)</p>
<p>Khi đó, hãy s dng {@link android.app.FragmentManager} để thêm phân đon vào hot động.
Bn có th thu được đối tượng d liu t phân đon khi hot động bt đầu li trong khi
thay đổi cu hình thi gian chy. Ví dụ, định nghĩa hot động ca bn như sau:</p>
<pre>
public class MyActivity extends Activity {
private RetainedFragment dataFragment;
&#64;Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// find the retained fragment on activity restarts
FragmentManager fm = getFragmentManager();
dataFragment = (DataFragment) fm.findFragmentByTag(“data”);
// create the fragment and data the first time
if (dataFragment == null) {
// add the fragment
dataFragment = new DataFragment();
fm.beginTransaction().add(dataFragment, data”).commit();
// load the data from the web
dataFragment.setData(loadMyData());
}
// the data is available in dataFragment.getData()
...
}
&#64;Override
public void onDestroy() {
super.onDestroy();
// store the data in the fragment
dataFragment.setData(collectMyLoadedData());
}
}
</pre>
<p>Trong ví d này, {@link android.app.Activity#onCreate(Bundle) onCreate()} thêm một phân đoạn
hoc khôi phc mt tham chiếu đến nó. {@link android.app.Activity#onCreate(Bundle) onCreate()} cũng
lưu tr đối tượng có trng thái bên trong thc th phân đon đó.
{@link android.app.Activity#onDestroy() onDestroy()} cập nhật đối tượng có trạng thái bên trong
thc th phân đon được gi li.</p>
<h2 id="HandlingTheChange">T mình X lý Thay đổi Cu hình</h2>
<p>Nếu ng dng ca bn không cn cp nht các tài nguyên trong mt thay đổi
cu hình c th <em>và</em> bn có gii hn v hiu năng yêu cu bn phi
tránh khi động li hot động, khi đó bn có th khai báo rng hot động ca bn t mình x lý thay đổi cu hình
, làm vy s tránh cho h thng khi động li hot động ca bn.</p>
<p class="note"><strong>Lưu ý:</strong> Vic t mình x lý thay đổi cu hình có th khiến vic
s dng các tài nguyên thay thế khó khăn hơn nhiu, vì h thng không t động áp dng chúng
cho bn. K thut này nên được coi là gii pháp cui cùng khi bn phi tránh khi động li do mt
thay đổi cu hình và không được khuyến cáo đối vi hu hết ng dng.</p>
<p>Để khai báo rng hot động ca bn x lý mt thay đổi cu hình, hãy chnh sa phn t <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code &lt;activity&gt;}</a> phù hp trong
tp bn kê khai ca bn để bao gm thuc tính <a href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code
android:configChanges}</a> vi mt giá tr có chc năng biu din cu hình mà bn mun
x lý. Các giá tr có th được lit kê trong tài liu dành cho thuc tính <a href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code
android:configChanges}</a> (các giá tr thường được s dng nht là {@code "orientation"} để
ngăn khi động li khi hướng màn hình thay đổi và {@code "keyboardHidden"} để ngăn
khi động li khi tính sn có ca bàn phím thay đổi). Bn có th khai báo nhiu giá tr cu hình trong
thuc tính bng cách tách chúng bng mt ký t {@code |} đường dn ni.</p>
<p>Ví dụ, đon mã bn kê khai sau khai báo mt hot động có chc năng x lý c
thay đổi v hướng màn hình và thay đổi v tính sn có ca bàn phím:</p>
<pre>
&lt;activity android:name=".MyActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/app_name">
</pre>
<p>Lúc này, khi mt trong nhng cu hình này thay đổi, {@code MyActivity} không khi động li.
Thay vào đó, {@code MyActivity} nhn được mt lnh gi ti {@link
android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}. Phương pháp này
được chuyn bi mt đối tượng {@link android.content.res.Configuration} mà quy định
cu hình thiết b mi. Bng cách đọc các trường trong {@link android.content.res.Configuration},
bn có th xác định cu hình mi và thc hin nhng thay đổi phù hp bng cách cp nht
tài nguyên được s dng trong giao din ca bn. Ti
thi đim phương pháp này được gi, đối tượng {@link android.content.res.Resources} ca hot động ca bn được cp nht
để tr v các tài nguyên da trên cu hình mi, sao cho bn có th d dàng
đặt li các phn t trong UI ca mình mà không để h thng khi động li hot động ca bn.</p>
<p class="caution"><strong>Chú ý:</strong> Bt đầu vi Android 3.2 (API mc 13), <strong>
"kích cỡ màn hình" cũng thay đổi</strong> khi thiết b chuyn gia hướng dc và kh ngang
. Vì thế, nếu bn mun ngăn cn vic khi động li vào thi gian chy do thay đổi hướng khi phát trin
cho API mc 13 hoc cao hơn (như được khai báo bi các thuc tính <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> và <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code targetSdkVersion}</a>
), bn phi bao gm giá tr {@code "screenSize"} bên cnh giá tr {@code
"orientation"}. C thể, bn phi khai báo {@code
android:configChanges="orientation|screenSize"}. Tuy nhiên, nếu ng dng ca bn nhm ti API mc
12 hoc thp hơn, khi đó hot động ca bn luôn t mình x lý thay đổi cu hình này (thay đổi
cu hình này không khi động li hot động ca bn, ngay c khi đang chy trên mt thiết b phiên bn Android 3.2 hoc cao hơn).</p>
<p>Ví dụ, vic trin khai {@link
android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()} sau
s kim tra hướng thiết b hin ti:</p>
<pre>
&#64;Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
}
</pre>
<p>Đối tượng {@link android.content.res.Configuration} biu din tt c cu hình
hin ti, không ch nhng cu hình đã thay đổi. Trong phn ln thi gian, bn s không quan tâm chính xác xem
cu hình đã thay đổi như thế nào và có th đơn gin gán li tt c tài nguyên ca mình vi chc năng cung cp ni dung thay thế
cho cu hình mà bn đang x lý. Ví dụ, do đối tượng {@link
android.content.res.Resources} nay đã được cp nht, bn có th đặt li
bt kỳ{@link android.widget.ImageView} nào vi {@link android.widget.ImageView#setImageResource(int)
setImageResource()}
và tài nguyên phù hp cho cu hình mi được s dng (như được mô t trong phn <a href="providing-resources.html#AlternateResources">Cung cp Tài nguyên</a>).</p>
<p>Lưu ý rng giá tr t các trường {@link
android.content.res.Configuration} là nhng s nguyên khp vi hng s c th
t lp {@link android.content.res.Configuration}. Đối vi tài liu v nhng hng s
cn s dng vi mi trường, hãy tham kho trường phù hp trong tham chiếu {@link
android.content.res.Configuration}.</p>
<p class="note"><strong>Hãy ghi nhớ:</strong> Khi bn khai báo hot động ca mình để x lý mt
thay đổi cu hình, bn có trách nhim đặt li bt k phn t nào mà bn cung cp ni dung thay thế cho. Nếu bn
khai báo hot động ca mình để x lý thay đổi hướng và có nhng hình nh nên thay đổi
gia kh ngang và hướng dc, bn phi gán li tng tài nguyên cho tng phn t trong khi {@link
android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}.</p>
<p>Nếu bn không cn cp nht ng dng ca mình da trên nhng thay đổi
cu hình này, thay vào đó bn có th <em>không</em> trin khai {@link
android.app.Activity#onConfigurationChanged(Configuration) onConfigurationChanged()}. Trong
trường hp đó, tt c tài nguyên được s dng trước khi thay đổi cu hình s vn được s dng
và bn ch mi tránh được vic khi động li hot động ca mình. Tuy nhiên, ng dng ca bn cn luôn có kh năng
tt và khi động li vi trng thái trước đó ca nó được gi nguyên, vì thế bn không nên coi
k thut này như mt cách để thoát khi vic gi li trng thái ca mình trong vòng đời ca hot động bình thường. Không ch bi
có nhng thay đổi cu hình khác mà bn không th ngăn không cho khi động li ng dng ca mình, mà
c bi vì bn nên x lý nhng s kin như là khi người dùng ri khi ng dng ca bn và nó b
hy trước khi người dùng quay li.</p>
<p>Để biết thêm v nhng thay đổi cu hình nào mà bn có th x lý trong hot động ca mình, hãy xem tài liu <a href="{@docRoot}guide/topics/manifest/activity-element.html#config">{@code
android:configChanges}</a> và lp {@link android.content.res.Configuration}
.</p>