2010-08-20 12 views
14

मेरे पास सतह दृश्य सेटअप और चल रहा है, लेकिन जब मैं इसे फिर से शुरू करता हूं तो मुझे एक त्रुटि मिलती है कि थ्रेड पहले ही शुरू हो चुका है। जब ऐप पृष्ठभूमि में जाता है और फिर अग्रभूमि पर वापस जाता है तो उसे संभालने का उचित तरीका क्या है? मैं चारों ओर झुका हुआ और ऐप को दुर्घटनाग्रस्त किए बिना वापस आने में कामयाब रहा ... लेकिन सतह दृश्य अब और कुछ नहीं खींचता है। मेरा कोड:सतह को रोकने और फिर से शुरू करने के लिए कैसे देखें

@Override 
    public void surfaceCreated(SurfaceHolder holder) { 
      Log.e("sys","surfaceCreated was called."); 
      if(systemState==BACKGROUND){ 
        thread.setRunning(true); 

      } 
      else { 
     thread.setRunning(true); 
       thread.start(); 
       Log.e("sys","started thread"); 
       systemState=READY; 
      } 



    } 
    @Override 
    public void surfaceDestroyed(SurfaceHolder holder) { 
      Log.e("sys","surfaceDestroyed was called."); 
      thread.setRunning(false); 
      systemState=BACKGROUND; 
    } 

उत्तर

11

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

अब SurfaceView चलाने वाली गतिविधि में, आपको SurfaceView में गतिविधि (या खंड) पर रेज़्यूम() और रोकें() विधियों को रेज़्यूम() और ऑन पॉज़() पर कॉल करने की आवश्यकता होगी। यह एक सुरुचिपूर्ण समाधान नहीं है, लेकिन यह काम करेगा।

+0

मुझे उर विचार पसंद है, मैं कुछ आसान खोजने के लिए चारों ओर काम कर रहा हूं। क्योंकि "सतही डाइस्ट्रॉयड" हर बार नहीं कहा जाता है लेकिन "ऑन पॉज़" होता है। बस "पावर" बटन दबाकर वापस लौटें। तो मुझे लगता है कि आपकी पसंद वास्तव में एक अच्छी है। –

0

आपको क्रियाएँ() और ऑनस्यूम() विधियों पर क्रियाकलापों का उपयोग करना चाहिए।

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

+0

मैं इसे ठीक से उपयुक्त स्थानों में setRunning का उपयोग करने के लिए सेट है, लेकिन होने thread.setRunning (सही) के बावजूद मेरी onResume मेरी SurfaceView में खाली है जब अपनी पीठ सबसे आगे में। धागा अभी भी वहां है, जब मैं होम स्क्रीन पर जाता हूं तो यह ऐप को क्रैश नहीं करता है, और यदि मैं एक और थ्रेड कोशिश करता हूं। स्टार्ट() मुझे यह कहते हुए त्रुटि मिलती है कि धागे शुरू हो गए हैं। कोई विचार? – jfisk

+0

आप केवल एक बार धागा शुरू कर सकते हैं। मुझे नहीं पता कि आपकी सेट राइजिंग विधि अंदर क्या करती है, लेकिन एंड्रॉइड पर थ्रेड को ठीक से रोकने का एकमात्र तरीका यह है कि इसे अपनी रन() विधि से वापस कर दें। उस बिंदु से, आपको 'नया' थ्रेड ऑब्जेक्ट बनाना होगा। आप उस धागे का फिर से उपयोग नहीं कर सकते। यदि आप थ्रेड को 'रोक' देना चाहते हैं, तो आपको प्रतीक्षा() और NOTifyAll() का उपयोग करना होगा। उदाहरण के लिए Google और इसके बारे में उचित समझ। – Moncader

2
public void surfaceCreated(SurfaceHolder holder) { 
     if (!_thread.isAlive()) { 
      _thread = new MyThread(this, contxt); 
     } 

public void surfaceDestroyed(SurfaceHolder holder) {    
     boolean retry = true; 
     _thread.setRunning(false); 
     while (retry) { 
      try { 
       _thread.join(); 
       retry = false; 
      } catch (InterruptedException e) { 
       // we will try it again and again... 
      } 
     } 
    } 
+0

मैं सतही दृश्य सीख रहा हूं लेकिन यह नहीं समझ सकता कि आप थोड़ी देर के दौरान ब्रेक स्टैमनेट का उपयोग क्यों नहीं कर रहे हैं। मेरा कार्यक्रम ऑनस्यूम() के दौरान जम गया, लेकिन जब मैंने ब्रेक लगाया तो यह शुरू हो गया, स्पष्ट रूप से एक नया धागा बनाया गया था। यह मेरा कोड और प्रश्न है: http://stackoverflow.com/questions/19200972/android-surfaceview-cant-resume-activity-from-pause – Luther

+0

Thread.join() के बारे में पढ़ें तो आप समझेंगे। –

+0

गतिविधि 'ऑनपॉज़' ** ** ** हमेशा 'सतह डीस्ट्रायर्ड' को अपने आप पर नहीं बुलाएगी। तो यह अकेले समस्या को हल नहीं करेगा। यह प्रश्न देखें http://stackoverflow.com/q/11495842/1180117 – Kiran

0

यह अच्छा ज्ञात समस्या के लिए एक अन्य समाधान। अफसोस की बात है, मुझे समझ में नहीं आता कि यह क्यों काम करता है - यह गलती से बाहर आया। लेकिन यह मेरे लिए अच्छा काम करता है और इसे कार्यान्वित करना आसान है: Activity के onPause(), onResume(), onStart(), onStop(), और विशेष थ्रेड विधियों (जैसे resume(), pause()) की आवश्यकता नहीं है।

विशेष आवश्यकता है थ्रेड क्लास को प्रस्तुत करने के अलावा किसी अन्य चीज़ में सभी बदलते चर डालना।

मुख्य अंक में जोड़ने के लिए प्रस्तुत करना धागा वर्ग:

class RefresherThread extends Thread { 
    static SurfaceHolder threadSurfaceHolder; 
    static YourAppViewClass threadView; 
    static boolean running; 

    public void run(){ 
     while(running){ 
      //your amazing draw/logic cycle goes here 
     } 
    } 
} 

अब, महत्वपूर्ण बातें YourAppViewClass के बारे में:

class YourAppViewClass extends SurfaceView implements SurfaceHolder.Callback { 
    static RefresherThread surfaceThread; 

    public YourAppViewClass(Activity inpParentActivity) { 
     getHolder().addCallback(this); 
     RefresherThread.threadSurfaceHolder = getHolder(); 
     RefresherThread.threadView = this; 
    } 

    @Override 
    public void surfaceCreated(SurfaceHolder holder) { 
     surfaceThread = new RefresherThread(); 
     surfaceThread.running=true; 
     surfaceThread.start(); 
    } 

    @Override 
    public void surfaceDestroyed(SurfaceHolder holder) { 
     surfaceThread.running=false; 
     try { 
      surfaceThread.join(); 
     } catch (InterruptedException e) { 
     }    
    } 
} 

दो कोड ब्लॉक ऊपर पूर्ण लिखा कक्षाएं नहीं है, लेकिन मात्र धारणा हैं जो आदेश देता है कि किस तरीके की आवश्यकता है। यह भी ध्यान रखें कि ऐप पर प्रत्येक वापसी surfaceChanged() को आमंत्रित करती है।

ऐसे अंतरिक्ष उपभोग करने वाले उत्तर के लिए खेद है। मुझे उम्मीद है कि यह ठीक से काम करेगा और मदद करेगा।

+0

गतिविधि 'ऑन पॉज़' ** ** ** ** हमेशा' सतह डीस्ट्रायर्ड 'को अपने आप पर नहीं बुलाएगी। तो यह समस्या को हल नहीं करेगा। यह प्रश्न देखें http://stackoverflow.com/q/11495842/1180117 – Kiran

1

उपर्युक्त स्वीकृत उत्तर पर टिप्पणी करने का प्रयास किया लेकिन यह नया नहीं हो सका। मुझे नहीं लगता कि आपको अपनी सतह दृश्य और गतिविधि दोनों से अपनी स्टार्ट/स्टॉप थ्रेड विधियों को कॉल करना चाहिए। इसके परिणामस्वरूप थ्रेड को दोगुना शुरू/बंद कर दिया जाएगा, और आप एक से अधिक बार धागा शुरू नहीं कर सकते हैं। बस अपनी विधियों को गतिविधि के ऑन पॉज़ और ऑन्यूज़ से कॉल करें। ऐप से बाहर निकलने और फिर से प्रवेश करने पर उन्हें बुलाया जाता है ताकि यह सुनिश्चित हो सके कि आपके राज्य ठीक से संभाले जा रहे हैं। सतह डीस्ट्रॉयड हमेशा नहीं कहा जाता है, जो मुझे थोड़ी देर के लिए गड़बड़ कर देता है।

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

 while (_run) { 
      if (_surfaceHolder.getSurface().isValid()) { 
       ... 
      } 
     } //end _run 
+0

एक वापस ले लिया गया टिप्पणी – tjb

2

सबसे अच्छा तरीका है मैं पाया है गतिविधि सतह दृश्य को नियंत्रित ताकि विधि इसके साथ फिर से को दर्शाता है SurfaceView की onResume विधि ओवरराइड करने के लिए है और फिर setContentView साथ यह तय करता है। इस दृष्टिकोण के साथ समस्या यह है कि आपको किसी भी राज्य को पुनः लोड करने की आवश्यकता है कि आपकी SurfaceView का ख्याल रख रहा था।

public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     setContentView(new MyCustomSurfaceView(this)); 
    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
     setContentView(new MyCustomSurfaceView(this)); 
    } 
+0

यह मेरे लिए चाल है। जब मैंने इसे केवल रेज़्यूम में करने से पहले कोशिश की तो यह काम नहीं कर सका। – sivi

1

यही वह है जो मैंने उपयोग किया है। ऐप अब क्रैश नहीं करता है।

देखें कक्षा:

holder.addCallback(new Callback() { 

     public void surfaceDestroyed(SurfaceHolder holder) { 
      gameLoopThread.setRunning(false); 
      gameLoopThread.stop(); 
     } 

     public void surfaceCreated(SurfaceHolder holder) { 
      gameLoopThread.setRunning(true); 
      gameLoopThread.start(); 

     } 

GameLoopThread में:

private boolean running = false; 

public void setRunning(boolean run) { 
    running = run; 
} 
@Override 
public void run() { 
    long ticksPs=1000/FPS; 
    long startTime; 
    long sleepTime; 

while(running){ 
     Canvas c = null; 
     startTime=System.currentTimeMillis(); 
     try { 
      c = view.getHolder().lockCanvas(); 
      synchronized (view.getHolder()) { 

       view.onDraw(c); 

      } 

     } finally { 

      if (c != null) { 
       view.getHolder().unlockCanvasAndPost(c); 
      } 

     } 
     sleepTime=ticksPs-(System.currentTimeMillis()-startTime); 
     try{ 

      if(sleepTime>0){ 
       sleep(sleepTime); 
      } 
      else 
       sleep(10); 
     } catch(Exception e){} 
} 

} 

मुझे आशा है कि यह मदद मिलेगी।

+0

गतिविधि 'ऑन पॉज़' ** ** ** ** सतह पर 'सतह डीस्ट्रायर्ड' का आह्वान नहीं करेगा। तो यह समस्या को हल नहीं करेगा। यह प्रश्न देखें http://stackoverflow.com/q/11495842/1180117 – Kiran

4

यह बग चंद्र लैंडर बग से संबंधित प्रतीत होता है, जो काफी प्रसिद्ध है (उस पर Google खोज करें)। इस बार के बाद, और कई एंड्रॉइड संस्करण रिलीज के बाद, बग अभी भी मौजूद है और किसी ने इसे अपडेट करने के लिए परेशान नहीं किया है। मैं ने पाया है यह कम से कम कोड अव्यवस्था के साथ काम करने के लिए:

public void surfaceCreated(SurfaceHolder holder) {  
      if (thread.getState==Thread.State.TERMINATED) { 
       thread = new MainThread(getHolder(),this); 
      } 
      thread.setRunning(true); 
      thread.start(); 
    } 
+0

गतिविधि 'ऑन पॉज़' ** ** ** ** सतह पर 'सतह' का उपयोग नहीं करेगा। तो यह अकेले समस्या को हल नहीं करेगा। यह प्रश्न http://stackoverflow.com/q/11495842/1180117 देखें – Kiran

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