프로그래밍 방식으로 활동을 재실행 / 재 작성 하시겠습니까?


121

내 데이터베이스에서 약간의 변경을 수행 한 후에는 내 뷰의 중요한 변경과 관련하여 onCreate를 다시 그리고 다시 실행하고 싶습니다.

어떻게 가능합니까?

답변:


129

업데이트 : Android SDK 11 recreate()은 활동에 메서드를 추가했습니다 .


활동을 시작한 인 텐트를 단순히 재사용함으로써 그렇게했습니다. 의도를 정의 starterIntent클래스와 그것에서 지정 onCreate()사용 starterIntent = getIntent();. 그런 다음 활동을 다시 시작하려면finish(); startActivity(starterIntent);

매우 우아한 솔루션은 아니지만 활동을 다시 시작하고 모든 것을 다시로드하도록 강제하는 간단한 방법입니다.


8
실제로 나는 장치 방향이 변경 될 때 활동의 oncreate가 비슷한 방식으로 호출된다고 생각합니다. 그래서 나는 이것을해도 상관 없습니다. startActivity (getIntent ()); 끝();
Raja

startActivity (getIntent ())는 활동 위에 활동을 계층화하기 때문에 현명하지 않습니다. 이전 활동을 종료해야합니다
Fallenreaper 2010 년

8
나는 호출 제안 @Fallenreaper finish()직후 startActivity()... 정확히 그 이유
스티브 헤일리

7
내가 먼저 전화를 달성 finish();한 후startActivity(starterIntent);
카를로 로드리게스

3
그래서 그것은 무엇입니까? finish () 그리고 startActivity? 아니면 그 반대?
Jeff Padgett

92

활동 의 recreate 메소드를 호출하십시오 .


19
앱이 SDK 레벨 11 이상 만 타겟팅하는 경우 괜찮습니다. 그렇지 않으면 나는 Steve Haley의 접근 방식으로 갈 것입니다.
TalkLittle

1
@FernandoEscher 불행히도 Honeycomb 장치 이상에서만 사용할 수 있습니다.
IgorGanapolsky 2013

2
recreate 메서드를 호출 할 위치
SAndroidD

1
repaetdedly repaetdedly 메서드 호출을 다시 생성 앱을 닫습니다
SAndroidD

예전에는 사용 recreate()했지만 지금은 라디오 버튼이 다시 생성 될 때 재설정되지 않는 이상한 문제가 있지만, finish(); startActivity(getIntent());지금은 이것을 사용하고 다음 며칠 또는 몇 주 동안 어떻게 작동하는지 확인합니다.
Ben

35

여기에 몇 가지 답변을 결합하면 다음과 같은 것을 사용할 수 있습니다.

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

테스팅

나는 그것을 약간 테스트했고 몇 가지 문제가 있습니다.

  1. 활동이 스택에서 가장 낮은 활동 인 경우 호출 startActivity(...); finish();은 앱만 존재 하며 활동을 다시 시작 하지 않습니다 .
  2. super.recreate()실제로 활동을 완전히 재현하는 것과 동일한 방식으로 작동하지 않습니다. 장치를 회전하는 것과 같으므로 Fragments가 setRetainInstance(true)있으면 다시 생성되지 않습니다. 단지 일시 중지 및 재개되었습니다.

그래서 현재 나는 수용 가능한 해결책이 없다고 생각합니다.


5
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB대신 사용11
S.Thiongane 2014

4
11은 rigth, .HONEYCOMB는 맞지 않습니다. SDK <11의 코드는 wtat가 HONEYCOMB임을 알지 못하기 때문입니다.
Tapa Save

6
대신 startActivity(getIntent());finish();finish();startActivity(getIntent());
아메드 hamdy

아니요, 권장 사항에 따라 사용 가능한 가장 높은 sdk를 대상으로해야하므로 컴파일 타임에 honeycomb을 사용할 수 있으며 int 상수는 애플리케이션 내에서 전달됩니다. 최소 sdk int보다 큰 sdk int를 사용하는 것이 일반적인 패턴이라고 생각합니다.
하이 장

32

옵션 1

전화 recreate()당신에 Activity. 그러나이 방법을 사용하면 활동 재생성 중에 깜박이는 검은 색 화면이 나타납니다.

옵션 2

finish();
startActivity(getIntent());

여기에 "깜박이는"검은 색 화면은 없지만별로 기분이 좋지 않은 검은 색 배경으로 이전 인스턴스와 새 인스턴스간에 전환되는 것을 볼 수 있습니다. 우리는 더 잘할 수 있습니다.

옵션 3

이 문제를 해결하기 위해 다음과 같은 호출을 추가 할 수 있습니다 overridePendingTransition().

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

안녕히 가세요 검은 화면,하지만 제 경우에는 이번에는 컬러 배경에서 여전히 일종의 전환 (페이드 애니메이션)이 보입니다. 새로운 것이 만들어지고 완전히 표시 되기 전에 활동의 현재 인스턴스를 완료하고 중간 색상이 windowBackground테마 속성 의 값이기 때문입니다.

옵션 4

startActivity(getIntent());
finish();

전화finish() startActivity() 종종 작은 슬라이드에 애니메이션, 활동 사이에 기본 전환을 사용합니다. 그러나 전환은 여전히 ​​보입니다.

옵션 5

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

나에게 이것은 아무 일도 일어나지 않는 것처럼 보이는 전환없이 활동을 다시 시작하기 때문에 최상의 솔루션입니다.

예를 들어 앱에서 시스템 언어와 관계없이 표시 언어를 변경하는 방법을 노출하는 경우 유용 할 수 있습니다. 이 경우 사용자가 앱의 언어를 변경할 때마다 전환없이 활동을 다시 시작하여 언어 전환이 즉시 보이도록 할 수 있습니다.


1
옵션 5의 문제점은 이전 활동을 백 스택에 추가한다는 것입니다. 이것을 여러 번 호출하면 사용자는 실제 이전 페이지로 이동하기 위해 여러 번 뒤로 클릭해야합니다.
Ollie

23

활동을 다시 시작해야 할 때 다음 코드를 사용합니다. 권장하지는 않지만.

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

1
매우 깨끗하고 우아한 솔루션입니다. SDK 11 이전 기기에서 잘 작동합니다.
IgorGanapolsky 2013

super.recreate () 메소드에 문제가 있었지만 Lollipop에서 작동합니다

6

11 이전의 API의 경우 recreate ()를 사용할 수 없습니다. 이 방법으로 해결했습니다.

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

그리고 onCreate ..

@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

에 대한 진저 브레드 구현을 찾은 후 recreate다음 코드 (진저 브레드)를 사용하고 싶습니다.

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

이러한 코드의 경우 상위 API의 구현에서 가져온 것입니다.

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에는 requestRelaunchActivity가 없지만 diff에서 다음을 발견했습니다.

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

그래서 scheduleRelaunchActivity대신 requestRelaunchActivity.

그리고 reflect를 사용하여 작성했습니다.

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

}

xposed 프레임 워크의 백 포팅에이 코드를 사용하고 있습니다.


환상적인 작품! 에뮬레이터에서 테스트 한 결과이 접근 방식은 Build.VERSION_CODES.ECLAIR_MR1(v7) 과 역 호환됩니다 . 이전 버전에서도 작동 할 수 있습니다.
Tim Cooke

3

recreate() 활동을 다시 만들려는 위치 에서 메서드를 호출합니다 . 이 메서드는를 사용 onDestroy()하여 활동의 현재 인스턴스를 파괴 한 다음을 사용하여 활동을 다시 만듭니다 onCreate().


1

이것이 문제인 경우 활동을 채우는보기를 수행하는 다른 방법을 구현해야합니다. 다시 실행하는 대신 몇 가지 인수로 채우기 메서드를 호출 onCreate()하도록 만들어야합니다 onCreate(). 데이터가 변경되면 채우기 메서드가 다른 인수와 함께 호출되어야합니다.


1

내가 그것을 해결 한 방법은 Fragments 를 사용하는 것입니다. . 이들은 지원 라이브러리를 사용하여 API 4까지 이전 버전과 호환됩니다.

FrameLayout이있는 "래퍼"레이아웃을 만듭니다.

예:

<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>

그런 다음 원하는 시간에 FrameLayout을 바꿀 수있는 FragmentActivity를 만듭니다.

예:

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

Fragment에서 팽창 / 교체 할 수 있습니다. onStart 및 onCreateView를 정상적으로 활동의 onCreate를 사용하는 것처럼 사용할 수 있습니다.

예:

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

또한 상황에 따라, 당신은해야 할 수도 있습니다 getActivity().recreate();대신 단지recreate() .

예를 들어, recreate()액티비티 클래스 내부에 생성 된 클래스에서 하고 있다면 사용해야합니다 .


0

한 번은 Firebase 클라우드 저장소를 사용하여 데이터베이스 파일을 업로드, 삭제, 다시 다운로드하는 테스트 앱을 만들었습니다. 데이터베이스에 데이터를 표시하기 위해 다음 코드가 내가 찾은 유일한 솔루션이었습니다. 이 경우 recreate()에도 finish()작동 하지 않았습니다 .

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

0

데이터 변경시 Fragment를 새로 고치는 가장 좋은 방법을 찾았습니다.

"검색"버튼이있는 경우 버튼 내부에 ARRAY 목록을 초기화해야합니다.

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 ()에 매개 변수를 전달하려면 여분을 추가하여 새 인 텐트를 생성하고이를 사용하여 StartActivity를 호출해야합니다. 여기 내가 이런 식으로 한 간단한 예가 있습니다.

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

나쁜 명명 규칙, 나쁜 변수 이름, 정말 혼란 코드 ... -1
아메드 아델 이스마일

-4

당신이 당신의 견해를 다시하고 싶다면 똑같은 문제가 있습니다. 에서 onResume기능이 퍼팅 시도 :

mView = new AndroidPinballView(getApplication());

이것은 또한 내 onCreate(), 그래서 이것을 넣어서 onResume나를 위해 일했습니다 :)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.