EnqueueWork, требующий сериализации, вызывает сбой AsyncTask - PullRequest
0 голосов
/ 22 мая 2019

Идея этого проекта заключается в том, чтобы при загрузке базы данных в веб-сервис работала панель прогресса

У меня есть AsyncTask, который выполняет некоторую работу, затем вызывает службу и ожидает ее завершения, прежде чем вызывать onPostExecute.()

private class UploadDatabaseAsyncTask extends AsyncTask<Void, Long, Void> {

    private AlertDialog dialog;
    private Activity activity;
    private TextView messageView;
    private String location;
    private long maxSize;
    private ProgressBar progressBar;

    UploadDatabaseAsyncTask(Activity activity, long maxSize, String location) {
        super();
        this.location = location;
        this.maxSize = maxSize;
        this.activity = activity;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

        progressBar = new ProgressBar(activity);
        progressBar.setMax(100);
        progressBar.setProgress(0);

        dialog = new AlertDialog.Builder(activity).setTitle("Uploading").setView(progressBar).create();
        messageView = dialog.findViewById(android.R.id.message);

       // dialog.show();

        if (activity != null && activity.getView() != null)
        {
            activity.getView().setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    return true;
                }
            });

            activity.getView().setBackgroundColor(ContextCompat.getColor(App.getAppContext(), R.color.grey));
        }
    }

    @Override
    protected void onProgressUpdate(Long... values) {
        messageView.setText(values[0] + " / " + maxSize);

        BigDecimal current = new BigDecimal(values[0]);
        BigDecimal max = new BigDecimal(maxSize);

        BigDecimal progress = current.divide(max, 3, RoundingMode.UP);

        progressBar.setProgress(Integer.valueOf(progress.multiply(new BigDecimal(100)).toString()));
    }

    @Override
    protected Void doInBackground(Void... voids) {

        Intent intent = new Intent();

        final Object lock = new Object();

        final boolean[] active = new boolean[]{true};

        DatabaseSyncService.SyncProgressCallback callback = new DatabaseSyncService.SyncProgressCallback() {
            @Override
            public void onProgress(long progress) {
                onProgressUpdate(progress);
            }

            @Override
            public void onFinish() {
                active[0] = false;
                lock.notify();
            }
        };


        intent.putExtra(DATABASE_ID, callback);
        intent.putExtra("LOCATION", location);
        DatabaseSyncService.enqueueWork(activity, intent);

        synchronized (lock)
        {
            while (active[0])
            {
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        return null;
    }

    @Override
    protected void onCancelled(Void aVoid) {
        if (activity != null && activity.getView() != null)
        {
            activity.getView().setOnTouchListener(null);
            activity.getView().setBackgroundColor(ContextCompat.getColor(App.getAppContext(), R.color.transparent));
        }
    }

    @Override
    protected void onCancelled() {
        if (activity != null && activity.getView() != null)
        {
            activity.getView().setOnTouchListener(null);
            activity.getView().setBackgroundColor(ContextCompat.getColor(App.getAppContext(), R.color.transparent));
        }
    }

    @Override
    protected void onPostExecute(Void aVoid) { 
        if (activity != null && activity.getView() != null) 
        {
            activity.getView().setOnTouchListener(null);
            activity.getView().setBackgroundColor(ContextCompat.getColor(App.getAppContext(), R.color.transparent))
        }

       AlertDialog.Builder builder = new AlertDialog.Builder(App.getAppContext());
       builder.setTitle("Upload Complete");
       builder.setMessage("You upload was completed!");
       builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
           @Override
           public void onClick(DialogInterface dialog, int which) { }
       });

       builder.show();
    }
}

У меня проблема с методом DatabaseSyncService.enqueueWork (), пытающаяся сериализовать AsyncTask, которая не будет работать.Любая идея, почему он пытается это сделать?

StackTrace

E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #4
Process: com.app.app, PID: 15935
java.lang.RuntimeException: An error occurred while executing doInBackground()
    at android.os.AsyncTask$3.done(AsyncTask.java:353)
    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
    at java.util.concurrent.FutureTask.run(FutureTask.java:271)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
    at java.lang.Thread.run(Thread.java:764)
 Caused by: java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = com.app.app.api.SettingApi$UploadDatabaseAsyncTask$2)
    at android.os.Parcel.writeSerializable(Parcel.java:1786)
    at android.os.Parcel.writeValue(Parcel.java:1734)
    at android.os.Parcel.writeArrayMapInternal(Parcel.java:801)
    at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1506)
    at android.os.Bundle.writeToParcel(Bundle.java:1181)
    at android.os.Parcel.writeBundle(Parcel.java:841)
    at android.content.Intent.writeToParcel(Intent.java:10199)
    at android.app.job.JobWorkItem.writeToParcel(JobWorkItem.java:117)
    at android.app.job.IJobScheduler$Stub$Proxy.enqueue(IJobScheduler.java:205)
    at android.app.JobSchedulerImpl.enqueue(JobSchedulerImpl.java:53)
    at androidx.core.app.JobIntentService$JobWorkEnqueuer.enqueueWork(JobIntentService.java:343)
    at androidx.core.app.JobIntentService.enqueueWork(JobIntentService.java:523)
    at androidx.core.app.JobIntentService.enqueueWork(JobIntentService.java:501)
    at com.ascsoftware.ascora.sync.DatabaseSyncService.enqueueWork(DatabaseSyncService.java:37)
    at com.ascsoftware.ascora.api.SettingApi$UploadDatabaseAsyncTask.doInBackground(SettingApi.java:291)
    at com.ascsoftware.ascora.api.SettingApi$UploadDatabaseAsyncTask.doInBackground(SettingApi.java:212)
    at android.os.AsyncTask$2.call(AsyncTask.java:333)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 
    at java.lang.Thread.run(Thread.java:764) 
 Caused by: java.io.NotSerializableException: com.app.app.api.SettingApi$UploadDatabaseAsyncTask
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1233)
    at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1597)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1558)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1481)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1227)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:347)
    at android.os.Parcel.writeSerializable(Parcel.java:1781)
    at android.os.Parcel.writeValue(Parcel.java:1734) 
    at android.os.Parcel.writeArrayMapInternal(Parcel.java:801) 
    at android.os.BaseBundle.writeToParcelInner(BaseBundle.java:1506) 
    at android.os.Bundle.writeToParcel(Bundle.java:1181) 
    at android.os.Parcel.writeBundle(Parcel.java:841) 
    at android.content.Intent.writeToParcel(Intent.java:10199) 
    at android.app.job.JobWorkItem.writeToParcel(JobWorkItem.java:117) 
    at android.app.job.IJobScheduler$Stub$Proxy.enqueue(IJobScheduler.java:205) 
    at android.app.JobSchedulerImpl.enqueue(JobSchedulerImpl.java:53) 
    at androidx.core.app.JobIntentService$JobWorkEnqueuer.enqueueWork(JobIntentService.java:343) 
    at androidx.core.app.JobIntentService.enqueueWork(JobIntentService.java:523) 
    at androidx.core.app.JobIntentService.enqueueWork(JobIntentService.java:501) 
    at com.app.app.sync.DatabaseSyncService.enqueueWork(DatabaseSyncService.java:37) 
    at com.app.app.api.SettingApi$UploadDatabaseAsyncTask.doInBackground(SettingApi.java:291) 
    at com.app.app.api.SettingApi$UploadDatabaseAsyncTask.doInBackground(SettingApi.java:212) 
    at android.os.AsyncTask$2.call(AsyncTask.java:333) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) 
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 
    at java.lang.Thread.run(Thread.java:764) 
I/System.out: (HTTPLog)-Static: isSBSettingEnabled false
(HTTPLog)-Static: isSBSettingEnabled false

Вот обратный вызов

public interface SyncProgressCallback extends Serializable {
    void onProgress(long progress);
    void onFinish();
}

1 Ответ

1 голос
/ 22 мая 2019

Эта строка не работает:

intent.putExtra(DATABASE_ID, callback);

Чтобы поместить объект в Intent, он должен реализовывать интерфейс Serializable / Parcelable. Более того, это же требование распространяется на все поля объекта.

Хотя ваш callback объект (который относится к типу DatabaseSyncService.SyncProgressCallback) реализует Serializable, но он создается из внутреннего класса callback = new DatabaseSyncService.SyncProgressCallback() {...}. Согласно это , java.io.NotSerializableException происходит в вашем случае, потому что:

  • сериализация такого экземпляра внутреннего класса также приведет к сериализации ассоциированного с ним экземпляра внешнего класса
  • Сериализация внутренних классов (т. Е. Вложенных классов, которые не являются статическими классами-членами), включая локальные и анонимные классы, настоятельно не рекомендуется

Это означает, что вы должны сделать так, чтобы ваш внешний класс UploadDatabaseAsyncTask реализовывал Serializable, который, в свою очередь, должен применяться ко всем его полям и т. Д.

Это довольно расстраивает.

Как правило, рассмотрите возможность поместить что-то более легкое / чистое, а не сложные объекты со сложными зависимостями в Intent.

Возвращаясь к вашему коду, одним простым исправлением может быть передача объекта callback в метод DatabaseSyncService.enqueueWork:

    //intent.putExtra(DATABASE_ID, callback);
    intent.putExtra("LOCATION", location);
    DatabaseSyncService.enqueueWork(activity, intent, callback);

Внутри enqueueWork() используйте callback напрямую вместо десериализации из намерения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...