for a uni project I need to integrate certain android apps together and I did it in the past with fragments, but the other project workers did it with a seperate activity. When I try to integrate their work, by recreating/handling everything now as a fragment (instead of their activity), I run into problems with a class inside the .xml file of their work. Their task was a touch-based game, for which they created the “Touchinput_Fragment” class. It shows a field, in which things should be displayed to “cross” out. The actual game should be done inside the fragment “OStrikeThroughFragment”. There is also the “Touchinput_Fragment” class, which causes me the problems when I try to handle it with the Fragment “OStrikeThroughFragment”. The other people used an acitivty, where this “Touchinput” class and view seems to be running normal.
I receive/have the following errors:
- When i try to start the actual “OStrikeThroughFragment” game, the “Touchinput_Fragment” cannot be cast to the class it should be ?
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.metaapptablet, PID: 7719 java.lang.ClassCastException: com.example.metaapptablet.pepperstrike.TouchInput_Fragment cannot be cast to com.example.metaappragtablet.FragmentFputersThrke$Instagram com.example.metaapptablet.pepperstrike.OStrikeThroughFragment.initialize(OStrikeThroughFragment.java:302)
- When I start the “OStrikeThroughFragment”, its actual view seems to get initialized 2x in the debugger?
I tried some other things, but it sometimes appears to me, that the class “Touchinput_Fragment” gets destroyed ? When I later try to refer to it, I got a Nullpointerexception. (Not a part of this code here). Does it get created every time i refer/call it ?
I needed to take out a lot of the code from the files, so they are not the complete classes.
Some hints, why such a class inside a fragment – .xml file creates such problems and how to solve it, are super appreaciated 🙂 Thanks in advance!
Mainactivity.java
(only the part, where I want to start the fragment with the game)[The Mainactivity, from where I start all Fragments, does not contain any parts of the fragment layout elements]
OStrikeThroughFragment fragment_crossout = new OStrikeThroughFragment();
getSupportFragmentManager().beginTransaction()
.replace(R.id.view, fragment_crossout, "layout_crossout_normal")
.commit();
OStrikeThroughFragment
public class OStrikeThroughFragment extends Fragment {
View view;
boolean onCreate = false;
boolean intitialize = false;
int [][] rasterO;
int [][] rasterO24;
int [][] rasterO16;
int [][] rasterO9;
int [] varying_OArray = new int[]{
1,2,1,1,2,3,1,2,3,1,2,2,2,
1,1,1,1,2,1,1,1,1,1,2,1,2,
1,3,2,1,3,2,1,1,2,1,3,1,2,
1,3,2,1,1,3,2,1,1,2,3,1,2,
3,2,1,3,1,1,2,1,1,2,1,1,3,
1,1,2,1,1,3,1,3,1,1,2,1,2,
2,3,2,1,3,1,3,1,2,1,1,2,1,
1,3,3,2,1,3,1,1,1,1,2,2,1,
1,1,1,3,1,1,2,2,2,1,1,1,3,
2,1,3,3,1,1,3,1,1,2,1,2,1,
1,2,1,1,1,3,1,2,1,1,3,1,2,
2,1,2,3,1,1,1,1,3,2,1,3,1
};
int mode = 0; // mode 0 for normal O-mode; mode 1 for varying O-mode;
ArrayList<ImageView> images = new ArrayList<>();
ArrayList<ImageView> blanks = new ArrayList<>();
CountDownTimer countDownTimer;
TouchInput_Fragment touch;
TextView points;
TextView time;
int score =0;
int lastScore = 0;
int pxpcm = 0;
int rownumber, columnnumber;
Menu main_menu;
int exercise_counter = 0;
int exercise_repetition_number = 4;
int escalation_level = 0;
boolean hint_sent = false;
MQTT mqtt;
String topic = "pepper";
String ipAddress;
public OStrikeThroughFragment() {
// Required empty public constructor
}
public static OStrikeThroughFragment newInstance(String param1, String param2) {
OStrikeThroughFragment fragment = new OStrikeThroughFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//super.onCreate(null);
if (getArguments() != null) {
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//inflater.getContext().setTheme(R.style.AppTheme_NoActionBar);
view = inflater.inflate(R.layout.fragment_o_strike_through,container,false);
pxpcm = pixelProCm();
generateGrid();
initialize(false);
setClickListener();
time = view.findViewById(R.id.timeDisplay);
time.setText(String.format(getResources().getString(R.string.time), 60));
points = view.findViewById(R.id.pointsDisplay);
points.setText(String.format(getResources().getString(R.string.points) , 0));
rasterO = rasterO24; //TODO Provisorium
container.addView(touch);
return view;
}
public void displayData(){
DisplayMetrics metrics = getResources().getDisplayMetrics();
float density = metrics.density;
float dpix = metrics.xdpi;
float dpiy = metrics.ydpi;
Point size = new Point();
getActivity().getWindowManager().getDefaultDisplay().getRealSize(size);
System.out.println("Display Auflösung: " + size.x + " x " + size.y);
double x = size.x/dpix;
double y = size.y/dpiy;
}
public int pixelProCm(){
DisplayMetrics metrics = getResources().getDisplayMetrics();
Display display = getActivity().getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getRealSize(size);
if (displayData | im_feeling_lucky)
displayData();
double y = size.y/metrics.ydpi*2.54;
double pxprocm = size.y/y;
return (int)pxprocm;
}
@SuppressLint("SetTextI18n")
private void initialize(boolean keepScore){
Bitmap o24Map = BitmapFactory.decodeResource(getResources(), R.drawable.o24);
Bitmap o16Map = BitmapFactory.decodeResource(getResources(), R.drawable.o16);
Bitmap o9Map = BitmapFactory.decodeResource(getResources(), R.drawable.o9);
rasterO24 = rasterizeImage (o24Map);
rasterO16 = rasterizeImage (o16Map);
rasterO9 = rasterizeImage (o9Map);
//get TouchInput and initialize its fields with 1st O
Toolbar toolbar = view.findViewById(R.id.toolbar);
((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
Objects.requireNonNull(((AppCompatActivity)getActivity()).getSupportActionBar()).setDisplayShowTitleEnabled(false);
if (!keepScore) {
if (touch != null) {
if (touch.exerciseStarted) {
touch.exerciseStarted = false;
countDownTimer.cancel();
}
}
score = 0;
}
// Problem here
touch = view.findViewById(R.id.touchInput_fragment);
touch.activity = this;
touch.images = images;
touch.activeOItem = images.get(0);
touch.activeOItemIndex = 0;
touch.o24Map = o24Map;
touch.rasterO24 = rasterO24;
touch.timer = true;
images = new ArrayList<>();
blanks = new ArrayList<>();
points = view.findViewById(R.id.pointsDisplay);
points.setText(String.format(getResources().getString(R.string.points), lastScore));
time = view.findViewById(R.id.timeDisplay);
time.setText(String.format(getResources().getString(R.string.time) , 60));
if (!keepScore) {
int start = 60000;
if (tenSecTimer) {
start = 10000;
time.setText(String.format(getResources().getString(R.string.time) , 10));
}
countDownTimer = new CountDownTimer(start, 1000) {
public void onTick(long millisUntilFinished) {
TextView time = view.findViewById(R.id.timeDisplay);
time.setText(String.format(getResources().getString(R.string.time), (millisUntilFinished / 1000)));
double time_delta = (System.currentTimeMillis() - touch.time_of_last_touch_event)/1000;
if (time_delta >= 3 && time_delta < 5 && touch.activeOItemIndex % columnnumber == 0){
mqtt.publish("userInactivity","3");
hint_sent = true;
}
else if (time_delta >= 5 && time_delta <15 && escalation_level == 0){
mqtt.publish("userInactivity","5");
escalation_level++;
}
else if (time_delta >= 15 && time_delta <25 && escalation_level == 1){
mqtt.publish("userInactivity","15");
escalation_level++;
}
else if (time_delta >=25 && escalation_level == 2){
mqtt.publish("userInactivity","25");
escalation_level++;
}
}
@RequiresApi(api = Build.VERSION_CODES.N)
public void onFinish() {
exercise_counter++;
escalation_level = 0;
TextView time = view.findViewById(R.id.timeDisplay);
time.setText(getResources().getString(R.string.TimeIsUp));
lastScore = score;
((TextView)view.findViewById(R.id.notificationText)).setText(String.format(getResources().getString(R.string.PointsNotificationText) ,lastScore));
view.findViewById(R.id.oTable).setAlpha(0.25f);
view.findViewById(R.id.notification).setVisibility(View.VISIBLE);
touch.timer = false;
String message = "" + score;
mqtt.publish(topic, message);
}
};
}
else {
touch.exerciseStarted = true;
}
touch.pixelProCm = pxpcm;
}
//generates the Grid with the "O"s
public void generateGrid(){
//gets the size of the Display in px
Display display = getActivity().getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getRealSize(size);
getActivity().setContentView(R.layout.fragment_o_strike_through);
TableLayout oTable = view.findViewById(R.id.oTable);
double scalingFactor = 0.95;
//calculates the number of Os that can be placed on the screen width
columnnumber = size.x /(int)(pxpcm*scalingFactor*7/5)-1;
//calculates the number of Os that can be placed on the screen height
rownumber = (int)(size.y - (100 * getResources().getDisplayMetrics().density));
rownumber = (int)(rownumber/(pxpcm*scalingFactor)/2);
if (generateGrid | im_feeling_lucky){
System.out.println("Anzahl O-Reihen: " + columnnumber);
System.out.println("Anzahl O-Spalten: " + rownumber);
}
int count = 0;
for (int i = 0; i < rownumber; i++){
TableRow tR = new TableRow (getContext());
tR.setGravity(Gravity.CENTER);
ArrayList<ImageView> tempO = new ArrayList<>();
for (int j = 0; j < columnnumber; j++){
// add O-images to table rows
ImageView img = new ImageView(getContext());
img.setAdjustViewBounds(true);
img.setMaxHeight((int)(pxpcm * scalingFactor));
setOImage(img, count);
tR.addView(img);
img.setId(count);
if(i%2 == 0)
images.add(img);
else
tempO.add(img);
//images.add(img);
// add spacing between each O
if (j < (columnnumber -1)) {
ImageView spacing = new ImageView(getContext());
spacing.setImageResource(R.drawable.blank_between_o);
spacing.setAdjustViewBounds(true);
spacing.setMaxHeight((int) (pxpcm * scalingFactor));
tR.addView(spacing);
}
count++;
}
if(i%2 == 1){
Collections.reverse(tempO);
images.addAll(tempO);
}
oTable.addView(tR, 2*i);
TableRow tRBlank = new TableRow(getContext());
tRBlank.setGravity(Gravity.CENTER);
ArrayList<ImageView> tempBlanks = new ArrayList<>();
for (int j = 0; j < columnnumber; j++){
// add Blanks to table rows
ImageView blankImg = new ImageView(getContext());
blankImg.setAdjustViewBounds(true);
blankImg.setMaxHeight((int)(pxpcm * scalingFactor));
blankImg.setImageResource(R.drawable.blank_line);
if(i%2 == 0)
blanks.add(blankImg);
else
tempBlanks.add(blankImg);
tRBlank.addView(blankImg);
}
if(i%2 == 1){
Collections.reverse(tempBlanks);
blanks.addAll(tempBlanks);
}
oTable.addView(tRBlank, (2*i)+1);
}
if(lastScore > 0) {
blanks.get((lastScore - 1)%(rownumber*columnnumber)).setImageResource(R.drawable.arrow_up);
}
}
public void setClickListener(){
Button button = view.findViewById(R.id.notificationButton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
View notification = (View) v.getParent();
notification.setVisibility(View.INVISIBLE);
view.findViewById(R.id.oTable).setAlpha(1f);
if (exercise_counter < exercise_repetition_number) {
reset();
}
else if (exercise_counter == exercise_repetition_number ){
view.findViewById(R.id.oTable).setAlpha(0.25f);
((TextView)view.findViewById(R.id.notificationText)).setText(getResources().getString(R.string.exerciseFinished));
notification.setVisibility(View.VISIBLE);
exercise_counter++;
}
else if (exercise_counter > exercise_repetition_number){
// returnToMainMenu();
}
}
});
}
public class TouchInput_Fragment extends View{
boolean im_feeling_lucky = true;
boolean onSizeChanged = false;
boolean TouchInput = false;
boolean onDraw = false;
boolean onTouchEvent = false;
boolean validation = false;
boolean validateLineStartEnd = false;
boolean isValidMove = false;
boolean getResizedBitmap = false;
private final Paint line, background;
private Canvas c;
private Canvas screenCan;
private Path touchPath;
private Bitmap b;
private Bitmap screenBit;
int screenbar = 94;
ArrayList<ImageView> images = new ArrayList<>();
RectF boundsOfPath = new RectF();
ImageView activeOItem;
int activeOItemIndex;
Bitmap lineBitmapOriginal;
Bitmap lineBitmapScaledUp;
Bitmap o24Map;
int[][] rasterO24;
int[][] rasterLine;
TextView points;
boolean exerciseStarted = false;
OStrikeThroughFragment activity;
int pixelProCm;
boolean from_left_to_right = true;
int os_completed_in_row = 0;
double minDiff = 0.3;
double maxDiff = 1.5;
boolean timer;
int downx = 0;
int downy = 0;
double time_of_last_touch_event;
@Override
protected void onSizeChanged(int width, int height, int oldwidth, int oldheight) {
super.onSizeChanged(width, height, oldwidth, oldheight);
b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
screenBit = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
c = new Canvas(b);
screenCan = new Canvas(screenBit);
}
public TouchInput_Fragment(Context context) {
this(context, null);
}
public TouchInput_Fragment(Context context, AttributeSet attrs) {
super(context, attrs);
line = new Paint(Paint.ANTI_ALIAS_FLAG);
line.setStyle(Paint.Style.STROKE);
line.setColor(Color.BLUE);
line.setStrokeWidth((float)(pixelProCm * 0.04));
background = new Paint(Paint.ANTI_ALIAS_FLAG);
background.setColor(Color.WHITE);
touchPath = new Path();
}
@Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(b, 0, 0, background);
canvas.drawBitmap(screenBit, 0, 0, background);
canvas.drawPath(touchPath, line);
}
int count_drawn_lines;
int count_drawn_success;
int max_tries;
int max_tries_tmp;
@SuppressLint({"SetTextI18n", "ClickableViewAccessibility"})
@Override
public boolean onTouchEvent(MotionEvent event) {
time_of_last_touch_event = System.currentTimeMillis();
activity.escalation_level = 0;
activity.hint_sent = false;
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchPath.moveTo(touchX, touchY);
downx = (int)touchX;
downy = (int)touchY;
if ((onTouchEvent) | (im_feeling_lucky))
System.out.println("Neues Touchevent:");
count_drawn_lines++;
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touchPath.lineTo(touchX, touchY);
if ((onTouchEvent) | (im_feeling_lucky))
System.out.println("Koordinaten: X = " + touchX + " Y = " + touchY);
invalidate();
break;
case MotionEvent.ACTION_UP:
touchPath.lineTo(touchX, touchY);
int upx = (int)touchX;
int upy = (int)touchY;
c.drawPath(touchPath, line);
screenCan.drawPath(touchPath, line);
int[] screenCoordsTouch = new int[2];
this.getLocationOnScreen(screenCoordsTouch);
//get Bitmap from drawn Line covering ActiveO
int [] location = new int [2];
activeOItem.getLocationOnScreen(location);
lineBitmapOriginal = Bitmap.createBitmap(b, activeOItem.getLeft(), location[1]-screenCoordsTouch[1], activeOItem.getWidth(), activeOItem.getHeight());
lineBitmapScaledUp = getResizedBitmap(lineBitmapOriginal, o24Map.getWidth(), o24Map.getHeight());
//Rasterizes the scaled Bitmap
rasterLine = OStrikeThroughActivity.rasterizeLine(lineBitmapScaledUp, 0);
//calls a function that prints out some debug-stuff
if (onTouchEvent | im_feeling_lucky)
debugPrints(location[1], screenCoordsTouch[0], screenCoordsTouch[1]);
//get Rectangle from drawn Line
touchPath.computeBounds(boundsOfPath,true);
//Starts validation if the timer is still running
validateLine(upx, upy);
break;
}
return true;
}
private void validateLine(int upx, int upy){
max_tries_tmp++;
boolean startEndOK = false;
boolean lineOK = false;
if (timer) {
//Check, if the line starts and ends in a certain area around the O
startEndOK = validateLineStartEnd(downx, downy, upx, upy);
if (validation | im_feeling_lucky)
System.out.println("Linie innerhalb:" + startEndOK);
lineOK = isValidMove(rasterLine, ((int)images.get(activeOItemIndex).getId() % 156));
if (validation | im_feeling_lucky)
System.out.println("Linie durch O (Top --> Down):" + lineOK);
if (!lineOK) {
rasterLine = OStrikeThroughActivity.rasterizeLine(lineBitmapScaledUp, 1);
lineOK = isValidMove(rasterLine, activeOItemIndex);
if (validation | im_feeling_lucky)
System.out.println("Linie durch O (Left --> Right):" + lineOK);
}
if (startEndOK && lineOK) {
activeOItem.setBackgroundColor(Color.GREEN);
activeOItemIndex++;
activity.score++;
activity.points.setText(String.format(getResources().getString(R.string.points), activity.score));
if (activeOItemIndex >= 0 && activeOItemIndex < images.size()) {
activeOItem = images.get(activeOItemIndex);
} else {
activity.resetKeepScore(from_left_to_right);
}
count_drawn_success++;
if(max_tries < max_tries_tmp){
max_tries = max_tries_tmp;
}
max_tries_tmp = 0;
} else {
activeOItem.setBackgroundColor(Color.RED);
}
}
if (!exerciseStarted){
activity.mqtt.publish("pepper","noPatientData");
activity.mqtt.publish("pepper","exerciseStarted" + String.valueOf(activity.exercise_counter+1));
activity.countDownTimer.start();
exerciseStarted = true;
}
touchPath = new Path();
if (TouchInput | im_feeling_lucky)
System.out.println("Touchevent beendet");
invalidate();
c.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
}
private boolean isValidMove(int[][] rasterLine, int index){
double offset = 0.3;
int [][] rasterO = activity.rasterO24;
if (activity.mode == 1){
int varying_OIndex = activity.varying_OArray[index];
switch (varying_OIndex) {
case 1:
rasterO = activity.rasterO9;
offset = 0.1;
break;
case 2:
rasterO = activity.rasterO16;
offset = 0.2;
break;
default:
rasterO = activity.rasterO24;
offset = 0.3;
}
}
boolean returnValue = false;
int countO = 0, countUnder = 0, countOver = 0;
double prozent = 0.01;
int width = rasterLine.length;
int height = rasterLine[0].length;
int initialPlusX = 0;
int initialPlusY = 0;
double diff;
double mindistance = offset * pixelProCm * (o24Map.getWidth() / (double)activeOItem.getWidth());
boolean touchO = false;
}
}
fragment_o_strike_through.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".pepperstrike.OStrikeThroughFragment"
>
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:clickable="true"
android:focusable="true"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="12dp">
<TextView
android:id="@+id/timeDisplay"
android:layout_width="26dp"
android:layout_height="45dp"
android:layout_weight="1"
android:text="@string/time"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
<TextView
android:id="@+id/pointsDisplay"
android:layout_width="38dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/points"
android:textAppearance="@style/TextAppearance.AppCompat.Display1" />
</LinearLayout>
</androidx.appcompat.widget.Toolbar>
<TableLayout
android:id="@+id/oTable"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="100dp"
android:baselineAligned="false"
android:gravity="center_horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
<com.example.metaapptablet.pepperstrike.TouchInput_Fragment
android:id="@+id/touchInput_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="70dp"
tools:context=".pepperstrike.OStrikeThroughFragment"
tools:layout_editor_absoluteX="4dp" />
<LinearLayout
android:id="@+id/notification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="100dp"
android:layout_marginTop="200dp"
android:layout_marginEnd="100dp"
android:layout_marginBottom="200dp"
android:gravity="center_horizontal"
android:orientation="vertical"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/notificationText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_weight="2"
android:fontFamily="sans-serif"
android:lineSpacingExtra="14sp"
android:text="@string/PointsNotificationText"
android:textAlignment="center"
android:textColor="@android:color/black"
android:textSize="36sp"
android:typeface="normal" />
<Button
android:id="@+id/notificationButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_weight="3"
android:backgroundTint="#2196F3"
android:fontFamily="sans-serif"
android:text="@string/close"
android:textAlignment="center"
android:textColor="@android:color/black"
android:textSize="36sp"
android:typeface="normal" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>