2013-03-22 9 views
65

मेरे पास FragmentActivity कक्षा है जिसमें आंतरिक कक्षा है जो Dialog प्रदर्शित करना चाहिए। लेकिन मुझे इसे static बनाने की आवश्यकता है। ग्रहण मुझे @SuppressLint("ValidFragment") के साथ त्रुटि दबाने के लिए प्रदान करता है। क्या यह खराब शैली है यदि मैं ऐसा करता हूं और संभावित परिणाम क्या हैं?टुकड़ा आंतरिक वर्ग स्थिर होना चाहिए

public class CarActivity extends FragmentActivity { 
//Code 
    @SuppressLint("ValidFragment") 
    public class NetworkConnectionError extends DialogFragment { 
    private String message; 
    private AsyncTask task; 
    private String taskMessage; 
    @Override 
    public void setArguments(Bundle args) { 
     super.setArguments(args); 
     message = args.getString("message"); 
    } 
    public void setTask(CarActivity.CarInfo task, String msg) { 
     this.task = task; 
     this.taskMessage = msg; 
    } 
    @Override 
    public Dialog onCreateDialog(Bundle savedInstanceState) { 
     // Use the Builder class for convenient dialog construction 
     AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 
     builder.setMessage(message).setPositiveButton("Go back", new DialogInterface.OnClickListener() { 
     @Override 
     public void onClick(DialogInterface dialog, int id) { 
      Intent i = new Intent(getActivity().getBaseContext(), MainScreen.class); 
      startActivity(i); 
     } 
     }); 
     builder.setNegativeButton("Retry", new DialogInterface.OnClickListener() { 
     @Override 
     public void onClick(DialogInterface dialog, int id) { 
      startDownload(); 
     } 
     }); 
     // Create the AlertDialog object and return it 
     return builder.create(); 
    } 
    } 

startDownload() Asynctask शुरू होता है।

+1

फाहा अनदेखी करने के लिए सामान्य अपने बुरे व्यवहार में कोड – rkmax

+2

दिखा सकते हैं। यह एक बहुत ही स्मार्ट उपकरण है। अपने कोड को पोस्ट करने का प्रयास करें, वास्तव में यह जानने के लिए कि आप बेहतर काम कैसे कर सकते हैं। –

+0

क्या आपने यह जानने के लिए यह http://code.google.com/p/android/issues/detail?id=41800 चेक किया है कि ValidFragment के बारे में है? लिंट कहती है कि: 'प्रत्येक टुकड़े में एक खाली कन्स्ट्रक्टर होना चाहिए, इसलिए इसे तत्काल' – sandrstar

उत्तर

88

गैर स्थैतिक आंतरिक वर्ग उनके मूल वर्गों का संदर्भ रखते हैं। एक टुकड़ा आंतरिक वर्ग गैर स्थैतिक बनाने में समस्या यह है कि आप हमेशा गतिविधि का संदर्भ रखते हैं। GarbageCollector आपकी गतिविधि एकत्र नहीं कर सकता है। तो यदि आप उदाहरण के लिए अभिविन्यास बदलते हैं तो आप गतिविधि 'रिसाव' कर सकते हैं। क्योंकि टुकड़ा अभी भी जीवित रह सकता है और एक नए गतिविधि में डाला जा सकता है।

संपादित करें:

के बाद से कुछ लोग मुझे कुछ उदाहरण मैं एक लेखन शुरू करने के लिए कहा है, जबकि यह कर मैं कुछ और अधिक समस्याओं जब गैर स्थिर टुकड़े का उपयोग कर पाया:

  • वे में नहीं किया जा सकता एक एक्सएमएल फ़ाइल क्योंकि उनके पास खाली कन्स्ट्रक्टर नहीं है (उनके पास एक खाली कन्स्ट्रक्टर हो सकता है, लेकिन आप आमतौर पर myActivityInstance.new Fragment() करके गैरस्टिक घोंसला वाले वर्गों को तुरंत चालू करते हैं और यह केवल खाली कन्स्ट्रक्टर को कॉल करने के लिए अलग है)
  • वे बी नहीं कर सकते ई बिल्कुल उपयोग किया गया - चूंकि FragmentManager कभी-कभी इस खाली कन्स्ट्रक्टर को भी कॉल करता है। यदि आपने कुछ लेनदेन में फ्रैगमेंट जोड़ा है।

तो आदेश मेरे उदाहरण काम करने के लिए में मैं

wrongFragment.setRetainInstance(true); 

लाइन को जोड़ने के लिए उन्मुखीकरण परिवर्तन पर ऐप्लिकेशन क्रैश नहीं किया था।

यदि आप इस कोड को निष्पादित करते हैं तो आपके पास कुछ टेक्स्टव्यू और 2 बटन के साथ एक गतिविधि होगी - बटन कुछ काउंटर बढ़ाते हैं। और टुकड़े उन्मुखीकरण को दिखाते हैं जो उन्हें लगता है कि उनकी गतिविधि है। शुरुआत में सब ठीक से काम करता है। लेकिन स्क्रीन अभिविन्यास को बदलने के बाद केवल पहला फ्रैगमेंट काम करता है - दूसरा अभी भी अपनी पुरानी गतिविधि में सामान बुला रहा है।

मेरी गतिविधि वर्ग:

package com.example.fragmenttest; 

import android.annotation.SuppressLint; 
import android.app.Activity; 
import android.app.Fragment; 
import android.app.FragmentTransaction; 
import android.content.res.Configuration; 
import android.os.Bundle; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.Button; 
import android.widget.LinearLayout; 
import android.widget.TextView; 

public class WrongFragmentUsageActivity extends Activity 
{ 
private String mActivityOrientation=""; 
private int mButtonClicks=0; 
private TextView mClickTextView; 


private static final String WRONG_FRAGMENT_TAG = "WrongFragment" ; 

@Override 
protected void onCreate(Bundle savedInstanceState) 
{ 
    super.onCreate(savedInstanceState); 
    int orientation = getResources().getConfiguration().orientation; 
    if (orientation == Configuration.ORIENTATION_LANDSCAPE) 
    { 
     mActivityOrientation = "Landscape"; 
    } 
    else if (orientation == Configuration.ORIENTATION_PORTRAIT) 
    { 
     mActivityOrientation = "Portrait"; 
    } 

    setContentView(R.layout.activity_wrong_fragement_usage); 
    mClickTextView = (TextView) findViewById(R.id.clicksText); 
    updateClickTextView(); 
    TextView orientationtextView = (TextView) findViewById(R.id.orientationText); 
    orientationtextView.setText("Activity orientation is: " + mActivityOrientation); 

    Fragment wrongFragment = (WrongFragment) getFragmentManager().findFragmentByTag(WRONG_FRAGMENT_TAG); 
    if (wrongFragment == null) 
    { 
     wrongFragment = new WrongFragment(); 
     FragmentTransaction ft = getFragmentManager().beginTransaction(); 
     ft.add(R.id.mainView, wrongFragment, WRONG_FRAGMENT_TAG); 
     ft.commit(); 
     wrongFragment.setRetainInstance(true); // <-- this is important - otherwise the fragment manager will crash when readding the fragment 
    } 
} 

private void updateClickTextView() 
{ 
    mClickTextView.setText("The buttons have been pressed " + mButtonClicks + " times"); 
} 

private String getActivityOrientationString() 
{ 
    return mActivityOrientation; 
} 


@SuppressLint("ValidFragment") 
public class WrongFragment extends Fragment 
{ 


    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    { 
     LinearLayout result = new LinearLayout(WrongFragmentUsageActivity.this); 
     result.setOrientation(LinearLayout.VERTICAL); 
     Button b = new Button(WrongFragmentUsageActivity.this); 
     b.setText("WrongFragmentButton"); 
     result.addView(b); 
     b.setOnClickListener(new View.OnClickListener() 
     { 
      @Override 
      public void onClick(View v) 
      { 
       buttonPressed(); 
      } 
     }); 
     TextView orientationText = new TextView(WrongFragmentUsageActivity.this); 
     orientationText.setText("WrongFragment Activities Orientation: " + getActivityOrientationString()); 
     result.addView(orientationText); 
     return result; 
    } 
} 

public static class CorrectFragment extends Fragment 
{ 
    private WrongFragmentUsageActivity mActivity; 


    @Override 
    public void onAttach(Activity activity) 
    { 
     if (activity instanceof WrongFragmentUsageActivity) 
     { 
      mActivity = (WrongFragmentUsageActivity) activity; 
     } 
     super.onAttach(activity); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    { 
     LinearLayout result = new LinearLayout(mActivity); 
     result.setOrientation(LinearLayout.VERTICAL); 
     Button b = new Button(mActivity); 
     b.setText("CorrectFragmentButton"); 
     result.addView(b); 
     b.setOnClickListener(new View.OnClickListener() 
     { 
      @Override 
      public void onClick(View v) 
      { 
       mActivity.buttonPressed(); 
      } 
     }); 
     TextView orientationText = new TextView(mActivity); 
     orientationText.setText("CorrectFragment Activities Orientation: " + mActivity.getActivityOrientationString()); 
     result.addView(orientationText); 
     return result; 
    } 
} 

public void buttonPressed() 
{ 
    mButtonClicks++; 
    updateClickTextView(); 
} 

} 

ध्यान दें कि आप शायद onAttach में गतिविधि डाली नहीं करना चाहिए आप विभिन्न गतिविधियों में अपने टुकड़ा उपयोग करना चाहते हैं - लेकिन यहाँ के लिए उदाहरण के लिए अपने काम कर रहे।

activity_wrong_fragement_usage.xml:

<LinearLayout 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:orientation="vertical" 
tools:context=".WrongFragmentUsageActivity" 
android:id="@+id/mainView"> 

<TextView 
    android:id="@+id/orientationText" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="" /> 

<TextView 
    android:id="@+id/clicksText" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="" /> 



<fragment class="com.example.fragmenttest.WrongFragmentUsageActivity$CorrectFragment" 
      android:id="@+id/correctfragment" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" /> 


</LinearLayout> 
+0

बहुत ही रोचक और शायद बहुत उपयोगी जवाब। मैं एक ही मुद्दे से निपट रहा हूं। क्या आप किसी प्रकार के स्रोत को छोड़ने पर ध्यान देंगे कि आपका उत्तर इस पर आधारित है? – Egis

+3

@Egis शायद यह आपको नेस्टेड-स्थैतिक आंतरिक कक्षाओं के बारे में कुछ अंतर्दृष्टि दे सकता है: http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html। – AxeEffect

+1

क्या आपके पास इस उत्तर का संदर्भ है? –

5

यू एंड्रॉयड स्टूडियो में इसे विकसित तो कोई समस्या नहीं है आप नहीं यह रूप में स्थिर देते हैं।प्रोजेक्ट बिना किसी त्रुटि के चलाएगा और एपीके की पीढ़ी के समय आपको त्रुटि मिलेगी: यह खंड आंतरिक वर्ग स्थिर होना चाहिए [वैधफ्रेगमेंट]

थैट्स लिंट त्रुटि, आप शायद गलती के साथ निर्माण कर रहे हैं, त्रुटियों पर निरस्त करने के लिए , जोड़ें:

lintOptions { 
    abortOnError false 
} 

build.gradle के लिए। `

+6

हटा दिया गया है, ठीक है, यह भवन की प्रक्रिया को पारित करेगा, लेकिन क्या इसका उपयोग इस तरह से करना सही है? क्योंकि वहां एक लीकिंग मेमोरी समस्या है और यही कारण है कि एंड्रॉइड स्टूडियो हमें चेतावनी देता है। – XcodeNOOB

+0

कभी-कभी मुझे लगता है कि गलत करने के लिए abortOnError मुश्किल है, मैं कमजोर या जानकारी के लिए लिंट के नियम को अनुकूलित करना पसंद करता हूं "आंतरिक वर्ग स्थिर होना चाहिए"। –

16

मैं आंतरिक टुकड़ों के बारे में बात नहीं करूंगा, लेकिन विशेष रूप से एक गतिविधि के भीतर परिभाषित डायलॉग फ्रैगमेंट के बारे में अधिक जानकारी क्योंकि यह इस प्रश्न के लिए 99% मामला है।
मेरे दृष्टिकोण से, मैं नहीं चाहता कि मेरा डायलॉगफ्रैगमेंट (आपका नेटवर्क कनेक्शन कनेक्शन) स्थिर हो क्योंकि मैं इसमें अपनी कक्षा (गतिविधि) से चर या विधियों को कॉल करने में सक्षम होना चाहता हूं।
यह स्थैतिक नहीं होगा, लेकिन मैं स्मृति स्मृति उत्पन्न नहीं करना चाहता हूं।
समाधान क्या है?
सरल। जब आप स्टॉप पर जाते हैं, तो सुनिश्चित करें कि आप अपने डायलॉग फ्रैगमेंट को मार दें। यह इतना सरल है। कोड ऐसा ही कुछ दिखाई देता है:

public class CarActivity extends AppCompatActivity{ 

/** 
* The DialogFragment networkConnectionErrorDialog 
*/ 
private NetworkConnectionError networkConnectionErrorDialog ; 
//... your code ...// 
@Override 
protected void onStop() { 
    super.onStop(); 
    //invalidate the DialogFragment to avoid stupid memory leak 
    if (networkConnectionErrorDialog != null) { 
     if (networkConnectionErrorDialog .isVisible()) { 
      networkConnectionErrorDialog .dismiss(); 
     } 
     networkConnectionErrorDialog = null; 
    } 
} 
/** 
* The method called to display your dialogFragment 
*/ 
private void onDeleteCurrentCity(){ 
    FragmentManager fm = getSupportFragmentManager(); 
    networkConnectionErrorDialog =(DeleteAlert)fm.findFragmentByTag("networkError"); 
    if(networkConnectionErrorDialog ==null){ 
     networkConnectionErrorDialog =new DeleteAlert(); 
    } 
    networkConnectionErrorDialog .show(getSupportFragmentManager(), "networkError"); 
} 

और इस तरह आप मेमोरी लीक से बचने (क्योंकि यह बुरा है) और आप बीमा तुम एक [पूरक] स्थिर टुकड़ा है कि अपनी गतिविधि के क्षेत्रों और विधियों का उपयोग नहीं कर सकते हैं की जरूरत नहीं है । मेरे दृष्टिकोण से, उस समस्या को संभालने का यह एक अच्छा तरीका है।

+0

अच्छा लग रहा है, लेकिन क्या आपको –

+0

यप के नीचे उल्लिखित @hakri रेड्डी जैसे एपीके की पीढ़ी के समय त्रुटियां मिलेंगी, लेकिन ऐसा इसलिए नहीं है क्योंकि लिंट इतना स्मार्ट नहीं है कि हमें "बेवकूफ के रूप में" होने की आवश्यकता है, ज्ञापन रिसाव का उपयोग कर चला गया है यह तकनीकी (कैनरीलीक आपको दिखाएगा) ... वैसे, मैं पहली बार अपने एपीके को अन्य गलतियों का पता लगाने के लिए चलाता हूं जो मैंने अपने कोड में किया है, मुझे लगता है कि मुझे लगता है कि समस्या को ठीक करें और फिर इसे चलाने के साथ abortOnError झूठी। और कुछ प्रोजेक्ट पर, मैं इस विशिष्ट नियम पर लिंट को कस्टमाइज़ करता हूं ("इनर क्लास स्थिर होना चाहिए" कमजोर करने के लिए ड्रॉप) –

+0

ओह ... लेकिन मेरे मामले में, वास्तविक एपीके पीढ़ी अमेरिकी कार्यालय में बैठे विभिन्न टीम द्वारा की जाती है (मैं हूं भारत में, और मैं केवल गिट कोड भंडार लिंक प्रदान करता हूं) क्योंकि वे किसी भी व्यक्ति को कंपनी हस्ताक्षर प्रमाणपत्र फ़ाइलों को साझा नहीं करते हैं। तो वे निश्चित रूप से मेरे कारण को नहीं सुनेंगे और उनकी सेटिंग्स को बदलने के लिए नहीं जा रहे हैं :( –

3

आप बाहरी स्तरीय (गतिविधि) के सदस्यों तक पहुँचने के लिए और अभी भी नहीं के सदस्यों गतिविधि (के बाद से टुकड़ा सार्वजनिक स्थिर होना चाहिए) में स्थिर बनाना चाहते चाहते हैं, आप ओवरराइड onActivityCreated

public static class MyFragment extends ListFragment { 

    private OuterActivityName activity; // outer Activity 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 
     activity = (OuterActivityName) getActivity(); 
     ... 
     activity.member // accessing the members of activity 
     ... 
    } 
-1

कर सकते हैं भीतरी कक्षा से पहले टिप्पणी जोड़ने

@SuppressLint ("validFragment")

संबंधित मुद्दे