2016-02-29 8 views
9

Ho notato che altre applicazioni di puzzle dal negozio Google Play può arrivare fino a un massimo di 400 pezzi separati mobili del puzzleCome si crea un'app puzzle in droid senza esaurire la memoria?

mi hanno cercato di imparare a prendere almeno un'immagine che rappresenterà il mio rompicapo, Crop alcune sezioni e mascherano lo spazio immagine che è rimasto con un pezzo di puzzle per creare i miei singoli pezzi di puzzle

Voglio max out con 20 pezzi per la mia app ma finora secondo il mio log di memoria di Android studio una volta bitmap la fabbrica ha finito di creare un pezzo di puzzle sto usando circa 18mb di memoria, dopo che sono stati creati 20 pezzi insieme a tutte le altre funzioni dell'app, sto usando 400 + mb di memoria che devo usare "largeHeap = tru" e "per evitare di esaurire la memoria, ma sono così vicino a superare quei limiti superiori che l'app è superfluo e l'attività animata sufficiente inevitabilmente bloccherà l'app

Mi piacerebbe sapere cosa fanno questi altri giochi applicazioni del puzzle stanno facendo che non sono

qualsiasi ingresso è molto apprezzato

FYI sto usando PNG24 per le mie immagini e la dimensione la mia immagine di prova su è 556x720

Ecco un esempio se io dovevano semplicemente creare un'immagine animata del puzzle di un pezzo

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    this.requestWindowFeature(Window.FEATURE_NO_TITLE);//Remove title bar 
    this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//Hides notification bar 
    this.setContentView(R.layout.activity_main);//set content view AFTER ABOVE sequence (to avoid crash) 

    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 

    mainDisplay = getWindowManager().getDefaultDisplay(); 
    mainLayout = (ViewGroup) findViewById(R.id.id_layout); 

    DisplayMetrics m = new DisplayMetrics(); 
    this.getWindowManager().getDefaultDisplay().getMetrics(m); 
    int windowHeight = m.heightPixels; 
    int windowWidth = m.widthPixels; 

    offsetX = (windowWidth/1440.0f); 
    offsetY = (windowHeight/2560.0f); 

    ourContext = this; 

    xpos = new float[2]; 
    ypos = new float[2]; 

    iv_PuzzleOne(); 

    bkgdbm = BitmapFactory.decodeResource(getResources(), R.drawable.puzzleimage); 

    paintObject = new Paint(); 
    paintObject.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR)); 

    bm_PuzzleOne(); 

    thisTimerTask = new ThisClass(); 
    thisTimer = new Timer(); 
    thisTimer.scheduleAtFixedRate(thisTimerTask, 16, 16); 

    touchpad = new ImageButton(this); 
    SetPos(0, 0, 1440, 2560); 
    touchpad.setLayoutParams(layoutPositioner); 
    touchpad.getBackground().setAlpha(1); 
    mainLayout.addView(touchpad); 

    touchpad.setOnTouchListener(new View.OnTouchListener() { 

     //@SuppressLint("NewApi") 
     @Override 
     public boolean onTouch(View v, MotionEvent event) { 

      if (event.getAction() == MotionEvent.ACTION_DOWN) { 
       xpos[0] = event.getX(); //storing my finger's position coordinates when I first touch the screen into the 1st element 
       ypos[0] = event.getY(); 

       if ((event.getX() > imgx1) && (event.getX() < imgx1 + imagewidth1) 
         && (event.getY() > imgy1) && (event.getY() < imgy1 + imageheight1)) { 
        touching1Puzzle = true; 
        img1.bringToFront(); 
       } 

      } 

      if (event.getAction() == MotionEvent.ACTION_MOVE) { 

       xpos[1] = event.getX(); //add my finger's new current coordinates into the 2nd element 
       ypos[1] = event.getY(); 

       if (touching1Puzzle) { 
        adjustImg(); 
       } 
      } 

      if (event.getAction() == MotionEvent.ACTION_UP) { 
       if (touching1Puzzle) { 
        touching1Puzzle = false; 
       } 

      } 

      return false; 
     } 

    }); 
} 


void bm_PuzzleOne() 
{ 
    //start of 1st puzzle 

    foregdimg1 = BitmapFactory.decodeResource(getResources(), R.drawable.puzzlepieceprac);//puzzle cut out (42.48MB) +6.15 
    mutableforegdimg1 = foregdimg1.copy(Bitmap.Config.ARGB_8888, true); //(48.32MB) +5.84 

    compositeImage1 = Bitmap.createBitmap(mutableforegdimg1);//cuts out foreground info into bkgdimage (54.43MB) +6.11 

    imgCanvas1 = new Canvas(compositeImage1); //canvas references puzzle cut out image (54.43MB) +0 
    imgCanvas1.drawBitmap(croppedBmp, null, new Rect(0, 0, 1500, 2000), paintObject);//places puzzle image on canvas (54.43MB) +0 

    img1.setImageBitmap(compositeImage1); 

} 


void iv_PuzzleOne() 
{ 
    img1 = new ImageView(ourContext); 
    SetPos(imgx1, imgy1, imagewidth1, imageheight1); 
    //bkgdimg.setImageResource(R.drawable.c); 
    //img1.setBackgroundColor(0xffF07305); //Orange 
    img1.setLayoutParams(layoutPositioner); 
    mainLayout.addView(img1); 

} 

void adjustImg() 
{ 
    if (touching1Puzzle) 
    { 
     if (xpos[1] > xpos[0]) //if the image had slid to the right 
     { 
      xPositionDifference = xpos[1] - xpos[0]; // find the difference in coordinate value between where my finger was and where it currently is 
      imgx1 += xPositionDifference; //add that difference to the current image position ... 

      xpos[0] += xPositionDifference; // ... store that difference for the next shift in finger postion 

     } else if (xpos[1] < xpos[0]) //if the image had slid to the left 
     { 
      xPositionDifference = xpos[0] - xpos[1]; // find the difference in coordinate value between where my finger was and where it currently is 
      imgx1 -= xPositionDifference; //subtract that difference to the current image position ... 

      xpos[0] -= xPositionDifference; // ... store that difference for the next shift in finger postion 
     } 

     if (ypos[1] > ypos[0]) //if the image had slid to the right 
     { 
      yPositionDifference = ypos[1] - ypos[0]; // find the difference in coordinate value between where my finger was and where it currently is 
      imgy1 += yPositionDifference; //add that difference to the current image position ... 

      ypos[0] += yPositionDifference; // ... store that difference for the next shift in finger postion 

     } else if (ypos[1] < ypos[0]) //if the image had slid to the left 
     { 
      yPositionDifference = ypos[0] - ypos[1]; // find the difference in coordinate value between where my finger was and where it currently is 
      imgy1 -= yPositionDifference; //subtract that difference to the current image position ... 

      ypos[0] -= yPositionDifference; // ... store that difference for the next shift in finger postion 

     } 
    } 

} 

class ThisClass extends TimerTask { 

    @Override 
    public void run() { 
     MainActivity.this.runOnUiThread(new Runnable() { 
      @Override 
      public void run() { 

       if(touching1Puzzle) 
       {SetPos(imgx1, imgy1, imagewidth1, imageheight1); 
        img1.setLayoutParams(layoutPositioner);} 

      } 
     }); 
    } 
} 

public void SetPos(float x, float y, float width, float height) { 
    layoutPositioner = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); 
    layoutPositioner.topMargin = (int) (offsetY * y); 
    layoutPositioner.leftMargin = (int) (offsetX * x); 
    layoutPositioner.width = (int) (width * offsetX); 
    layoutPositioner.height = (int) (height * offsetY); 
} 

}

Questo è quello che sembra quando carico 5 immagini

http://s15.postimg.org/ymqspk77v/Screenshot_2016_02_29_07_19_26.png

risposta

2

Semplicemente basta usare vettori al posto delle immagini .. vi farà risparmiare molta memoria per l'esecuzione di app e di stoccaggio. È supportato molto bene. ed è possibile utilizzare le risorse SVG

+0

Grazie Maher, non avevo mai usato i vettori prima e dopo aver giocato con esso nel droide mi sto rasando via un carico di memoria della barca con quello solo, mi addolora che non ne avevo abbastanza il tempo di testare i suggerimenti di terze parti di Zeyad e Smartiz prima del periodo di ricompense [Sto gestendo 2 posti di lavoro e programmando nel mio tempo libero] ma sembrava che fossero soluzioni nella giusta direzione ... JeD grazie per la tua in profondità di risposta non era la soluzione per il mio problema specifico – user1091368

3

Va bene vediamo.

Prima di tutto non è necessario pezzi del puzzle per essere così grande, in modo da poter scalare giù:

Da http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

A dire il decoder per sottocampionare l'immagine, il caricamento di un minore versione in memoria, imposta inSampleSize su true nel tuo oggetto BitmapFactory.Options. Ad esempio, un'immagine con risoluzione 2048x1536 che viene decodificata con un inSampleSize di 4 produce una bitmap di circa 512x384. Caricamento di questo nella memoria utilizza 0.75MB anziché 12 MB per l'immagine completa (assumendo una configurazione di bitmap ARGB_8888)

secondo luogo si dovrebbe provare bitmap loading in un AsyncTask per impedire l'applicazione congelamento.

In terzo luogo è possibile memorizzare nella cache i tuoi bitmap utilizzando LRUCache per accelerare le cose

http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html

private LruCache<String, Bitmap> mMemoryCache; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    ... 
    // Get max available VM memory, exceeding this amount will throw an 
    // OutOfMemory exception. Stored in kilobytes as LruCache takes an 
    // int in its constructor. 
    final int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024); 

    // Use 1/8th of the available memory for this memory cache. 
    final int cacheSize = maxMemory/8; 

    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { 
     @Override 
     protected int sizeOf(String key, Bitmap bitmap) { 
      // The cache size will be measured in kilobytes rather than 
      // number of items. 
      return bitmap.getByteCount()/1024; 
     } 
    }; 
    ... 
} 

public void addBitmapToMemoryCache(String key, Bitmap bitmap) { 
    if (getBitmapFromMemCache(key) == null) { 
     mMemoryCache.put(key, bitmap); 
    } 
} 

public Bitmap getBitmapFromMemCache(String key) { 
    return mMemoryCache.get(key); 
} 

che dovrebbe essere sufficiente, ma nel caso in cui non è qui ci sono tutte le fonti e poi alcuni extra: http://developer.android.com/training/displaying-bitmaps/index.html

Si può anche provare a utilizzare

void bm_PuzzleOne() 
{ 
    //start of 1st puzzle 
    BitmapFactory.Options opt = new BitmapFactory.Options(); 

    //makes a loaded image mutable 
    opt.inMutable=true; 
    //reduces density to that of screen 
    opt.inTargetDensity = this.context.getResources().getDisplayMetrics().densityDpi; 
    opt.inScaled=true; 

    //makes bitmap half as big 
    opt.inSampleSize=2; 

    //foregdimg1 = BitmapFactory.decodeResource(getResources(), R.drawable.puzzlepieceprac);//puzzle cut out (42.48MB) +6.15 
    mutableforegdimg1 = BitmapFactory.decodeResource(getResources(), R.drawable.puzzlepieceprac,opt) 

    compositeImage1 = Bitmap.createBitmap(mutableforegdimg1);//cuts out foreground info into bkgdimage (54.43MB) +6.11 

    imgCanvas1 = new Canvas(compositeImage1); //canvas references puzzle cut out image (54.43MB) +0 
    imgCanvas1.drawBitmap(croppedBmp, null, new Rect(0, 0, 1500, 2000), paintObject);//places puzzle image on canvas (54.43MB) +0 

    img1.setImageBitmap(compositeImage1); 

} 

invece di

void bm_PuzzleOne() 
{ 
    //start of 1st puzzle 

    foregdimg1 = BitmapFactory.decodeResource(getResources(), R.drawable.puzzlepieceprac);//puzzle cut out (42.48MB) +6.15 
    mutableforegdimg1 = foregdimg1.copy(Bitmap.Config.ARGB_8888, true); //(48.32MB) +5.84 

    compositeImage1 = Bitmap.createBitmap(mutableforegdimg1);//cuts out foreground info into bkgdimage (54.43MB) +6.11 

    imgCanvas1 = new Canvas(compositeImage1); //canvas references puzzle cut out image (54.43MB) +0 
    imgCanvas1.drawBitmap(croppedBmp, null, new Rect(0, 0, 1500, 2000), paintObject);//places puzzle image on canvas (54.43MB) +0 

    img1.setImageBitmap(compositeImage1); 

} 
+0

quando si dice che non ho bisogno di quelle così grandi presumo che si stia riferendo alla bitmap disegnata a 1500x2000 ...L'immagine precaricata non è 1500x2000 Sono costretto ad espanderla a quella dimensione solo per avere il pezzo del puzzle mascherato a destra ... la dimensione della mia immagine di puzzle è precaricata di 425x601, sono costretto ad espandere la dimensione dell'immagine del puzzle per adattarsi alla dimensione del mio pezzo di puzzle ... Spero che questo abbia un senso e aggiunga più chiarezza al mio blocco attuale ... Ecco un esempio di come appare ... http: //postimg.org/image/o62dgyw0t/ – user1091368

+0

Fatto un montaggio, guardalo e dimmi se funziona. Inoltre, usi mutableforegdimg dopo averlo aggiunto a compositeImage? Se non dovresti provare a riciclarlo – JeD

1

Prima di tutto vorrei ringraziare il @JeD per la sua grande risposta, ma devo dire che penso che la risposta è diversa.

Iniziamo dalle basi ...


Ogni dispositivo Android ha una specifica "dimensione heap". inizia da 16 mg a 64 mg e anche 128 mg in alcuni dispositivi! (Non sono sicuro di 128 mg: D)

Quindi ogni volta che si utilizza un drawable nella visualizzazione, richiede una quantità specifica di ram.

Domanda: come viene calcolato ?!

E 'la dimensione di drawable s, non la dimensione. Ad esempio abbiamo due drawable s con 500 KB di dimensione. Uno di questi ha le dimensioni 500 * 500, l'altro ha 700 * 700 Il secondo richiede più heap anche se entrambe le dimensioni erano uguali! La formula è questa: WIDTH * HEIGHT * 4 BYTE (4 proviene da ARGB, richiede quattro byte per ogni pixel per memorizzare i dati)

A questo punto, è necessario capire che non è possibile utilizzare MOLTE immagini insieme! Se si desidera utilizzare LRUCACH come @JeD menzionato, si perderebbero alcune delle immagini man mano che l'heap si riempirebbe.

Domanda: Che cosa dovremmo fare ?!

La risposta utilizza motori e telai di terze parti! I motori di gioco come COCOS2D, BOX2D, ecc ... sono anche buoni esempi o anche utilizzando NDK che rende la tua app HEAP FREE !!! : D

Problemi correlati