Bir etkinliği programlı olarak yeniden başlatmak / yeniden oluşturmak mı?


121

Veritabanımda, görüşlerimde önemli değişiklikler içeren bazı değişiklikler yaptıktan sonra, onCreate'i yeniden çizmek, yeniden çalıştırmak istiyorum.

Bu nasıl mümkün olabilir?

Yanıtlar:


129

GÜNCELLEME : Android SDK 11 recreate(), etkinliklere bir yöntem ekledi .


Bunu sadece etkinliği başlatan amacı yeniden kullanarak yaptım. Bir niyet tanımla starterIntentsınıfınızda ve içinde atamak onCreate()kullanarak starterIntent = getIntent();. Ardından etkinliği yeniden başlatmak istediğinizdefinish(); startActivity(starterIntent);

Çok zarif bir çözüm değil, ancak aktivitenizi yeniden başlatmanın ve her şeyi yeniden yüklemeye zorlamanın basit bir yolu.


8
aslında cihaz oryantasyonu değiştiğinde, aktivitenin on yaratıcısı da benzer bir şekilde çağrıldığını düşünüyorum .. bu yüzden bunu yapmayı umursamıyorum. startActivity (getIntent ()); bitiş();
Raja

startActivity'yi (getIntent ()) yapmak akıllıca değildir çünkü etkinlikleri etkinliklerin üzerine katman olarak yerleştirir. Eski aktiviteyi bitirmek gerekiyor
Fallenreaper

8
@Fallenreaper Tam da bu nedenle finish()hemen sonra aramayı önerdim startActivity()...
Steve Haley

7
Önce finish();o zaman çağırarak başardımstartActivity(starterIntent);
Carlo Rodríguez

3
Öyleyse hangisi? finish () ve sonra startActivity? Ya da tam tersi?
Jeff Padgett

92

Aktivitenin yeniden oluşturma yöntemini çağırın .


19
Uygulamanız yalnızca 11 ve üzeri düzey SDK'yı hedefliyorsa bu sorun olmaz. Aksi takdirde Steve Haley'in yaklaşımıyla giderdim.
TalkLittle

1
@FernandoEscher Maalesef bu yalnızca Honeycomb cihazlarda ve daha yüksek sürümlerde kullanılabilir.
IgorGanapolsky

2
yeniden oluşturma yöntemi nerede
çağrılır

1
yeniden oluştur yöntem çağrısı uygulamayı hızlı bir şekilde kapatın
SAndroidD

Eskiden kullanırdım, recreate()ancak şimdi radyo düğmelerinin yeniden oluştururken sıfırlanmadığı garip bir sorun görüyorum, ancak bu finish(); startActivity(getIntent());yüzden bunu şimdilik kullanıyorum ve önümüzdeki günlerde veya haftalarda nasıl çalıştığını görüyorum.
Ben

35

Burada bazı cevapları birleştirerek aşağıdaki gibi bir şey kullanabilirsiniz.

class BaseActivity extends SherlockFragmentActivity
{
    // Backwards compatible recreate().
    @Override
    public void recreate()
    {
        if (android.os.Build.VERSION.SDK_INT >= 11)
        {
            super.recreate();
        }
        else
        {
            startActivity(getIntent());
            finish();
        }
    }
}

Test yapmak

Biraz test ettim ve bazı sorunlar var:

  1. Etkinlik çağrısında yığının en düşük biriyse startActivity(...); finish();sadece app var ve yok aktiviteyi yeniden başlatın.
  2. super.recreate()aslında aktiviteyi tamamen yeniden yaratmakla aynı şekilde davranmaz. Cihazı döndürmeye eşdeğerdir, böylece herhangi bir Fragmente- setRetainInstance(true)postanız varsa yeniden oluşturulmazlar; yalnızca duraklatıldı ve yeniden başlatıldı.

Bu yüzden şu anda kabul edilebilir bir çözüm olduğuna inanmıyorum.


5
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMBkullanmak yerine11
S.Thiongane

4
11 doğru, .HONEYCOMB doğru değil, çünkü SDK <11'deki kodunuz wtat'ın HONEYCOMB olduğunu bilmiyor.
Tapa

6
yerine startActivity(getIntent());finish();görefinish();startActivity(getIntent());
ahmed hamdy

Hayır, öneriye göre mevcut en yüksek sdk'yi hedeflemelisiniz, bu nedenle bal peteği derleme zamanında kullanılabilir olacak ve int sabiti uygulamanızda taşınır. Minimum sdk int'den daha büyük bir sdk int kullanmanın yaygın bir model olduğuna inanıyorum.
Hai Zhang

32

seçenek 1

Çağrı recreate()Aşağıdaki yerlerde de Activity. Ancak bu yöntem, etkinliğin yeniden oluşturulması sırasında yanıp sönen siyah bir ekranın görünmesine neden olur.

seçenek 2

finish();
startActivity(getIntent());

Burada "yanıp sönen" siyah ekran yok, ancak eski ve yeni örnekler arasında pek hoş olmayan siyah bir arka plana sahip bir geçiş göreceksiniz. Daha iyisini yapabiliriz.

3. Seçenek

Bunu düzeltmek için şu numaraya bir çağrı ekleyebiliriz overridePendingTransition():

finish();
startActivity(getIntent());
overridePendingTransition(0, 0);

Elveda siyah ekran, ama benim durumumda hala bu sefer renkli bir arka planda bir tür geçiş (solma animasyonu) görüyorum. Bunun nedeni, etkinliğinizin mevcut örneğini yenisi oluşturulmadan ve tam olarak görünür hale gelmeden önce bitirmeniz ve aradaki renk, windowBackgroundtema özelliğinin değeridir .

4. seçenek

startActivity(getIntent());
finish();

finish() Sonra arama startActivity(), genellikle küçük bir kayan animasyonla etkinlikler arasındaki varsayılan geçişi kullanacaktır. Ancak geçiş hala görülebilir.

Seçenek 5

startActivity(getIntent());
finish();
overridePendingTransition(0, 0);

Bana göre bu en iyi çözüm çünkü hiçbir şey olmamış gibi aktiviteyi görünür bir geçiş olmadan yeniden başlatıyor.

Örneğin, uygulamanızda görüntüleme dilini sistemin dilinden bağımsız olarak değiştirmenin bir yolunu açıklarsanız yararlı olabilir. Bu durumda, kullanıcı uygulamanızın dilini her değiştirdiğinde, muhtemelen geçiş yapmadan etkinliğinizi yeniden başlatmak isteyeceksiniz, bu da dil geçişinin anında görünmesini sağlayacaktır.


1
5. seçenekle ilgili bir sorun, önceki etkinliği arka yığına eklemesidir. Bunu birkaç kez arayın ve kullanıcınızın gerçek bir önceki sayfaya ulaşmak için birkaç kez geri tıklaması gerekir.
Ollie

23

Bir aktiviteyi yeniden başlatmam gerektiğinde aşağıdaki kodu kullanıyorum. Tavsiye edilmese de.

Intent intent = getIntent();
finish();
startActivity(intent);

1
Çok temiz ve zarif bir çözüm. SDK 11 öncesi cihazlarda harika çalışıyor.
IgorGanapolsky

Super.recreate () yöntemiyle ilgili sorunlar yaşadım, ancak bu Lollipop'ta Tamam çalışıyor

6

11'den önceki API için repreate () kullanamazsınız. Bu şekilde çözdüm:

Bundle temp_bundle = new Bundle();
onSaveInstanceState(temp_bundle);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("bundle", temp_bundle);
startActivity(intent);
finish();

ve onCreate'de ..

@Override
public void onCreate(Bundle savedInstanceState) {

    if (getIntent().hasExtra("bundle") && savedInstanceState==null){
        savedInstanceState = getIntent().getExtras().getBundle("bundle");
    }

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //code

}

3

Zencefilli çörek aletini aradıktan sonra recreate, aşağıdaki kodları kullanmak istiyorum (zencefilli kurabiye için):

activity.mMainThread.mAppThread.scheduleRelaunchActivity(activity.mToken, null, null, 0, false, null);

Bu kodlar için, daha yüksek api'deki uygulamadandır.

public void recreate() {
    if (mParent != null) {
        throw new IllegalStateException("Can only be called on top-level activity");
    }
    if (Looper.myLooper() != mMainThread.getLooper()) {
        throw new IllegalStateException("Must be called from main thread");
    }
    mMainThread.requestRelaunchActivity(mToken, null, null, 0, false, null, false);
}

Api-10'da requestRelaunchActivity yok, ancak farktan şunu buldum:

             public final void scheduleRelaunchActivity(IBinder token,
                     List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
                     int configChanges, boolean notResumed, Configuration config) {
    -            ActivityClientRecord r = new ActivityClientRecord();
    -
    -            r.token = token;
    -            r.pendingResults = pendingResults;
    -            r.pendingIntents = pendingNewIntents;
    -            r.startsNotResumed = notResumed;
    -            r.createdConfig = config;
    -
    -            synchronized (mPackages) {
    -                mRelaunchingActivities.add(r);
    -            }
    -
    -            queueOrSendMessage(H.RELAUNCH_ACTIVITY, r, configChanges);
    +            requestRelaunchActivity(token, pendingResults, pendingNewIntents,
    +                    configChanges, notResumed, config, true);
             }

Bu yüzden scheduleRelaunchActivityyerine kullanabileceğimi düşünüyorum requestRelaunchActivity.

Ve bunları reflekte kullanarak yazdım:

package me.piebridge.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.res.Configuration;
import android.os.Build;
import android.os.IBinder;

public class GingerBreadUtil {

    private static Field scanField(Class<?> clazz, String... names) {
        for (String name : names) {
            Field field;
            try {
                field = clazz.getDeclaredField(name);
                field.setAccessible(true);
                return field;
            } catch (NoSuchFieldException e) {
            }
            try {
                field = clazz.getField(name);
                field.setAccessible(true);
                return field;
            } catch (NoSuchFieldException e) {
            }
        }
        return null;
    }

    public static void recreate(Activity activity) {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1) {
            recreateHC(activity);
        } else {
            try {
                recreateGB(activity);
            } catch (InvocationTargetException e) {
                e.getTargetException().printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private static void recreateHC(Activity activity) {
        ((Activity) activity).recreate();
    }

    private static void recreateGB(Activity activity) throws IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Field Activity$mToken = scanField(Activity.class, "mToken");
        IBinder mToken = (IBinder) Activity$mToken.get(activity);
        Field Activity$mMainThread = scanField(Activity.class, "mMainThread");
        Object mMainThread = Activity$mMainThread.get(activity);
        Field ActivityThread$mAppThread = scanField(mMainThread.getClass(), "mAppThread");
        Object mAppThread = ActivityThread$mAppThread.get(mMainThread);
        Method method = mAppThread.getClass().getMethod("scheduleRelaunchActivity",
            IBinder.class, List.class, List.class, int.class, boolean.class, Configuration.class);
        method.invoke(mAppThread, mToken, null, null, 0, false, null);
    }

}

Bu kodları xposed çerçevesinin geri taşınması için kullanıyorum.


Harika bir çalışma! Bir emülatörde test ettim ve bu yaklaşım Build.VERSION_CODES.ECLAIR_MR1(v7) ile geriye doğru uyumlu . Eski sürümlerde de çalışabilir.
Tim Cooke

3

recreate() Aktivitenizi yeniden oluşturmak istediğiniz yerden yöntemi çağırın . Bu yöntem, ile mevcut Activity örneğini yok edecek onDestroy()ve ardından etkinliği ile yeniden oluşturacaktır onCreate().


1

Eğer sorununuz buysa, Aktivitenizi doldurmak için muhtemelen başka bir yol uygulamalısınız. Yeniden çalıştırmak yerine, onCreate()onu onCreate()doldurma yönteminizi bazı argümanlarla çağırmalısınız. Veriler değiştiğinde, doldurma yöntemi başka bir argümanla çağrılmalıdır.


1

Bunu çözme şeklim Fragments kullanmaktı . Bunlar, destek kitaplığı kullanılarak API 4'e kadar geriye dönük uyumludur.

İçinde FrameLayout bulunan bir "sarmalayıcı" düzeni yaparsınız.

Misal:

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

     <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/fragment_container"
          android:layout_width="match_parent"
          android:layout_height="match_parent" />
</LinearLayout>

Ardından istediğiniz zaman FrameLayout'u değiştirebileceğiniz bir FragmentActivity oluşturursunuz.

Misal:

public class SampleFragmentActivity extends FragmentActivity
{

     @Override
 public void onCreate(Bundle savedInstanceState)
 {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.wrapper);

    // Check that the activity is using the layout version with
    // the fragment_container FrameLayout
    if (findViewById(R.id.fragment_container) != null)
    {

        // However, if we're being restored from a previous state,
        // then we don't need to do anything and should return or else
        // we could end up with overlapping fragments.
        if (savedInstanceState != null)
        {
            return;
        }
        updateLayout();
     }
  }

  private void updateLayout()
  {
     Fragment fragment = new SampleFragment();
     fragment.setArguments(getIntent().getExtras());

     // replace original fragment by new fragment
     getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commit();
  }

Şişirdiğiniz / değiştirdiğiniz Fragment'te onStart ve onCreateView'i normalde bir etkinliğin onCreate'ini kullanacağınız gibi kullanabilirsiniz.

Misal:

public class SampleFragment extends Fragment
{

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

    @Override
    public void onStart()
    {
        // do something with the components, or not!
        TextView text = (TextView) getActivity().findViewById(R.id.text1);

        super.onStart();
    }
}

1

Ayrıca durumunuza bağlı olarak getActivity().recreate();, sadece ihtiyacınız olabilir recreate().

Örneğin, recreate()aktivite sınıfı içinde oluşturulan sınıfta yapıyorsanız kullanmalısınız .


0

Bir keresinde, firebase bulut depolamasını kullanarak veritabanı dosyasını yükleyen, silen ve ardından yeniden indiren bir test uygulaması yaptım. Verileri veritabanında görüntülemek için bulduğum tek çözüm aşağıdaki koddu. Bu durumda recreate()ne finish()işe yaradı ne de çalıştı.

Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
System.exit(0);

0

Veri değiştiğinde Parçanızı yenilemenin en iyi yolunu buldum

bir düğme "arama" varsa, düğmenin içindeki ARRAY listenizi başlatmanız gerekir

mSearchBtn.setOnClickListener (new View.OnClickListener () {

@Override public void onClick (View v) {

mList = new ArrayList<Node>();

firebaseSearchQuery.addValueEventListener(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot dataSnapshot) {


      for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {

        Node p = dataSnapshot1.getValue(Node .class);
        mList.add(p);
      }
      YourAdapter = new NodeAdapter(getActivity(), mList);
      mRecyclerView.setAdapter(YourAdapter );

    }

-2

OnCreate () 'e bir parametre iletmek istiyorsanız, fazladan ekleyerek yeni bir amaç oluşturmanız ve onunla StartActivity'yi çağırmanız gerekir. İşte bu şekilde yaptığım basit bir örnek.

              String eczSabit = sa.getItem(position).getValue();
              if(!Util.IsNullOrEmpty(eczSabit)){
                  sabit = Long.parseLong(eczSabit);
                  Intent intent = new Intent(eczaneSegmentasyon.this,eczaneSegmentasyon.class);
                  intent.putExtra("sabit", sabit);
                  startActivity(intent);
              }

kötü adlandırma kuralı, kötü değişken adları, gerçekten kafa karıştırıcı kod ... -1
Ahmed Adel Ismail

-4

Sadece görüşünüzü yeniden yapmak istiyorsanız, aynı sorunu yaşadım. In onResumefonksiyonu bu koymayı deneyin:

mView = new AndroidPinballView(getApplication());

Bu da benim içindi onCreate(), bu yüzden bunu benim için onResumeişe yaradı :)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.