android之fragment活動棧單例
本文主要記錄一些零碎的東西
最近參加了一個做地圖的公司的面試,怎麼說呢,反正問的我都不會,問題感覺偏向記憶體的顯示優化方向,比如Bitmap佔記憶體大小啦之流,只怪自己學業不精。
專案還要繼續,在寫專案時,發現fragment的活動棧有些問題,回想起面試官問過這個問題 ,研究一下。
說一下問題的出現,我的fragment,從A--->(transaction.addToBackStack)B--->(transaction.addToBackStack)C--->B--->(transaction.addToBackStack)C,然後在這是按返回按鈕,回退到B,再次按回退按鈕,介面沒有反應,在頂部的導航欄中將當前的佈局檔案的內容切換成另外一個fragment,沒有壓入棧,這時就會發現介面上亂套了,兩個介面都顯示著,新切換的介面在上C介面在下,問題就出現啦。
這裡解決也簡單,在C--->B是加上transaction.addToBackStack,就沒有問題了,但是又會出現一個問題,沒有做單例,如果我一直C--->B--->C--->B--->C...活動棧中存在多個重複的B和C物件。
那如何做單例呢,activity裡做單例可以在mainfest.xml檔案裡的activity 裡配置android:launchMode,有四個引數
standard 每次都會新建,每個Task都可以有,且每個Task都可以有多個例項(每個Task都可以有,且可以有多個)
singleTop 當前例項如果在棧頂,就不新建例項,呼叫其OnNewIntent。 如不在棧頂,則新建例項
singleTask 新建一個Task,如果已經有其他的Task並且包含該例項,那就直接呼叫那個Task的例項。(只有一個Task中會有)
singleInstance 新建一個Task,且在該Task中只有它的唯一一個例項。 (只有一個Task會有,且該Task中只有它)
但是上面這麼好的東西,但是不是我想要的效果,其實我每次C--->B--->C--->B--->C...時資料都是變化的,我想實現的是使用一個物件,但是每次replace時不僅要切換介面,還要更新顯示的資料,目前還沒有想到很好的解決方案。
- - - - - - - - - - - - - - - - - - - -更新 2016-04-13 - -- - - - - - -- - - - - - - - - - - - -
想著fragment切換時不傳資料,把要更新的資料寫在一個單獨的類中有get/set方法,新的fragment直接get新資料
發現 replace()這個方法只是在上一個Fragment不再需要時採用的簡便方法。
正確的切換方式是add(),切換時hide(),add()另一個Fragment;再次切換時,只需hide()當前,show()另一個。
這樣就能做到多個Fragment切換不重新例項化,
有點投機取巧的意思,呼叫onResume方法,但是基本上我實現了返回棧裡只有物件的單例的,同時也重新整理的fragment上的資料,
看下測試執行結果
上傳一張fragment的生命週期
主要程式碼:
先看看DataUtil,簡單模擬一下資料
/**
* Created by Administrator on 2016/4/13.
*/
public class DataUtil {
public static String getNum() {
return (new Random()).nextInt()+"";
}
}
main_activity 佈局檔案
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
<FrameLayout
android:id="@+id/change"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
</RelativeLayout>
fragment佈局檔案,
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<TextView
android:background="#0ff"
android:id="@+id/show"
android:layout_width="match_parent"
android:layout_height="100dp"
android:textSize="40sp"
android:text="111"/>
</LinearLayout>
mainactivity
package android.addre.com.fragmenttest;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
switchContent(null,FragmetntA.getFragmetntA());
}
public void switchContent(Fragment from, Fragment to) {
FragmentTransaction transactio = getSupportFragmentManager().beginTransaction();
if (!to.isAdded()) { // 先判斷是否被add過,沒有新增就新增
if(from != null){
transactio.hide(from);
transactio.addToBackStack(null);
}
transactio.add(R.id.change, to);
transactio.commit(); // 隱藏當前的fragment,add下一個到Activity中
} else {
if(from != null){
transactio.hide(from);
}
to.onResume();//這裡使用者更新資料,不加這句就可以實現單例了,但是不會呼叫任何生命週期裡的方法,不會更新資料
transactio.show(to).commit(); // 隱藏當前的fragment,顯示下一個
}
}
}
fragmentA
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* Created by Administrator on 2016/4/13.
*/
public class FragmetntA extends Fragment {
private View view;
private TextView textView;
private static FragmetntA fragmetntA;
public static FragmetntA getFragmetntA(){
if(fragmetntA == null){
fragmetntA = new FragmetntA();
}
return fragmetntA;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.i("slack", "onAttach...A");
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("slack", "onCreate...A");
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.i("slack", "onCreateView...A");
view = inflater.inflate(R.layout.fragmentlayout, null);
textView =(TextView)view.findViewById(R.id.show);
view.findViewById(R.id.show).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("slack", "onClick...A");
//切換介面
/*FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.change, FragmetntB.getFragmetntB());
transaction.addToBackStack(null);
transaction.commit();*/
((MainActivity)getActivity()).switchContent(fragmetntA, FragmetntB.getFragmetntB());
}
});
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.i("slack", "onActivityCreated...A");
}
@Override
public void onStart() {
super.onStart();
Log.i("slack", "onStart...A");
}
@Override
public void onResume() {
super.onResume();
Log.i("slack", "onResume...A");
textView.setText("A:" + DataUtil.getNum());
}
@Override
public void onPause() {
super.onPause();
Log.i("slack", "onPause...A");
}
@Override
public void onStop() {
super.onStop();
Log.i("slack", "onStop...A");
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.i("slack", "onDestroyView...A");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("slack", "onDestroy...A");
}
@Override
public void onDetach() {
super.onDetach();
Log.i("slack", "onDetach...A");
}
}
fragmentB
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* Created by Administrator on 2016/4/13.
*/
public class FragmetntB extends Fragment {
private View view;
private TextView textView;
private static FragmetntB fragmetntB;
public static FragmetntB getFragmetntB(){
if(fragmetntB == null){
fragmetntB = new FragmetntB();
}
return fragmetntB;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.i("slack", "onAttach...B");
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("slack", "onCreate...B");
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.i("slack", "onCreateView...B");
View view = inflater.inflate(R.layout.fragmentlayout,null);
textView =(TextView)view.findViewById(R.id.show);
view.findViewById(R.id.show).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("slack", "onClick...B");
//切換介面
/*FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.change, FragmetntA.getFragmetntA());
transaction.addToBackStack(null);
transaction.commit();*/
((MainActivity) getActivity()).switchContent(fragmetntB, FragmetntA.getFragmetntA());
}
});
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.i("slack", "onActivityCreated...B");
}
@Override
public void onStart() {
super.onStart();
Log.i("slack", "onStart...B");
}
@Override
public void onResume() {
super.onResume();
Log.i("slack", "onResume...B");
textView.setText("B:" + DataUtil.getNum());
}
@Override
public void onPause() {
super.onPause();
Log.i("slack", "onPause...B");
}
@Override
public void onStop() {
super.onStop();
Log.i("slack", "onStop...B");
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.i("slack", "onDestroyView...B");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("slack", "onDestroy...B");
}
@Override
public void onDetach() {
super.onDetach();
Log.i("slack", "onDetach...B");
}
}
跳轉都寫成一個方法,在main_activity裡switchContent,引數的意思是當前是顯示那個fragment,要顯示哪個新的fragment,
新增時先判斷一下,要顯示的是否已被新增過,未被新增則隱藏當前,新增新的,如果已被新增,則隱藏當前,顯示棧裡的對應物件
public void switchContent(Fragment from, Fragment to) {
FragmentTransaction transactio = getSupportFragmentManager().beginTransaction();
if (!to.isAdded()) { // 先判斷是否被add過,沒有新增就新增
if(from != null){
transactio.hide(from);
transactio.addToBackStack(null);
}
transactio.add(R.id.change, to);
transactio.commit(); // 隱藏當前的fragment,add下一個到Activity中
} else {
if(from != null){
transactio.hide(from);
}
to.onResume();//這裡使用者更新資料,不加這句就可以實現單例了,但是不會呼叫任何生命週期裡的方法,不會更新資料
transactio.show(to).commit(); // 隱藏當前的fragment,顯示下一個
}
}
如果是已被新增的,在呼叫show之前先呼叫resume方法更新一下資料
@Override
public void onResume() {
super.onResume();
Log.i("slack", "onResume...A");
textView.setText("A:" + DataUtil.getNum());
}