1

I have a navigation drawer where these many options are present

  • Image material
  • Video Material
  • Audio Material

We are maintaining separate fragment for each material and every fragment have grid view in which we are populating thumbnail of that material. Once user click on the thumbnail a full material will be downloaded(Using AsyncTask). I am displaying the progress bar over the thumbnail while downloading the full material.

Now here i stuck to a problem that suppose progress bar is showing 20% and i switched the fragment to another and again came back to the same and the downloading progress bar is lost.

I went to a solution to use intent service and broadcast receiver to populate the progress bar but in that case on every added bytes a broadcasting will be done is it a good practice ?

Hablu
  • 203
  • 1
  • 4
  • 10
  • Why is it lost? Are you creating a new instance of the fragment? – natario Sep 19 '15 at 13:08
  • No actually i am attaching and detaching fragment on every navigation and hence on every navigation onCreateview() is called that i am loosing progress bar instance in that. – Hablu Sep 19 '15 at 13:58
  • As far as I remember, if you use popBackStack() the fragment's on create should not be called again. – natario Sep 19 '15 at 14:06
  • I tried it still i am loosing progress bar while navigating to another fragments. – Hablu Sep 19 '15 at 17:38
  • Why not control the Progressbar from the underlying Activity while you switch Fragments? – Gunnar Karlsson Sep 20 '15 at 09:09

2 Answers2

1

As an abstract blueprint you could add a download Service to your app and let it to download your materials.

For communicating with this service you might want to declare it as a bind-able service so that whenever user switch to that fragment your activity can bind to this service and see what is going on.

Using this way, you can report download progress to user and also you no longer need sending broadcasts.

frogatto
  • 28,539
  • 11
  • 83
  • 129
  • Can you have any reference link where i can find related examples what you are trying to explain. – Hablu Sep 19 '15 at 17:40
1

The previous answer wasn't good enough, I made up a new one, have a look, it works very well.

The code consists of the Base Class for fragments, Two fragments, Model for holding data for grid elements and Main UI thread.

The base class:

import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;

import java.util.ArrayList;

/**
 * Created by Movsar Bekaev on 20/09/2015.
 */
public class GridFragment extends Fragment {
    static ArrayList<xThumbnail> myInformation;
    static Activity mActivity;
    GAdapter adapter;
    GridView grid;

    enum fragment_names {FR1, FR2}

    static fragment_names this_fragment_name;

    public GridFragment() {
        refresh();
    }

    protected void refresh() {
        if (grid == null) {
            grid = new GridView(mActivity);
            grid.setLayoutParams(new GridView.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT));
            grid.setBackgroundColor(Color.WHITE);
            grid.setNumColumns(2);
            grid.setColumnWidth(GridView.AUTO_FIT);
            grid.setVerticalSpacing(5);
            grid.setHorizontalSpacing(5);
            grid.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);
        }
        adapter = new GAdapter(mActivity, myInformation);
        grid.setAdapter(adapter);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        refresh();
        return grid;
    }


    public class GAdapter extends BaseAdapter {
        private Context mContext;
        private ArrayList<xThumbnail> mInfo;

        // Gets the context so it can be used later
        public GAdapter(Context c, ArrayList<xThumbnail> info) {
            mInfo = info;
            mContext = c;

        }

        // Total number of things contained within the adapter
        public int getCount() {
            return mInfo.size();
        }

        public xThumbnail getItem(int position) {
            return mInfo.get(position);
        }

        // Require for structure, not really used in my code. Can
        // be used to get the id of an item in the adapter for
        // manual control.
        public long getItemId(int position) {
            return position;
        }

        public View getView(final int position,
                            View convertView, ViewGroup parent) {

            View v;
            if (convertView == null) {
                LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                v = inflater.inflate(R.layout.thumbnail, null);
                final TextView tv = (TextView) v.findViewById(R.id.tvClickMe);
                final ProgressBar pb = (ProgressBar) v.findViewById(R.id.prgb_progress);
                pb.setProgress(mInfo.get(position).getProgress());
                tv.setText(mInfo.get(position).getProgress() + "");
                mInfo.get(position).setProgressBar(pb);
                mInfo.get(position).setTextView(tv);
                tv.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        runOp(mInfo.get(position), position, this_fragment_name);
                    }
                });
            } else {
                v = convertView;
            }
            return v;
        }
    }

    private void runOp(final xThumbnail x, final int position, final fragment_names f_name) {
        if (x.xt == null) {
            x.xt = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = x.getProgress(); i <= 100; i++) {

                        //  UNCOMMENT IF YOU WANT TO STOP THE PROCESS AFTER SWITCHING
                        //   if ((f_name == this_fragment_name) && !mThread.isInterrupted()) {
                        final int progress = i;
                        mActivity.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                x.setProgressBar(adapter.getItem(position).getProgressBar());
                                x.setTextView(adapter.getItem(position).getTextView());
                                x.setProgress(progress);
                                x.getProgressBar().setProgress(progress);
                                x.getTextView().setText(progress + "");
                                // ARBITRARY CHANGE OF MYINFORMATION
                                // JUST TO SHOW THAT IT WORKS
                                if (progress == 20) {
                                    myInformation.get(3).setProgress(12);
                                    refresh();
                                }
                                // **********************************
                            }
                        });
                        try {
                            Thread.sleep(150);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        //  } else {
                        //       return;
                        //  }
                    }
                }
            });
        }
        if (!x.xt.isAlive())
            x.xt.start();
    }
}

The fr1.java:

 public class fr1 extends GridFragment {
    static ArrayList<xThumbnail> fr1Info;

    public static fr1 newInstance(Activity act) {
        mActivity = act;
        return new fr1();
    }

    @Override
    protected void refresh() {
        if (fr1Info == null || fr1Info.size() == 0) {
            fr1Info = new ArrayList<>();
            for (int i = 0; i < 10; i++) {
                xThumbnail x;
                x = new xThumbnail();
                fr1Info.add(x);
            }

        }
        myInformation = fr1Info;
        super.refresh();
    }
}

The fr2.java:

  public class fr2 extends GridFragment {
    static ArrayList<xThumbnail> fr2Info;

    public static fr2 newInstance(Activity act) {
        mActivity = act;
        return new fr2();
    }

    @Override
    protected void refresh() {
        if (fr2Info == null || fr2Info.size() == 0) {
            fr2Info = new ArrayList<>();
            for (int i = 0; i < 10; i++) {
                xThumbnail x;
                x = new xThumbnail();
                fr2Info.add(x);
            }
        }
        myInformation = fr2Info;
        super.refresh();
    }
}

The xThumbnail.java (model):

    public class xThumbnail {    
    private int prgb_value = 0;
    private ProgressBar pb;
    private TextView tv;
    public Thread xt;

    public void setProgress(Integer i) {
        prgb_value = i;
    }

    public Integer getProgress() {
        return prgb_value;
    }

    public void setProgressBar(ProgressBar prb) {
        pb = prb;
    }

    public ProgressBar getProgressBar() {
        return pb;
    }

    public void setTextView(TextView tv) {
        this.tv = tv;
    }

    public TextView getTextView() {
        return tv;
    }
}

The MainActivity.java:

 public class MainActivity extends AppCompatActivity {
        Button btn_one, btn_two;
        fr1 mFr1;
        fr2 mFr2;
        FragmentManager fm = getFragmentManager();

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            btn_one = (Button) findViewById(R.id.btn_one);
            btn_two = (Button) findViewById(R.id.btn_two);

            mFr1 = (fr1) fm.findFragmentByTag("fr1");
            mFr2 = (fr2) fm.findFragmentByTag("fr2");
           final FrameLayout frameLayout = (FrameLayout)findViewById(R.id.frLayout);

            btn_one.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

               GridFragment.this_fragment_name= GridFragment.fragment_names.FR1;

                if (mFr1 == null) {
                    mFr1 = fr1.newInstance(MainActivity.this);
                    fm.beginTransaction().add(R.id.frLayout, mFr1, "fr1").commit();
                } else {
                    fm.beginTransaction().detach(mFr1).commit();
                    fm.beginTransaction().attach(mFr1).commit();

                }
            }
        });

        btn_two.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                GridFragment.this_fragment_name= GridFragment.fragment_names.FR2;

                if (mFr2 == null) {
                    mFr2 = fr2.newInstance(MainActivity.this);
                    fm.beginTransaction().add(R.id.frLayout, mFr2, "fr2").commit();
                } else{
                    fm.beginTransaction().detach(mFr2).commit();
                    fm.beginTransaction().attach(mFr2).commit();

                }
            }
        });
        }
    }

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=".MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1"
        android:id="@+id/btn_one"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="2"
        android:id="@+id/btn_two"
        android:layout_alignParentBottom="true"
        android:layout_alignRight="@+id/prgb_uni"
        android:layout_alignEnd="@+id/prgb_uni" />

    <ProgressBar
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/prgb_uni"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="40dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:id="@+id/frLayout"></FrameLayout>


</RelativeLayout>

thumbnail.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ProgressBar
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/prgb_progress" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="center"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="ClickMe!"
        android:id="@+id/tvClickMe"
        android:layout_gravity="center_horizontal"
        android:textIsSelectable="false" />
</FrameLayout>

What it does: We have here one base class, it operates with representation of views and populating progress bars. It has field to work with current items (that holds progress bar values), every time when we switching between fragments this field is updated to respective values of Fragment1 or Fragment2, those fragments have static fields to hold their own data so it can be changed and used.

The thing with Thread and some other code is just to show that it's works and for better understanding.

I hope it will help.

PoC - https://youtu.be/uKGeX40z_mA :)

Movsar Bekaev
  • 888
  • 1
  • 12
  • 30
  • I can't take progress bar in fragment. As i said every fragment have a grid view which contains list of view and for every view a progress bar is there. – Hablu Sep 20 '15 at 05:05
  • Then can't you create a class to hold your progress bars and their values and make an array of them for each fragment? – Movsar Bekaev Sep 20 '15 at 05:10
  • If i will take a static variable i have to take many as i have many views in a fragment. if i will take single static variable it can be modified by the other progress update value. – Hablu Sep 20 '15 at 05:26
  • It's working. You guy's are relay doing awesome work. Thank you, Thank you for your help. – Hablu Sep 22 '15 at 14:09
  • Because refresh() is called only once so while switching the fragment how can i refresh that fragment with updated list ? – Hablu Sep 24 '15 at 10:19
  • @Hablu, the refresh() called every time when you switch fragments because of this:"fm.beginTransaction().detach(mFr2).commit(); fm.beginTransaction().attach(mFr2).commit();" this calls onCreateView and that calls refresh();, all you need is to update fr1info or fr2info, other work should be done automatically. – Movsar Bekaev Sep 24 '15 at 11:06
  • Can you look once more i have seen and debugged the code it is calling only once. As while attaching and detaching it is not creating any new fragment object so constructor is not getting called. – Hablu Sep 24 '15 at 11:22
  • @Habu. sorry then, then you need just add refresh(); to onCreateView() or other method that will be called after attaching, just update fr1Info or fr2Info using its setXXX methods when you need to update it, and then after switching the refresh() will be called and new data will be shown – Movsar Bekaev Sep 24 '15 at 11:52
  • Thank you so much Movsar. It is working as what i expected. – Hablu Sep 24 '15 at 14:44
  • after calling refresh() from onCreateView() progress bar is stooped can you please check this for one more time. – Hablu Sep 29 '15 at 04:33
  • @Hablu, I updated the base class code, copy it and paste, the problem is solving by updating TextView and ProgressBar links in running thread as you can see in the code. – Movsar Bekaev Sep 30 '15 at 08:43