Home > Back-end >  Android Studio Page Spitter
Android Studio Page Spitter

Time:09-09

Regards to all.

I am a beginner in Android Studio. I'm trying to make a simple application that converts long text into multiple pages. I found an old example of the "PageSplitter" project, but the new version of Android Studio reported a lot of errors. I managed to debug it but when I start the project in the emulator it starts to open and then a message appears that the application has been terminated. Can anyone help me find the error. Thanks in advance. Here is the code:

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="ru.appheads.pagesplitterapp">

<application
    android:allowBackup="true"
    android:dataExtractionRules="@xml/data_extraction_rules"
    android:fullBackupContent="@xml/backup_rules"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/Theme.Pagesplitterapp"
    tools:targetApi="31">
    <activity
        android:name=".MainActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

</manifest>    

MainActivity.java

package ru.appheads.pagesplitterapp;

import android.os.Bundle;
import android.text.TextPaint;
import android.view.ViewTreeObserver;

import androidx.fragment.app.FragmentActivity;
import androidx.viewpager.widget.ViewPager;


public class MainActivity extends FragmentActivity {
private ViewPager pagesView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);
    pagesView = (ViewPager) findViewById(R.id.pages);

    // to get ViewPager width and height we have to wait global layout
    pagesView.getViewTreeObserver().addOnGlobalLayoutListener(new
ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            PageSplitter pageSplitter = new PageSplitter(pagesView.getWidth(),
pagesView.getHeight(), 1, 0);

            TextPaint textPaint = new TextPaint();
            textPaint.setTextSize(getResources().getDimension(R.dimen.text_size));
            for (int i = 0; i < 1000; i  ) {
                pageSplitter.append("Hello, ", textPaint);
                textPaint.setFakeBoldText(true);
                pageSplitter.append("world", textPaint);
                textPaint.setFakeBoldText(false);
                pageSplitter.append("! ", textPaint);
                if ((i   1) % 100 == 0) {
                    pageSplitter.append("\n", textPaint);
                }
            }

            pagesView.setAdapter(new TextPagerAdapter(getSupportFragmentManager(),
pageSplitter.getPages()));
            pagesView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    });

 }
 }

PageFragment.java

package ru.appheads.pagesplitterapp;

import android.os.Bundle;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.fragment.app.Fragment;

public class PageFragment extends Fragment {
private final static String PAGE_TEXT = "PAGE_TEXT";

public static PageFragment newInstance(CharSequence pageText) {
    PageFragment frag = new PageFragment();
    Bundle args = new Bundle();
    args.putCharSequence(PAGE_TEXT, pageText);
    frag.setArguments(args);
    return frag;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
    CharSequence text = getArguments().getCharSequence(PAGE_TEXT);
    TextView pageView = (TextView) inflater.inflate(R.layout.page, container, false);
    pageView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimension(R.dimen.text_size));
    pageView.setText(text);
    return pageView;
}
}    

PageSpitter.java

package ru.appheads.pagesplitterapp;

import android.graphics.Typeface;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.TextPaint;
import android.text.style.StyleSpan;

import java.util.ArrayList;
import java.util.List;

public class PageSplitter {
private final int pageWidth;
private final int pageHeight;
private final float lineSpacingMultiplier;
private final int lineSpacingExtra;
private final List<CharSequence> pages = new ArrayList<CharSequence>();
private SpannableStringBuilder currentLine = new SpannableStringBuilder();
private SpannableStringBuilder currentPage = new SpannableStringBuilder();
private int currentLineHeight;
private int pageContentHeight;
private int currentLineWidth;
private int textLineHeight;

public PageSplitter(int pageWidth, int pageHeight, float lineSpacingMultiplier, int
lineSpacingExtra) {
    this.pageWidth = pageWidth;
    this.pageHeight = pageHeight;
    this.lineSpacingMultiplier = lineSpacingMultiplier;
    this.lineSpacingExtra = lineSpacingExtra;
}

public void append(String text, TextPaint textPaint) {
    textLineHeight = (int) Math.ceil(textPaint.getFontMetrics(null) * lineSpacingMultiplier  
lineSpacingExtra);
    String[] paragraphs = text.split("\n", -1);
    int i;
    for (i = 0; i < paragraphs.length - 1; i  ) {
        appendText(paragraphs[i], textPaint);
        appendNewLine();
    }
    appendText(paragraphs[i], textPaint);
}

private void appendText(String text, TextPaint textPaint) {
    String[] words = text.split(" ", -1);
    int i;
    for (i = 0; i < words.length - 1; i  ) {
        appendWord(words[i]   " ", textPaint);
    }
    appendWord(words[i], textPaint);
}

private void appendNewLine() {
    currentLine.append("\n");
    checkForPageEnd();
    appendLineToPage(textLineHeight);
}

private void checkForPageEnd() {
    if (pageContentHeight   currentLineHeight > pageHeight) {
        pages.add(currentPage);
        currentPage = new SpannableStringBuilder();
        pageContentHeight = 0;
    }
}

private void appendWord(String appendedText, TextPaint textPaint) {
    int textWidth = (int) Math.ceil(textPaint.measureText(appendedText));
    if (currentLineWidth   textWidth >= pageWidth) {
        checkForPageEnd();
        appendLineToPage(textLineHeight);
    }
    appendTextToLine(appendedText, textPaint, textWidth);
}

private void appendLineToPage(int textLineHeight) {
    currentPage.append(currentLine);
    pageContentHeight  = currentLineHeight;

    currentLine = new SpannableStringBuilder();
    currentLineHeight = textLineHeight;
    currentLineWidth = 0;
}

private void appendTextToLine(String appendedText, TextPaint textPaint, int textWidth) {
    currentLineHeight = Math.max(currentLineHeight, textLineHeight);
    currentLine.append(renderToSpannable(appendedText, textPaint));
    currentLineWidth  = textWidth;
}

public List<CharSequence> getPages() {
    List<CharSequence> copyPages = new ArrayList<CharSequence>(pages);
    SpannableStringBuilder lastPage = new SpannableStringBuilder(currentPage);
    if (pageContentHeight   currentLineHeight > pageHeight) {
        copyPages.add(lastPage);
        lastPage = new SpannableStringBuilder();
    }
    lastPage.append(currentLine);
    copyPages.add(lastPage);
    return copyPages;
}

private SpannableString renderToSpannable(String text, TextPaint textPaint) {
    SpannableString spannable = new SpannableString(text);

    if (textPaint.isFakeBoldText()) {
        spannable.setSpan(new StyleSpan(Typeface.BOLD), 0, spannable.length(), 0);
    }
    return spannable;
 }
 }

TextAdapter.java

package ru.appheads.pagesplitterapp;

import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;

import java.util.List;

public class TextPagerAdapter extends FragmentPagerAdapter {
private final List<CharSequence> pageTexts;

public TextPagerAdapter(FragmentManager fm, List<CharSequence> pageTexts) {
    super(fm);
    this.pageTexts = pageTexts;
}

@Override
public Fragment getItem(int i) {
    return PageFragment.newInstance(pageTexts.get(i));
}

@Override
public int getCount() {
    return pageTexts.size();
}
}    

activity_main.xml

<RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context="ru.appheads.pagesplitterapp.MainActivity">

<androidx.viewpager2.widget.ViewPager2 xmlns:android="http://schemas.android.com/apk/res
/android"
    android:id="@ id/pages"
    android:overScrollMode="never"
    android:layout_height="match_parent"
    android:layout_width="match_parent">
</androidx.viewpager2.widget.ViewPager2>
</RelativeLayout>    

Page.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:lineSpacingMultiplier="1"
android:lineSpacingExtra="0sp">
</TextView>    

styles.xml

<resources>
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
</style>
</resources>

build.gradle.app

plugins {
id 'com.android.application'
}

android {
compileSdk 32

defaultConfig {
    applicationId "ru.appheads.pagesplitterapp"
    minSdk 21
    targetSdk 32
    versionCode 1
    versionName "1.0"

    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-
rules.pro'
    }
}
compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}
}

dependencies {

implementation 'androidx.appcompat:appcompat:1.5.0'
implementation 'com.google.android.material:material:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.viewpager2:viewpager2:1.0.0'
//implementation 'androidx.fragment:fragment-ktx:1.2.0-beta02'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

}       

CodePudding user response:

This is a 1/4 of logcat content.

This is second logcat - after clear logcat.

2022-09-08 23:03:25.664 6760-6760/? I/pagesplitterap: Late-enabling
-Xcheck:jni
2022-09-08 23:03:25.731 6760-6760/? I/pagesplitterap: Unquickening 12
vdex files!
2022-09-08 23:03:25.737 6760-6760/? W/pagesplitterap: Unexpected CPU 
variant for X86 using defaults: x86
2022-09-08 23:03:26.651 6760-6760/ru.appheads.pagesplitterapp 
D/NetworkSecurityConfig: No Network Security Config specified, using 
platform default
2022-09-08 23:03:26.651 6760-6760/ru.appheads.pagesplitterapp
D/NetworkSecurityConfig: No Network Security Config specified, using 
platform default
2022-09-08 23:03:26.739 6760-6783/ru.appheads.pagesplitterapp
D/libEGL: 
loaded /vendor/lib/egl/libEGL_emulation.so
2022-09-08 23:03:26.743 6760-6783/ru.appheads.pagesplitterapp 
D/libEGL: 
loaded /vendor/lib/egl/libGLESv1_CM_emulation.so
2022-09-08 23:03:26.753 6760-6783/ru.appheads.pagesplitterapp 
D/libEGL: 
loaded /vendor/lib/egl/libGLESv2_emulation.so
2022-09-08 23:03:27.182 6760-6760/ru.appheads.pagesplitterapp 
D/AndroidRuntime: Shutting down VM


--------- beginning of crash
2022-09-08 23:03:27.184 6760-6760/ru.appheads.pagesplitterapp
 E/AndroidRuntime: FATAL EXCEPTION: main
Process: ru.appheads.pagesplitterapp, PID: 6760
java.lang.RuntimeException: Unable to start activity
ComponentInfo   {ru.appheads.pagesplitterapp
/ru.appheads.pagesplitterapp.MainActivity}:
java.lang.ClassCastException: androidx.viewpager2.widget.ViewPager2 
cannot be cast to androidx.viewpager.widget.ViewPager
at
android.app.ActivityThread.performLaunchActivity
(ActivityThread.java:3449)
    at android.app.ActivityThread.handleLaunchActivity
(ActivityThread.java:3601)
    at android.app.servertransaction.LaunchActivityItem.execute
(LaunchActivityItem.java:85)
    at
android.app.servertransaction.TransactionExecutor.executeCallbacks
(TransactionExecutor.java:135)
    at android.app.servertransaction.TransactionExecutor.execute
(TransactionExecutor.java:95)
    at android.app.ActivityThread$H.handleMessage
(ActivityThread.java:2066)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:223)
    at android.app.ActivityThread.main(ActivityThread.java:7656)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run
(RuntimeInit.java:592)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
 Caused by: java.lang.ClassCastException:
 androidx.viewpager2.widget.ViewPager2 cannot be cast to
 androidx.viewpager.widget.ViewPager
    at ru.appheads.pagesplitterapp.MainActivity.onCreate 
 (MainActivity.java:19)
    at android.app.Activity.performCreate(Activity.java:7994)
    at android.app.Activity.performCreate(Activity.java:7978)
    at  android.app.Instrumentation.callActivityOnCreate
 (Instrumentation.java:1309)
    at android.app.ActivityThread.performLaunchActivity
 (ActivityThread.java:3422)
    at android.app.ActivityThread.handleLaunchActivity 
 (ActivityThread.java:3601) 
    at  android.app.servertransaction.LaunchActivityItem.execute 
 (LaunchActivityItem.java:85) 
    at  android.app.servertransaction.TransactionExecutor. 
 executeCallbacks (TransactionExecutor.java:135) 
    at android.app.servertransaction.TransactionExecutor.execute
(TransactionExecutor.java:95) 
    at android.app.ActivityThread$H.handleMessage
 (ActivityThread.java:2066) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:223) 
    at android.app.ActivityThread.main(ActivityThread.java:7656) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run 
(RuntimeInit.java:592) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 
2022-09-08 23:03:27.217 6760-6760/ru.appheads.pagesplitterapp
I/Process: Sending signal. PID: 6760 SIG: 9

CodePudding user response:

you are using Viewpager2 in xml and imported and declared Viewpager in MainActivity, that's why you are getting ClassCastException. Both xml and activity viewPager type should be same

  • Related