【问题标题】:How to implement a "loading" indicator into Android app如何在 Android 应用中实现“加载”指示器
【发布时间】:2014-06-02 16:38:16
【问题描述】:

好的,所以现在我有一个ListView,它正在通过PHP script. 填充信息现在,列表一次加载一个。通过这个,我的意思是用户可以看到每个列表何时加载(例如,他们看到一个项目,一秒钟后他们看到第二个项目,等等)我想要做的是等待,直到所有项目都被检索然后显示他们一下子。在发生这种情况时,要有某种类型的“加载”指示器(可能是旋转圆圈类型的交易)。有什么办法可以实现吗?这是我的代码:

public class MainActivity extends ActionBarActivity {

    ArrayList<Location> arrayOfLocations;
    LocationAdapter adapter;
    Button refresh;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_main);

        // Construct the data source
        arrayOfLocations = new ArrayList<Location>();

        // Create the adapter to convert the array to views
        adapter = new LocationAdapter(this, arrayOfLocations);

        getData();

        // Attach the adapter to a ListView
        ListView listView = (ListView) findViewById(R.id.listView1);
        listView.setAdapter(adapter);
    }
}

所以,我的 getData() 方法将每个位置添加到适配器中,并且 那么我的 Adapter 类就是将数据放入 ListView 的:

public class LocationAdapter extends ArrayAdapter<Location> {
    public LocationAdapter(Context context, ArrayList<Location> locations) {
        super(context, R.layout.item_location, locations);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // Get the data item for this position
        Location location = getItem(position);
        // Check if an existing view is being reused, otherwise inflate the view
        if (convertView == null) {
            convertView = LayoutInflater.from(getContext()).inflate(
                    R.layout.item_location, parent, false);
        }

        // Lookup view for data population
        TextView tvName = (TextView) convertView.findViewById(R.id.tvName);
        TextView tvDetails = (TextView) convertView
                .findViewById(R.id.tvDetails);
        TextView tvDistance = (TextView) convertView
                .findViewById(R.id.tvDistance);
        TextView tvHours = (TextView) convertView.findViewById(R.id.tvHours);
        ImageView ivIcon = (ImageView) convertView.findViewById(R.id.imgIcon);

        // Populate the data into the template view using the data object
        tvName.setText(location.name);
        tvDetails.setText(location.details);
        tvDistance.setText(location.distance);
        tvHours.setText(location.hours);
        ivIcon.setImageBitmap(location.icon);
        // Return the completed view to render on screen
        return convertView;
    }
}

另外,我有一个简单的加载指示器的代码:

public class MainActivity extends Activity {

    private ProgressDialog progress;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        progress = new ProgressDialog(this);
    }

    public void open(View view) {
        progress.setMessage("Loading...Please Wait");
        progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        progress.setIndeterminate(true);
        progress.show();

        final int totalProgressTime = 100;

        final Thread t = new Thread() {

            @Override
            public void run() {

                int jumpTime = 0;
                while (jumpTime < totalProgressTime) {
                    try {
                        sleep(200);
                        jumpTime += 5;
                        progress.setProgress(jumpTime);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                }

            }
        };
        t.start();

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}

所以基本上,我想做的是弄清楚如何做到这一点: 1.活动开始时,显示“加载中”指示符 2. 将所有项目加载到 ListView 3. 列出所有项目后,去掉“正在加载”指示符,显示ListView

有什么想法吗?谢谢。

【问题讨论】:

  • 我会为此使用 AsynchTask。
  • 我正在使用 AsyncTask 加载每个 ListView 项目。您建议如何使用 AsyncTask 来检查列表是否已满?
  • 您将需要一个进度对话框,以及您的 AsyncTask 中的一个回调。然后是 AsyncTask,确保将 Context 作为构造函数的参数传递,以及 CallBack。覆盖 onPreExecute() 以显示对话框。重写 onPostExecute() 以将 doInBackground() 返回的值传递给您的 CallBack 并关闭您的进度对话框。我希望这对你有意义。
  • 我从未使用过回调,但它确实有点道理。我不知道该怎么做是我怎么知道 ListView 何时完成加载?
  • 当你在片段或活动中调用你的 AsyncTask 时,使用:asyncTask.execute(无论你在此处传入什么参数),asynctask 将完成 doInBackground() 中的所有工作,例如加载数据、.. . 只要doInBackground()完成,就会把数据传给onPostExecute()。在 onPostExecute() 中,您可以检查数据是否有效,如果数据有效,则关闭对话框。在您调用异步任务类的片段或活动中,您将需要在其中更新列表的地方实现回调。

标签: java php android listview


【解决方案1】:

实现此目的的另一种简单方法是让您的视图中的 ProgressBar 已经可见,并在处理完成时将其隐藏:

<RelativeLayout
    android:id="@+id/app_container"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1">

    <FrameLayout
        android:id="@+id/loading_progress_container"
        android:layout_width="45dp"
        android:layout_height="45dp"
        android:layout_centerInParent="true">
        <ProgressBar
            android:id="@+id/list_progress_indicator"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </FrameLayout>

    <com.example.MyListView
        android:id="@+id/my_list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone"/>

</RelativeLayout>

然后在您的请求的回调中执行以下操作:

final View progressView = containerView.findViewById(R.id.loading_progress_container);
final View myListView = containerView.findViewById(R.id.my_list_view);
activity.runOnUiThread(new Runnable() {
    progressView.setVisibility(View.GONE);
    myListView.setVisibility(View.VISIBLE);
});

显然,您需要参考上述代码的容器视图和活动。

【讨论】:

    【解决方案2】:

    为此,您需要一个扩展 AsyncTask 的类。在 doInBackground 方法的此类中,您需要执行所有“繁重”的工作。在您的情况下填充您的 ListView。如果您想显示您的进度,您可以在每次迭代结束时调用 publishProgress 方法。最后在 onPostExecute 方法中,您可以通知用户该过程已完成。这是一个简单的例子

     public class ExampleAsync extends AsyncTask <Void, Integer, Void> {
    
         private ProgressDialog progressBar; //to show a little modal with a progress Bar
     private Context context;  //needed to create the progress bar
    
         public ExampleAsync(Context context){
               this.context = context;
         }
    
         //this is called BEFORE you start doing anything 
         @Override 
         protected void onPreExecute(){
             progressBar = new ProgressDialog(context);
             progressBar.setCancelable(false);
             progressBar.setMessage("I am starting to look for stuff");
             progressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
             progressBar.setIndeterminate(true);
             progressBar.show();
         }
    
         //every time you call publishProgress this method is executed, in this case receives an Integer
         @Override
     protected void onProgressUpdate(Integer ... option){
             progressBar.setMessage("I have found :" + option[0]);      
    }  
    
         @Override
     protected void onPostExecute(Void unused){     
          progressBar.dismiss(); //hides the progress bar
              //do whatever you want now
    }
    
    
    
         //in here is where you execute your php script or whatever "heavy" stuff you need
         @Override
     protected Void doInBackground(Void... unused) {          
            for (int i = 0; i < someLimit; i++){
                 //do something
                 publishProgress(i); //to show the progress
            }
         } 
    
    
    
    
     }
    

    在你的主要活动中:

    //code
    new ExampleAsync(this).execute();
    

    显然这是一个简单的例子。你可以在 onProgressUpdate 方法中做很多事情,而你需要更新进度条的正是这个方法。

    希望对你有帮助

    【讨论】:

    • 感谢您的回答。我的事情是我想显示一个旋转的圆圈,而不是更新用户的进度。我想让他们知道的是数据正在加载。但是这个例子还是很有帮助的
    • 另外,什么是context in progressBar = new ProgressDialog(context); ?
    • 如果你只想显示一个旋转的圆圈然后评论 progressBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);在 onPreExecute 方法中。这样你只会看到一个圆圈
    • 关于上下文:对不起,我基于旧代码并忘记包含上下文。我编辑了代码。
    • 当我实现这个时,我得到 android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
    猜你喜欢
    • 2023-03-03
    • 2022-12-14
    • 2014-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多