问题
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 ?
回答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 :)
回答2:
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.
来源:https://stackoverflow.com/questions/32668285/how-to-retain-progress-bar-state-while-switching-the-fragments