0

When app is started it works fine i can swipe left and right without any problem. But as soon as app is been minimized and resumed it again calls the loader and data is been fetched again it results into more no of dots in bottom. ps: The loader is been called again as dots are in onLoadfinshed.

At first launch Intial launch

After minimizing and resuming the app after resuming

package com.example.kaushal.slider;

/**
 * Created by kaushal on 25-09-2017.
 */

import android.app.LoaderManager;
import android.content.Loader;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import android.widget.LinearLayout;

import java.util.List;


public class MainActivity1 extends AppCompatActivity implements LoaderManager.LoaderCallbacks<List<video1>> {
    customadap adap;
    ViewPager viewPager;
    private List<video1> videolist;
    int LoaderId = 1;
    LinearLayout slidedotepanel;
    int dotscount;
    ImageView[] dots;
    String jsonurl = "";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main1);
        viewPager =(ViewPager)findViewById(R.id.viewpager);
        slidedotepanel = (LinearLayout)findViewById(R.id.SliderDots);
        LoaderManager lm = getLoaderManager();
        lm.initLoader(LoaderId,null,this);
    }

    @Override
    public Loader<List<video1>> onCreateLoader(int i, Bundle bundle) {
        return new videoLoader1(this,jsonurl);
    }

    @Override
    public void onLoadFinished(Loader<List<video1>> loader, List<video1> videos) {
        adap = new customadap(videos,this);
        viewPager.setAdapter(adap);
        dotscount = adap.getCount();
        dots = new ImageView[dotscount];
        for(int i = 0;i<dotscount;i++) {
            dots[i] = new ImageView(this);
            dots[i].setImageDrawable(ContextCompat.getDrawable(this, R.drawable.nonactive_dot));
            LinearLayout.LayoutParams layout_linear = new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);

            layout_linear.setMargins(8, 0, 8, 0);
            slidedotepanel.addView(dots[i], layout_linear);
        }
            dots[0].setImageDrawable(ContextCompat.getDrawable(this,R.drawable.active_dot));
            viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

                }

                @Override
                public void onPageSelected(int position) {
                    for(int i =0; i<dotscount;i++){
                        dots[i].setImageDrawable(ContextCompat.getDrawable(getApplicationContext(), R.drawable.nonactive_dot));
                    }
                    dots[position].setImageDrawable(ContextCompat.getDrawable(getApplicationContext(), R.drawable.active_dot));
                }

                @Override
                public void onPageScrollStateChanged(int state) {

                }
            });
        }


    @Override
    public void onLoaderReset(Loader<List<video1>> loader) {

    }
/*
    public void getlib(){
        StringRequest stringRequest = new StringRequest(jsonurl, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                try {
                JSONArray jsonArray = new JSONArray(response);
            JSONObject jsonObject = jsonArray.getJSONObject(0);
            JSONArray jarray = jsonObject.getJSONArray("videolist");

                } catch (JSONException e) {
                    e.printStackTrace();
                }

            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {

            }
        });
    }*/
}

Updated: currently i am handling it via deleting the loader on LoadFinished in last line it works fine but won't able to handle orientation changes any better approach appreciated.

1 Answers1

0

In the Activity's onCreate, we should check with the load manager if an existing thread already exists. If it does, we should not call initLoader. I've provided a simple example of how to use AsyncTaskLoader.

import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;

import java.lang.ref.WeakReference;

public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Integer> {
    private static final String TAG = MainActivity.class.getSimpleName();
    private static final int TASK_LOADER_ID = 10;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "onCreate.  Entered function.");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        LoaderManager loaderManager = getSupportLoaderManager();
        Loader<Integer> myLoader = loaderManager.getLoader(TASK_LOADER_ID);
        if (myLoader != null && MyAsyncTask.isRunning()) {
            Log.d(TAG, "onCreate --> Existing loader exists and is running.  Re-using it.");
            // We use initLoader instead of restartLoader as callbacks
            //   must be replaced with those from this new activity
            loaderManager.initLoader(TASK_LOADER_ID, null, this);
            MyAsyncTask.setActivity(new WeakReference<>(this));
            showProcess( true);
        } else {
            Log.d(TAG, "onCreate --> Loader is not active.");
            showProcess( false);
        }
    }

    private void showProcess(boolean pShowProcess) {
        SeekBar seekBar = (SeekBar) findViewById(R.id.sb_progress);
        Button btnStart = (Button) findViewById(R.id.btn_start);
        Button btnCancel = (Button) findViewById(R.id.btn_cancel);
        if (pShowProcess) {
            seekBar.setVisibility(View.VISIBLE);
            btnStart.setEnabled(false);
            btnCancel.setEnabled(true);
        }
        else {
            seekBar.setVisibility(View.INVISIBLE);
            seekBar.setProgress(0);
            btnStart.setEnabled(true);
            btnCancel.setEnabled(false);
        }
    }

    public void clickStart(View view) {
        LoaderManager loaderManager = getSupportLoaderManager();
        // Restart existing loader if it exists, otherwise a new one (initLoader) is auto created
        loaderManager.restartLoader(TASK_LOADER_ID, null, this);
    }

    // A graceful attempt to stop the loader
    public void clickCancel(View view) {
        Loader<Integer> myLoader = getSupportLoaderManager().getLoader(TASK_LOADER_ID);
        if (myLoader != null) {
            MyAsyncTask.cancelled(true);
        }
    }

    @Override
    public Loader<Integer> onCreateLoader(int pID, Bundle pArgs) {
        Log.d(TAG, "onCreateLoader.  Entered function.");
        showProcess(true);
        return new MyAsyncTask(this);
    }

    @Override
    public void onLoadFinished(Loader<Integer> pLoader, Integer pResult) {
        Log.d(TAG, "onLoadFinished --> Number of items processed = " + pResult);
        showProcess( false);
        getLoaderManager().destroyLoader(TASK_LOADER_ID);
    }

    @Override
    public void onLoaderReset(Loader<Integer> pLoader) { }

    private static class MyAsyncTask extends AsyncTaskLoader<Integer> {
        private final static int SLEEP_TIME = 10 * 10;       // 100 milliseconds
        static WeakReference<MainActivity> aActivity;
        private static boolean isRunning = false, cancelled = true;
        private Integer aResult;        // Holds the results once the task is finished or cancelled

        MyAsyncTask(MainActivity pActivity) {
            super(pActivity);
            aActivity = new WeakReference<>(pActivity);
        }

        synchronized static void setActivity(WeakReference<MainActivity> pActivity) {
            aActivity = pActivity;
        }

        synchronized static void cancelled(boolean pCancelled) {
            cancelled = pCancelled;
        }

        static boolean isRunning() {
            return isRunning;
        }

        @Override
        protected void onStartLoading() {
            Log.d(TAG, "onStartLoading.  Entered function.    cancelled = " + cancelled);
            super.onStartLoading();
            if (aResult != null) {
                deliverResult(aResult);
                return;
            }
            if (!isRunning) {   // Don't start a new process unless explicitly initiated by clickStart
                Log.d(TAG, "onStartLoading --> No existing process running, so we can start a new one.");
                forceLoad();
            }
        }

        @Override
        public Integer loadInBackground() {
            Log.d(TAG, "loadInBackground.  Entered function.");
            isRunning = true;
            cancelled = false;
            int i;
            for (i = 1; i < 100 && !cancelled; i++) {
                try {
                    Thread.sleep(SLEEP_TIME);
                } catch (InterruptedException ie) {
                    ie.printStackTrace();
                }
                if (aActivity.get() != null) {
                    SeekBar seekBar = (SeekBar) aActivity.get().findViewById(R.id.sb_progress);
                    seekBar.setProgress(i);
                }
                if (i % 15 == 0) {
                    Log.d(TAG, "Process running with i = " + i);
                }
            }
            isRunning = false;
            aResult = i;
            return aResult;
        }
    }
}

activity_main.xml is given below.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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="com.snoopy.loadertest.MainActivity">

    <SeekBar
        android:id="@+id/sb_progress"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="clickStart"
        android:text="Start Process"
        app:layout_constraintBottom_toTopOf="@id/sb_progress"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

When the 'Start Button' is clicked, it makes the SeekBar visible and starts the AsyncTaskLoader in a separate thread. While the task is running, you can rotate the device and send it to the background. On restarting the app, onCreate checks if the task exists. If so, it updates the new Activity object to the task so that the new progress bar can be updated by the task. I've tested this and it works. This should give you a better idea on how to use AsyncTaskLoader and manage resume.

Big Tom
  • 31
  • 5