Project

General

Profile

« Previous | Next » 

Revision 8f139bfb

Added by Leszek Koltunski about 1 year ago

- some progress with Mosaic Cube.
- very important memory optimizations for the main dialogs (mainly Scores - which no longer leaks memory!)
- increase the size of object icons from 144x144 to 256x256

View differences:

src/main/java/org/distorted/dialogs/RubikDialogPatternPagerAdapter.java
74 74
  public void destroyItem(ViewGroup collection, int position, @NonNull Object view)
75 75
    {
76 76
    collection.removeView((View) view);
77
    mViews[position] = null;
77 78
    }
78 79

  
79 80
///////////////////////////////////////////////////////////////////////////////////////////////////
src/main/java/org/distorted/dialogs/RubikDialogScores.java
61 61

  
62 62
  public void positiveAction()
63 63
    {
64

  
64
    RubikDialogScoresThread thr = RubikDialogScoresThread.getInstance();
65
    thr.exit();
65 66
    }
66 67

  
67 68
///////////////////////////////////////////////////////////////////////////////////////////////////
src/main/java/org/distorted/dialogs/RubikDialogScoresPagerAdapter.java
31 31

  
32 32
class RubikDialogScoresPagerAdapter extends PagerAdapter implements RubikNetwork.ScoresReceiver
33 33
  {
34
  private static final int NETWORK_NOT_READY = 0;
35
  private static final int NETWORK_SUCCESS   = 1;
36
  private static final int NETWORK_FAILURE   = 2;
37

  
34 38
  private final FragmentActivity mAct;
35 39
  private final RubikDialogScores mDialog;
36 40
  private final RubikDialogScoresView[] mViews;
37 41
  private final ViewPager mViewPager;
38 42
  private final int mNumTabs;
39 43
  private final boolean mIsSubmitting;
40
  private int mToDoTab, mToDoLvl;
41

  
42
///////////////////////////////////////////////////////////////////////////////////////////////////
43

  
44
  private void prepareView()
45
    {
46
    mAct.runOnUiThread(new Runnable()
47
      {
48
      @Override
49
      public void run()
50
        {
51
        for(int i=0; i<mNumTabs; i++)
52
          {
53
          mViews[i].prepareView(mAct);
54
          }
55
        }
56
      });
57
    try
58
      {
59
      Thread.sleep(150);
60
      }
61
    catch( InterruptedException ignored)
62
      {
63

  
64
      }
65
    }
44
  private final int[] mNumLevels;
45
  private String[][][] mCountry, mName;
46
  private int[][][] mTime;
47
  private String mMessage;
48
  private int mNetworkState;
49
  private final Object mObj;
66 50

  
67 51
///////////////////////////////////////////////////////////////////////////////////////////////////
68 52

  
69
  private void addSection(int tab, int level, int numLevels, final RubikDialogScoresView view, final String[] country, final String[] name, final int[] time)
53
  public void receive(final String[][][] country, final String[][][] name, final int[][][] time)
70 54
    {
71
    String title = level==numLevels ?
72
                   mAct.getString(R.string.levelM) :
73
                   mAct.getString(R.string.lv_placeholder,level+1);
74

  
75
    final LinearLayout section = view.createSection(mAct, tab, title, level, country, name, time);
76

  
77
    mAct.runOnUiThread(new Runnable()
78
      {
79
      @Override
80
      public void run()
81
        {
82
        view.addSection(section);
83
        }
84
      });
85

  
86
    try
55
    synchronized(mObj)
87 56
      {
88
      Thread.sleep(50);
89
      }
90
    catch( InterruptedException ignored)
91
      {
92

  
93
      }
94
    }
57
      RubikDialogScoresThread thr = RubikDialogScoresThread.getInstance();
58
      thr.equip(mAct,mViewPager);
95 59

  
96
///////////////////////////////////////////////////////////////////////////////////////////////////
60
      mNetworkState = NETWORK_SUCCESS;
61
      mCountry = country;
62
      mName = name;
63
      mTime = time;
97 64

  
98
  private void getNext(int currentTab, int[] toDoTab, int[] numLevels)
99
    {
100
    if( toDoTab[currentTab]<=numLevels[currentTab] )
101
      {
102
      mToDoTab = currentTab;
103
      mToDoLvl = toDoTab[currentTab];
104
      toDoTab[currentTab]++;
105
      }
106
    else
107
      {
108
      for(int tab=0; tab<mNumTabs; tab++)
109
        {
110
        if( toDoTab[tab]<=numLevels[tab] )
65
      for(int t=0; t<mNumTabs; t++)
66
        if( mViews[t]!=null )
111 67
          {
112
          mToDoTab = tab;
113
          mToDoLvl = toDoTab[tab];
114
          toDoTab[tab]++;
115
          break;
68
          int num = mNumLevels[t];
69
          String[][] c = country[t];
70
          String[][] n = name[t];
71
          int[][] tm = time[t];
72
          for(int l=0; l<=num; l++)  thr.newWork(t, l, num, mViews[t], c[l], n[l], tm[l]);
116 73
          }
117
        }
118
      }
119
    }
120

  
121
///////////////////////////////////////////////////////////////////////////////////////////////////
122

  
123
  public void receive(final String[][][] country, final String[][][] name, final int[][][] time)
124
    {
125
    prepareView();
126
    int toDo=0;
127
    int[] toDoTab   = new int[mNumTabs];
128
    int[] numLevels = new int[mNumTabs];
129

  
130
    for(int i=0; i<mNumTabs; i++)
131
      {
132
      toDoTab[i]= 0;
133
      RubikObject object = RubikObjectList.getObject(i);
134
      int numScramble = object==null ? 1 : object.getNumScramble();
135
      numLevels[i] = Math.min(numScramble-1,RubikScreenPlay.LEVELS_SHOWN);
136
      toDo += (numLevels[i]+1);
137
      }
138

  
139
    while( toDo>0 )
140
      {
141
      toDo--;
142
      getNext(mViewPager.getCurrentItem(), toDoTab, numLevels);
143
      addSection( mToDoTab, mToDoLvl, numLevels[mToDoTab], mViews[mToDoTab], country[mToDoTab][mToDoLvl], name[mToDoTab][mToDoLvl], time[mToDoTab][mToDoLvl]);
144 74
      }
145 75
    }
146 76

  
......
148 78

  
149 79
  public void message(final String mess)
150 80
    {
81
    mNetworkState = NETWORK_FAILURE;
82
    mMessage = mess;
83

  
151 84
    mAct.runOnUiThread(new Runnable()
152 85
      {
153 86
      @Override
154 87
      public void run()
155 88
        {
156
        for(int i=0; i<mNumTabs; i++) mViews[i].message(mess);
89
        for(int i=0; i<mNumTabs; i++)
90
          if( mViews[i]!=null ) mViews[i].message(mess);
157 91
        }
158 92
      });
159 93
    }
......
189 123

  
190 124
  RubikDialogScoresPagerAdapter(FragmentActivity act, ViewPager viewPager, boolean isSubmitting, RubikDialogScores diag)
191 125
    {
126
    mObj = new Object();
192 127
    mAct = act;
193 128
    mDialog = diag;
194 129
    mNumTabs = RubikObjectList.getNumObjects();
195 130
    mViews = new RubikDialogScoresView[mNumTabs];
196 131
    mViewPager = viewPager;
197 132
    mIsSubmitting = isSubmitting;
133
    mNetworkState = NETWORK_NOT_READY;
134

  
135
    mNumLevels = new int[mNumTabs];
136

  
137
    for(int i=0; i<mNumTabs; i++)
138
      {
139
      RubikObject object = RubikObjectList.getObject(i);
140
      int numScramble = object==null ? 1 : object.getNumScramble();
141
      mNumLevels[i] = Math.min(numScramble-1, RubikScreenPlay.LEVELS_SHOWN);
142
      }
198 143

  
199 144
    viewPager.setAdapter(this);
200
    viewPager.setOffscreenPageLimit(mNumTabs-1);
145
    viewPager.setOffscreenPageLimit(1);
146

  
147
    RubikNetwork network = RubikNetwork.getInstance();
148

  
149
    if( mIsSubmitting )  network.submit  ( this, mAct );
150
    else                 network.download( this, mAct );
201 151
    }
202 152

  
203 153
///////////////////////////////////////////////////////////////////////////////////////////////////
......
206 156
  @NonNull
207 157
  public Object instantiateItem(@NonNull ViewGroup collection, int position)
208 158
    {
159
    RubikDialogScoresView view;
209 160
    DisplayMetrics metrics = mAct.getResources().getDisplayMetrics();
210 161

  
211
    mViews[position] = new RubikDialogScoresView(mAct, metrics.heightPixels, mIsSubmitting);
212
    collection.addView(mViews[position]);
162
    synchronized(mObj)
163
      {
164
      view = new RubikDialogScoresView(mAct, metrics.heightPixels, mIsSubmitting);
165
      collection.addView(view);
213 166

  
214
    boolean allCreated = true;
167
      if( mNetworkState==NETWORK_SUCCESS )
168
        {
169
        int num = mNumLevels[position];
170
        String[][] c = mCountry[position];
171
        String[][] n = mName[position];
172
        int[][] tm = mTime[position];
215 173

  
216
    for(int i=0; i<mNumTabs; i++)
217
      {
218
      if( mViews[i]==null )
174
        for(int l=0; l<=num; l++)
175
          {
176
          String title = (l==num ? mAct.getString(R.string.levelM) : mAct.getString(R.string.lv_placeholder, l+1));
177
          LinearLayout section = view.createSection(mAct, position, title, l, c[l], n[l], tm[l]);
178
          view.addSection(mAct,section);
179
          }
180
        }
181
      else if( mNetworkState==NETWORK_FAILURE )
219 182
        {
220
        allCreated = false;
221
        break;
183
        view.message(mMessage);
222 184
        }
223 185
      }
224 186

  
225
    if( allCreated )
226
      {
227
      RubikNetwork network = RubikNetwork.getInstance();
228

  
229
      if( mIsSubmitting )  network.submit  ( this, mAct );
230
      else                 network.download( this, mAct );
231
      }
187
    mViews[position] = view;
232 188

  
233
    return mViews[position];
189
    return view;
234 190
    }
235 191

  
236 192
///////////////////////////////////////////////////////////////////////////////////////////////////
......
239 195
  public void destroyItem(ViewGroup collection, int position, @NonNull Object view)
240 196
    {
241 197
    collection.removeView((View) view);
198
    mViews[position] = null;
242 199
    }
243 200

  
244 201
///////////////////////////////////////////////////////////////////////////////////////////////////
src/main/java/org/distorted/dialogs/RubikDialogScoresThread.java
1
///////////////////////////////////////////////////////////////////////////////////////////////////
2
// Copyright 2023 Leszek Koltunski                                                               //
3
//                                                                                               //
4
// This file is part of Distorted.                                                               //
5
//                                                                                               //
6
// Magic Cube is proprietary software licensed under an EULA which you should have received      //
7
// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
8
///////////////////////////////////////////////////////////////////////////////////////////////////
9

  
10
package org.distorted.dialogs;
11

  
12
import android.widget.LinearLayout;
13

  
14
import androidx.fragment.app.FragmentActivity;
15
import androidx.viewpager.widget.ViewPager;
16

  
17
import org.distorted.main.R;
18

  
19
import java.lang.ref.WeakReference;
20
import java.util.Vector;
21

  
22
///////////////////////////////////////////////////////////////////////////////////////////////////
23

  
24
class RubikDialogScoresThread extends Thread
25
  {
26
  private final Object mObject;
27
  private final Vector<WorkLoad> mBuffers;
28
  private WeakReference<FragmentActivity> mWeakAct;
29
  private ViewPager mViewPager;
30
  private boolean mRunning;
31

  
32
  private static RubikDialogScoresThread mThis;
33

  
34
  private static class WorkLoad
35
    {
36
    int tab, level, numLevels;
37
    RubikDialogScoresView view;
38
    String[] country, name;
39
    int[] time;
40

  
41
    WorkLoad(int t, int l, int nl, RubikDialogScoresView v, String[] c, String[] n, int[] tm)
42
      {
43
      tab = t;
44
      level = l;
45
      numLevels = nl;
46
      view = v;
47
      country = c;
48
      name = n;
49
      time = tm;
50
      }
51
    }
52

  
53
///////////////////////////////////////////////////////////////////////////////////////////////////
54

  
55
  private RubikDialogScoresThread()
56
    {
57
    mObject  = new Object();
58
    mRunning = true;
59
    mBuffers = new Vector<>();
60
    this.start();
61
    }
62

  
63
///////////////////////////////////////////////////////////////////////////////////////////////////
64

  
65
  static RubikDialogScoresThread getInstance()
66
    {
67
    if( mThis==null ) mThis = new RubikDialogScoresThread();
68
    return mThis;
69
    }
70

  
71
///////////////////////////////////////////////////////////////////////////////////////////////////
72

  
73
  void equip(FragmentActivity act, ViewPager pager)
74
    {
75
    mWeakAct = new WeakReference<>(act);
76
    mViewPager = pager;
77
    }
78

  
79
///////////////////////////////////////////////////////////////////////////////////////////////////
80

  
81
  void newWork(int t, int l, int nl, RubikDialogScoresView v, String[] c, String[] n, int[] tm)
82
    {
83
    synchronized(mObject)
84
      {
85
      WorkLoad load = new WorkLoad(t,l,nl,v,c,n,tm);
86
      mBuffers.add(load);
87
      mObject.notify();
88
      }
89
    }
90

  
91
///////////////////////////////////////////////////////////////////////////////////////////////////
92

  
93
  void exit()
94
    {
95
    synchronized(mObject)
96
      {
97
      mRunning = false;
98
      mThis = null;
99
      mObject.notify();
100
      }
101
    }
102

  
103
///////////////////////////////////////////////////////////////////////////////////////////////////
104

  
105
  public void run()
106
    {
107
    WorkLoad load;
108

  
109
    while(true)
110
      {
111
      synchronized(mObject)
112
        {
113
        do
114
          {
115
          load = getNextLoad();
116
          if( load!=null ) process(load);
117
          }
118
        while(load!=null);
119

  
120
        if( mRunning )
121
          {
122
          try { mObject.wait(); }
123
          catch(InterruptedException ignored) { }
124
          }
125
        else break;
126
        }
127
      }
128
    }
129

  
130
///////////////////////////////////////////////////////////////////////////////////////////////////
131

  
132
  private WorkLoad getNextLoad()
133
    {
134
    if( mViewPager==null ) return null;
135

  
136
    int currentTab = mViewPager.getCurrentItem();
137
    int size = mBuffers.size();
138

  
139
    for(int i=0; i<size; i++)
140
      {
141
      WorkLoad load = mBuffers.get(i);
142
      if( load.tab==currentTab ) return mBuffers.remove(i);
143
      }
144

  
145
    return size>0 ? mBuffers.remove(0) : null;
146
    }
147

  
148
///////////////////////////////////////////////////////////////////////////////////////////////////
149

  
150
  private void process(WorkLoad load)
151
    {
152
    final FragmentActivity act = mWeakAct.get();
153
    int tab = load.tab;
154
    int level = load.level;
155
    int numLevels = load.numLevels;
156
    RubikDialogScoresView view = load.view;
157
    String[] country = load.country;
158
    String[] name = load.name;
159
    int[] time = load.time;
160
    String title = level==numLevels ? act.getString(R.string.levelM) : act.getString(R.string.lv_placeholder, level+1);
161

  
162
    final LinearLayout section = view.createSection(act, tab, title, level, country, name, time);
163

  
164
    act.runOnUiThread(new Runnable()
165
      {
166
      @Override
167
      public void run()
168
        {
169
        view.addSection(act,section);
170
        }
171
      });
172
    }
173
  }
src/main/java/org/distorted/dialogs/RubikDialogScoresView.java
30 30

  
31 31
public class RubikDialogScoresView extends FrameLayout
32 32
  {
33
  private LinearLayout mLayout;
33
  private LinearLayout mLayout=null;
34 34
  private int mHeight;
35 35

  
36 36
///////////////////////////////////////////////////////////////////////////////////////////////////
......
163 163
///////////////////////////////////////////////////////////////////////////////////////////////////
164 164
// needs to run on UI thread
165 165

  
166
  void prepareView(FragmentActivity act)
166
  void addSection(FragmentActivity act, LinearLayout section)
167 167
    {
168
    removeAllViews();
169

  
170
    View tab = inflate(act, R.layout.dialog_scores_tab, null);
171
    mLayout = tab.findViewById(R.id.tabLayout);
172
    addView(tab);
173
    }
174

  
175
///////////////////////////////////////////////////////////////////////////////////////////////////
176
// needs to run on UI thread
168
    if( mLayout==null )
169
      {
170
      removeAllViews();
171
      View tab = inflate(act, R.layout.dialog_scores_tab, null);
172
      mLayout = tab.findViewById(R.id.tabLayout);
173
      addView(tab);
174
      }
177 175

  
178
  void addSection(LinearLayout section)
179
    {
180 176
    mLayout.addView(section);
181 177
    }
182 178

  
src/main/java/org/distorted/dialogs/RubikDialogTutorialPagerAdapter.java
73 73
  public void destroyItem(ViewGroup collection, int position, @NonNull Object view)
74 74
    {
75 75
    collection.removeView((View) view);
76
    mViews[position] = null;
76 77
    }
77 78

  
78 79
///////////////////////////////////////////////////////////////////////////////////////////////////

Also available in: Unified diff