प्रोग्रामेटिक रूप से किसी गतिविधि को फिर से शुरू करना / बहलाना?


121

अपने डेटाबेस में कुछ परिवर्तन करने के बाद, जिसमें मेरे विचारों में महत्वपूर्ण बदलाव शामिल है, मैं पुनः बनाना चाहता हूं, फिर से क्रिएट पर फिर से अमल करना चाहता हूं।

वो कैसे संभव है?

जवाबों:


129

अद्यतन : एंड्रॉइड एसडीके 11 ने recreate()गतिविधियों में एक विधि जोड़ी ।


मैंने यह किया है कि इस गतिविधि को शुरू करने वाले इरादे का पुन: उपयोग करके। starterIntentअपनी कक्षा में एक इरादे को परिभाषित करें और इसे onCreate()उपयोग करने में निर्दिष्ट करें starterIntent = getIntent();। फिर जब आप गतिविधि को पुनरारंभ करना चाहते हैं, तो कॉल करेंfinish(); startActivity(starterIntent);

यह एक बहुत ही सुंदर समाधान नहीं है, लेकिन यह आपकी गतिविधि को फिर से शुरू करने और सब कुछ पुनः लोड करने के लिए मजबूर करने का एक सरल तरीका है।


8
वास्तव में मुझे लगता है कि जब डिवाइस ओरिएंटेशन बदल जाता है तो गतिविधि की ऑन्क्रिएट को इसी तरह से बुलाया जाता है .. इसलिए मुझे ऐसा करने में कोई आपत्ति नहीं है। startActivity (getIntent ()); समाप्त();
राजा

यह स्टार्टअक्टिविटी (getIntent ()) करने के लिए स्मार्ट नहीं है क्योंकि यह गतिविधियों के शीर्ष पर गतिविधियों को लेयर करेगा। पुरानी गतिविधि को समाप्त करने की आवश्यकता है
फॉलेंप्रिपर

8
@Fallenreaper मैंने ठीक उसी कारण से finish()तुरंत कॉल करने का सुझाव दिया startActivity()...
स्टीव हेली

7
मैं पहली बार बुला यह हासिल की finish();तोstartActivity(starterIntent);
कार्लो Rodríguez

3
तो यह कौन सा है? खत्म () और फिर शुरुआत? या फिर इसके विपरीत?
जेफ पडगेट

92

गतिविधि की रीक्रिएट विधि को कॉल करें ।


19
यह ठीक है अगर आपका ऐप केवल एसडीके स्तर 11 और इसके बाद के संस्करण को लक्षित कर रहा है। नहीं तो मैं स्टीव हेली के दृष्टिकोण के साथ जाता।
TalkLittle 22

1
@FernandoEscher दुर्भाग्य से यह केवल हनीकॉम्ब उपकरणों और ऊपर उपलब्ध है।
इगोरगानापोलस्की

2
जहाँ
रीक्रिएट

1
रीक्रिएट मेथड कॉल रीपैटेडली फ्रिक्वेंटली एप को बंद करें
सिंड्रोइड

मैं उपयोग करता था, recreate()लेकिन अब मुझे एक अजीब समस्या दिखाई देती है जहां रेडियो बटन को रीक्रिएट करने पर रीसेट नहीं मिलता है, लेकिन वे ऐसा तब करते हैं जब finish(); startActivity(getIntent());मैं अभी इसके लिए उपयोग कर रहा हूं और देखता हूं कि यह अगले दिनों या हफ्तों में कैसे काम करता है।
बेन

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()वास्तव में पूरी तरह से गतिविधि को फिर से बनाने के समान कार्य नहीं करता है। यह डिवाइस को घुमाने के बराबर है इसलिए यदि आपके पास कोई Fragmentएस है तो setRetainInstance(true)उन्हें फिर से बनाया नहीं जाएगा; केवल रुका हुआ और फिर से शुरू हुआ।

इसलिए वर्तमान में मुझे विश्वास नहीं है कि एक स्वीकार्य समाधान है।


5
Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMBउपयोग करने के बजाय11
S.Thiongane

4
11 कठोर है, .HONEYCOMB सही नहीं है, क्योंकि SDK <11 में आपका कोड wtat नहीं पता है HONEYCOMB है।
तापी सेव

6
की जगह startActivity(getIntent());finish();के लिएfinish();startActivity(getIntent());
अहमद hamdy

नहीं, अनुशंसा के अनुसार आपको उच्चतम उपलब्ध एसडीके को लक्षित करना चाहिए, इसलिए मधुकोश संकलन के समय उपलब्ध होगा, और आपके एप्लिकेशन के भीतर इंट कॉन्स्टेंट चलाया जाता है। मेरा मानना ​​है कि यह एक सामान्य पैटर्न है जो न्यूनतम 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 के साथ एक समस्या यह है कि पिछली गतिविधि को बैकस्टैक में जोड़ा जाता है। इसे कई बार कॉल करें और वास्तविक पिछले पृष्ठ पर पहुंचने के लिए आपके उपयोगकर्ता को कई बार वापस क्लिक करना होगा।
ओली

23

जब मुझे किसी गतिविधि को पुनरारंभ करने की आवश्यकता होती है, तो मैं निम्नलिखित कोड का उपयोग करता हूं। हालांकि यह अनुशंसित नहीं है।

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

1
बहुत साफ और सुरुचिपूर्ण समाधान। प्री-एसडी 11 उपकरणों पर बढ़िया काम करता है।
इगोरगानापोलस्की

Super.recreate () विधि के साथ समस्या थी, लेकिन यह लॉलीपॉप पर ठीक काम करता है

6

11 से पहले एपीआई के लिए आप विश्राम () का उपयोग नहीं कर सकते। मैंने इस तरह से हल किया:

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

इन कोडों के लिए, यह उच्च एपीआई में कार्यान्वयन से है।

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 का कोई अनुरोध नहीं है। हालांकि, इस अंतर से, मुझे यह पता चला:

             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

और मैंने उन्हें दर्शाते हुए लिखा है:

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) के अनुकूल है । यह पुराने संस्करणों पर भी काम कर सकता है।
टिम कुक

3

उस recreate() विधि को कॉल करें जहां से आप अपनी गतिविधि को फिर से बनाना चाहते हैं। यह पद्धति गतिविधि की वर्तमान आवृत्ति को नष्ट कर देगी onDestroy()और फिर गतिविधि को फिर से बनाएगी onCreate()


1

यदि यह आपकी समस्या है, तो आपको संभवतः अपनी गतिविधि में दृश्य भरने के लिए एक और तरीका लागू करना चाहिए। फिर से दौड़ने के बजाय onCreate()आपको इसे बनाना चाहिए ताकि onCreate()कुछ तर्क के साथ आपके भरने की विधि को कॉल किया जा सके । जब डेटा बदलता है, तो भरने की विधि को किसी अन्य तर्क के साथ बुलाया जाना चाहिए।


1

जिस तरह से मैंने इसे हल किया वह फ्रेगमेंट्स का उपयोग करके है । समर्थन पुस्तकालय का उपयोग करके एपीआई 4 तक ये पीछे की ओर संगत हैं।

आप इसमें एक फ्रेम-आउट के साथ "रैपर" लेआउट बनाते हैं।

उदाहरण:

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

फिर आप एक 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();
  }

फ्रैगमेंट में आप / को फुलाते / प्रतिस्थापित करते हैं, आप 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

मैंने एक बार एक परीक्षण ऐप बनाया था जो फायरबेस क्लाउड स्टोरेज का उपयोग करके डेटाबेस फ़ाइल को अपलोड, डिलीट और फिर डाउनलोड करता है। डेटाबेस में डेटा प्रदर्शित करने के लिए, निम्नलिखित कोड एकमात्र समाधान था जो मुझे मिला। न तो recreate()है और न ही finish()इस मामले में काम किया।

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

0

जब डेटा में बदलाव होता है तो मुझे आपके फ्रैगमेंट को ताज़ा करने का सबसे अच्छा तरीका पता चला

यदि आपके पास एक बटन "खोज" है, तो आपको बटन के अंदर अपनी ARRAY सूची को इनिशियलाइज़ करना होगा

mSearchBtn.setOnClickListener (नया दृश्य .nClickListener () {

@ ऑवरराइड सार्वजनिक शून्य पर क्लिक करें (देखें 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मेरे लिए काम में लाना :)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.