-2

我的應用程序由導航抽屜和4個片段構成。 這個應用程序的舊版本使用活動,所以我需要改變片段中的活動。安卓力量當屏幕更改方向時重新繪製片段

目前一切運作良好,但在一個Fragment我有80 Buttons用戶可以設置文字和背景顏色和方法調用DialogActivity是在管理所有FragmentsonActivityResults通過對話框稱爲內Fragments用於管理的唯一一個MainActivity用戶更改。

當屏幕方向更改爲橫向時,會發生此問題。 如果我按Buttons並設置文字和顏色所有作品與肖像但如果改變方向的屏幕與風景我得到的東西像「背景」的像「陰影」和我沒有改變它們的屬性,當我點擊他們,但如果我再次旋轉屏幕變化的按鈕變得可見。 奇怪的是,在片段背景中,我看到的按鈕與正確的更新,但不是在頂部...(我發佈的照片​​,這很難解釋)

我改變的舊按鈕仍然改變,因爲我把它保存到數據庫,但與景觀我不能更新澈其他按鈕...

enter image description here

CODE:

MainActivity.java

public class MainActivity extends AppCompatActivity 
     implements NavigationView.OnNavigationItemSelectedListener { 


    static String clickedButtonViewId; 

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

     setContentView(R.layout.activity_main); 

     Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 
     setSupportActionBar(toolbar); 


     DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 
     ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
       this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close); 
     drawer.setDrawerListener(toggle); 
     toggle.syncState(); 

     NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); 
     navigationView.setNavigationItemSelectedListener(this); 

     if (findViewById(R.id.content_frame) != null){ 

      getSupportFragmentManager().beginTransaction() 
        .add(R.id.content_frame, new OrarioFragment()).commit(); 
     } 
    } 

    @Override 
    public void onBackPressed() { 
     DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 
     if (drawer.isDrawerOpen(GravityCompat.START)) { 
      drawer.closeDrawer(GravityCompat.START); 
     } else { 
      super.onBackPressed(); 
     } 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.main, menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     // Handle action bar item clicks here. The action bar will 
     // automatically handle clicks on the Home/Up button, so long 
     // as you specify a parent activity in AndroidManifest.xml. 
     int id = item.getItemId(); 

     //noinspection SimplifiableIfStatement 
     if (id == R.id.action_settings) { 
      return true; 
     } 

     return super.onOptionsItemSelected(item); 
    } 

    @SuppressWarnings("StatementWithEmptyBody") 
    @Override 
    public boolean onNavigationItemSelected(MenuItem item) { 
     // Handle navigation view item clicks here. 
     int id = item.getItemId(); 

     FragmentManager fragmentManager = getSupportFragmentManager(); 

     if (id == R.id.nav_orario) { 

      fragmentManager.beginTransaction() 
        .replace(R.id.content_frame, new OrarioFragment()) 
        .commit(); 

     } else if (id == R.id.nav_calendario) { 

      fragmentManager.beginTransaction() 
        .replace(R.id.content_frame, new CalendarioFragment()) 
        .commit(); 

     } else if (id == R.id.nav_voti) { 

      fragmentManager.beginTransaction() 
        .replace(R.id.content_frame, new VotiFragment()) 
        .commit(); 

     } else if (id == R.id.nav_registrazioni) { 

      fragmentManager.beginTransaction() 
        .replace(R.id.content_frame, new RegistrazioniFragment()) 
        .commit(); 

     } else if (id == R.id.nav_share) { 

     } else if (id == R.id.nav_send) { 

     } 

     DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); 
     drawer.closeDrawer(GravityCompat.START); 
     return true; 
    } 


    public void addMateria(View v){ 

     /* Prendo il nome della risorsa cosi nel ricompilare il progetto non perdo * 
     * tutti i riferimenti ai bottoni salvati nel database      */ 

     clickedButtonViewId = getResources().getResourceEntryName(v.getId()); 

     //StartActivityForResult perche mi aspetto la materia inserita dall'altra activity 
     Intent myIntent = new Intent(MainActivity.this, ActivityAddMateria.class); 
     startActivityForResult(myIntent, 1); 
     //onStop(); 
    } 

    //Take back data from ActivityAddMateria 
    public void onActivityResult(int requestCode, int resultCode, Intent data) { 
     if(requestCode == 1) { 
      if (resultCode == RESULT_OK) { 

       MySQLiteHelper db = new MySQLiteHelper(this); 

       //Cambio subito il Button 
       int resId = getResources().getIdentifier(clickedButtonViewId, "id", getPackageName()); 
       final Button clickedtextView = (Button) findViewById(resId); 

       String result = data.getStringExtra("result"); //Take the materia from Dialog 
       int color = data.getIntExtra("color", 1); //Take the color from Dialog 

       //Controllo se il Button è già presente nel db se presente aggiorno se non presente inserisco 
       boolean modifica = db.Exists(clickedButtonViewId); 

       //Se voglio ripristinare il bottone di default 
       if (color == getResources().getColor(R.color.blue_orario)) { 

        //Ripristino la grafica di Default 
        Drawable style = setButtonColor(color); 
        clickedtextView.setBackground(style); 
        clickedtextView.setText("New"); 

        //Se la materia è nel database la cancello 
        if (modifica) { 

         db.deleteSingleMateria(clickedButtonViewId); 

        } 

       } else { 
        //Quando inserisco un normale bottone colorato 
        if (!modifica) { 

         //Materia da inserire in un nuovo spazio 
         db.addMateriaToDb(new Materia(clickedButtonViewId, result, color)); 

        } else { 

         //Materia già presente nel Button quindi aggiorno la materia 
         db.updateMateria(new Materia(clickedButtonViewId, result, color)); 
         Toast.makeText(getApplicationContext(), "Materia modificata!", 
           Toast.LENGTH_LONG).show(); 
        } 

        //Inserisco la materia nel DB dei voti_media 
        db.addMateriaVotiFromOrario(new MaterieVoti(result, 0.0)); 

        clickedtextView.setText(result); 
        //clickedtextView.setBackgroundColor(color); 
        //clickedtextView.getBackground().setColorFilter(color, PorterDuff.Mode.MULTIPLY); 
        Drawable style = setButtonColor(color); 
        clickedtextView.setBackground(style); 
       } 
      } 

      if (resultCode == RESULT_CANCELED) { 
       //Nessuna materia inserita 
      } 

     } 
    }//onActivityResult 

編輯

好吧,我發現這個問題。

在MainActivity我有力這行代碼的第一片段中顯示

if (findViewById(R.id.content_frame) != null){ 

      getSupportFragmentManager().beginTransaction() 
        .add(R.id.content_frame, new OrarioFragment()).commit(); 
     } 

而當屏幕方向改變在MainActivity被重建並且如果加載相同的片段通過舊片段,因爲我使用.add()

那麼我應該如何設置片段顯示,當應用程序開始避免這個問題?

我管理抽屜有問題嗎?

+0

顯示您的代碼。 – Bryan

+0

@Bryan添加了代碼,如果需要更多隻是告訴:) – Dario

+0

你也可以分享你的佈局嗎? – JRG

回答

1

Android文檔解釋了關於保存狀態和關於在活動和片段中保存狀態的非常好的文章。

保存和恢復活動狀態有些情況下,你的活動是由於正常的應用程序的行爲摧毀了幾個方案,比如當用戶按下「後退」按鈕,或者您的活動通過調用finish()方法來標記自己的銷燬。如果活動處於停止狀態並且很長一段時間未使用活動,或者前臺活動需要更多資源,系統還可能銷燬包含活動的進程以恢復內存。

當您的活動因用戶按下「後退」或活動自行完成而被銷燬時,該活動實例的系統概念將永遠消失,因爲該行爲表示活動不再需要。但是,如果系統由於系統限制(而不是正常的應用程序行爲)而破壞了活動,那麼雖然實際的活動實例已經消失,但系統會記住它已存在,因此如果用戶導航回它,系統會創建一個新的使用一組保存的數據描述活動在銷燬時的狀態。系統用於恢復先前狀態的已保存數據稱爲實例狀態,是存儲在Bundle對象中的鍵值對的集合。

默認情況下,系統使用Bundle實例狀態來保存有關活動佈局中每個View對象的信息(例如輸入到EditText小部件中的文本值)。 因此,如果您的活動實例被銷燬並重新創建,那麼佈局的狀態將恢復到之前的狀態,而您不需要任何代碼。但是,您的活動可能包含更多想要恢復的狀態信息,例如跟蹤用戶活動進度的成員變量。

保存您的活動狀態 當你的活動開始,停止,系統調用的onSaveInstanceState()方法,因此您的活動可以保存狀態信息與鍵值對的集合。此方法的默認實現可以保存有關活動視圖層次結構狀態的瞬態信息,例如EditText小部件中的文本或ListView小部件的滾動位置。你的應用應該在onPause()方法之後和onStop()之前實現onSaveInstanceState()回調。不要在onPause()中實現此回調。

警告:您必須始終調用onSaveInstanceState()的超類實現,以便默認實現可以保存視圖層次結構的狀態。

要保存活動的其他狀態信息,必須重寫onSaveInstanceState()並將鍵值對添加到在您的活動意外銷燬的事件中保存的Bundle對象。例如:

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); 
} 

注意:爲了讓Android系統以恢復您的活動的意見的狀態,每個視圖必須有一個唯一的ID,由機器人提供:id屬性。

要保存持久數據(例如用戶首選項或數據庫數據),當您的活動處於前臺時,應該採取適當的機會。如果沒有這樣的機會出現,您應該在onStop()方法中保存這些數據。

恢復您的活動狀態 當您的活動被重建後,先前被破壞,可以從捆綁恢復保存的狀態,該系統傳遞到您的活動。 onCreate()和onRestoreInstanceState()回調方法都會收到包含實例狀態信息的相同Bundle。

因爲無論系統是在創建活動的新實例還是重新創建前一個實例,都會調用onCreate()方法,您必須在嘗試讀取之前檢查狀態Bundle是否爲null。如果它爲空,那麼系統正在創建一個活動的新實例,而不是恢復之前被銷燬的實例。

例如,下面的代碼片段展示瞭如何在的onCreate()恢復了一些狀態數據:

@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 
    } 
    ... 
} 

相反的onCreate()中恢復狀態,你可以選擇實施onRestoreInstanceState (),系統在onStart()方法之後調用。該系統調用onRestoreInstanceState()只如果有恢復已保存的狀態,這樣你就不會需要檢查包是否爲空:

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); 
} 

注意:始終調用父類實現onRestoreInstanceState的( ),所以默認實現可以恢復視圖層次的狀態。

+0

是的,但爲什麼我在屏幕方向更改時有像照片那樣的「陰影」,以及爲什麼我無法看到按鈕隨屏幕風景而改變。 如果我回到肖像所有工作完美,這是問題的景觀,並不認爲問題是InstanceState ....不是? 隨着instanceState我無法避免風景的「陰影」效應 – Dario

+0

你有兩個方向相同的佈局,或者你有佈局和layout-land文件夾的方向? – JRG

+0

相同的佈局,我沒有兩個不同的屏幕方向佈局。 當屏幕方向改變時,我可能需要銷燬碎片。 也許「陰影」效應它是兩個片段UI的重疊? 因爲背景中的陰影,如果我改變一個按鈕與風景我看到在陰影背景更新,但不是在頂部(這很難解釋:D) – Dario