Android 从活动异步完成后在片段上填充ListView

Android 从活动异步完成后在片段上填充ListView,android,android-fragments,android-listview,android-asynctask,Android,Android Fragments,Android Listview,Android Asynctask,我的主要活动是从url异步获取JSON数据 这是MainActivity.java public class MainActivity extends FragmentActivity implements ActionBar.TabListener{ private ViewPager viewPager; private TabsPagerAdapter mAdapter; private ActionBar actionBar; //Tab titles

我的主要活动是从url异步获取JSON数据

这是MainActivity.java

public class MainActivity extends FragmentActivity implements ActionBar.TabListener{
    private ViewPager viewPager;
    private TabsPagerAdapter mAdapter;
    private ActionBar actionBar;

    //Tab titles
    private String[] tabs = {"Sermons", "More"};
    private String[] sermonsList = new String[0];

    //JSON URL for sermonList data
    private static String sermonListJSONUrl = "https://dl.dropboxusercontent.com/u/12345/index.php";

    //Variable to save JSON Object
    private static final String JSON_KEY_SERMONS = "sermon";

    private JSONObject sermonListJSONObject = null;
    private JSONArray sermonListJSONArray = null;
    SermonsFragment mSermonFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Call JSONParser Asynchronously to get sermonList in JSON Format

        new callJSONParserAsync().execute(sermonListJSONUrl);
        //this.mSermonFragment = (SermonsFragment) getFragmentManager().findFragmentById(android.R.id.list);
        this.mSermonFragment = (SermonsFragment) getFragmentManager().findFragmentById(R.id.pager);

        //Initialization
        viewPager = (ViewPager) findViewById(R.id.pager);
        actionBar = getActionBar();
        mAdapter = new TabsPagerAdapter(getFragmentManager());

        viewPager.setAdapter(mAdapter);
        actionBar.setHomeButtonEnabled(false);
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        //Adding Tabs
        for(String tab_name : tabs) {
            actionBar.addTab(actionBar.newTab().setText(tab_name).setTabListener(this));
        }

        /**
         * on swiping the viewpager make respective tab selected
         */
        viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                //on changing the page
                //make respected tab selected
                actionBar.setSelectedNavigationItem(position);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
    }
这是activity_main.xml

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</android.support.v4.view.ViewPager>
最后,这是一个错误

07-27 16:42:27.921    1549-1555/org.myapp.myapp E/jdwp﹕ Failed writing handshake bytes: Broken pipe (-1 of 14)
07-27 16:42:29.941    1549-1549/org.myapp.myapp E/OpenGLRenderer﹕ Getting MAX_TEXTURE_SIZE from GradienCache
07-27 16:42:29.941    1549-1549/org.myapp.myapp E/OpenGLRenderer﹕ MAX_TEXTURE_SIZE: 16384
07-27 16:42:29.953    1549-1549/org.myapp.myapp E/OpenGLRenderer﹕ Getting MAX_TEXTURE_SIZE from Caches::initConstraints()
07-27 16:42:29.953    1549-1549/org.myapp.myapp E/OpenGLRenderer﹕ MAX_TEXTURE_SIZE: 16384
07-27 16:42:30.353    1549-1549/org.myapp.myapp E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: org.myapp.myapp, PID: 1549
    java.lang.NullPointerException
            at org.myapp.myapp.MainActivity$callJSONParserAsync.onPostExecute(MainActivity.java:174)
            at org.myapp.myapp.MainActivity$callJSONParserAsync.onPostExecute(MainActivity.java:157)
            at android.os.AsyncTask.finish(AsyncTask.java:632)
            at android.os.AsyncTask.access$600(AsyncTask.java:177)
            at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5017)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
            at dalvik.system.NativeStart.main(Native Method)
我不知道为什么会出现OpenGLRenderer错误,但自从我创建了这个应用程序并且运行良好以来,它一直存在,所以这不是问题所在(尽管如果你能指出如何修复这个问题,那将非常好)。java:174是
mSermonFragment.updateListView(布道列表)上的这一行

如何确保它正确填充?最好是异步的,这样就不会锁定UI,可以在异步完成后更新listview


如果您还可以指出如何在异步过程中这样做,它将检查是否有internet连接,列表视图将显示加载循环,如果没有internet,或者空列表将不显示任何数据,否则它将显示列表。为什么不调用/执行

布道列表=((MainActivity)getActivity()).getSermonsList()

在AsyncJob的onPostExecute()中

onPostExecute在UI线程上运行-因此应该没有问题

有很多选项:

  • 将片段的引用传递到
    AsyncTask
    中,并在
    onPostExecute
    中更新适配器
  • 在活动中创建方法,并在任务完成后调用它。在这个方法中,更新你的片段
  • 在片段内执行
    AsyncTask
  • 更新片段中数据的示例:

    public class SermonsFragment extends ListFragment {
      public void update(String[] sermonsList){
        listAdapter.addAll(sermonsList);
        listAdapter.notifyDataSetChanged();
      }
    }
    
    public void updateData(String[] newData) {
        this.listAdapter.clear();
        for(int i = 0; i < newData.length; i++) {
            this.listAdapter.add(newData[i]);
        }
        this.listAdapter.notifyDataSetChanged();
    }
    

    因为您只有两个片段,所以可以在保存实例时跟踪它们。按建议使用回调不是最好的选择

    因此,在寻呼机适配器中:

    public class TabsPagerAdapter extends FragmentPagerAdapter {
    
        SermonsFragment mSermonsFragment;
        MoreFragment mMoreFragment;
    
        public TabsPagerAdapter(FragmentManager fm) {
            super(fm);
            this.mSermonsFragment = new SermonsFragment();
            this.mMoreFragment = new MoreFragment();
        }
    
        @Override
        public Fragment getItem(int index) {
            switch (index) {
                case 0:
                    //Sermons fragment activity
                    return mSermonsFragment;
                case 1:
                    //More fragment activity
                    return mMoreFragment;
    
            }
    
            return null;
        }
    
        @Override
        public int getCount() {
            //get item count - equal to number of tabs
            return 2;
        }
    
        public updateSermonsFragment(String[] data) {
             mSermonsFragment.updateData(data);
        }
    
        //i don't know what's the data type managed by MoreFragment
        public updateMoreFragment(Object data) {
             mMoreFragment.updateData(data)
        }
    }
    
    在片段中创建更新适配器的方法:

    public class SermonsFragment extends ListFragment {
      public void update(String[] sermonsList){
        listAdapter.addAll(sermonsList);
        listAdapter.notifyDataSetChanged();
      }
    }
    
    public void updateData(String[] newData) {
        this.listAdapter.clear();
        for(int i = 0; i < newData.length; i++) {
            this.listAdapter.add(newData[i]);
        }
        this.listAdapter.notifyDataSetChanged();
    }
    

    另一个最佳实践是在片段中定义一个静态
    newInstace(String[]data)
    方法,这样您就可以在第一次网络调用时初始化片段数据,以确保您的片段有一个要使用的数据集,然后按照上面所述进行更新。

    onResume()填充listview的方法可能就是这个主题,但我刚刚遇到了一个类似的
    握手
    错误,使用
    volley
    https
    URL。查看更多信息

    简单检查您的连接是否被拒绝是为了信任所有SSL证书。(这只能用于测试!!

    在第一次调用之前运行此命令(例如,扩展
    应用程序
    ,并在
    onCreate
    中调用以下命令)

    信任一切类:

    public class SSLCertificateHandler {
    
    protected static final String TAG = "NukeSSLCerts";
    
    public static void nuke() {
        try {
            TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    X509Certificate[] myTrustedAnchors = new X509Certificate[0];
                    return myTrustedAnchors;
                }
    
                @Override
                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                }
    
                @Override
                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                }
            } };
    
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String arg0, SSLSession arg1) {
                    return true;
                }
            });
        } catch (Exception e) {
        }
    }
    

    }如果我能帮助你,那就太好了,因为我也遇到过这样的问题

    您希望设置适配器,该适配器包括asynctask提供的字符串数组

    在TabsPagerAdapter.class中创建构造函数

      ArrayList<String> arrayList_Tab = new ArrayList<String>();
       ** Constructor of the class */
       public TabsPagerAdapter(FragmentManager fm,
            ArrayList<String> arrayList1) {
        super(fm);
        this.arrayList = arrayList1;
      ................
       @Override
       public Fragment getItem(int index) {
        Bundle data = new Bundle();
        switch (index) {
    
            case 0:
                  SermonsFragment ment = new SermonsFragment ();
            data.putStringArrayList("data", arrayList);
            ment.setArguments(data);
            return ment;
    
            case 1:
                //More fragment activity
                return new MoreFragment();
    
        }
    
        return null;
    }
    
    改为

      mAdapter = new TabsPagerAdapter(getFragmentManager(),ArrayLListgotfromAsyctask);
    
    现在在SermonsFragment类中获取arraylist,如下所示:-

    ArrayList<String> arrayList = new ArrayList<String>();
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        arrayList = getArguments().getStringArrayList("data");
    }
    
    ArrayList ArrayList=new ArrayList();
    @凌驾
    创建时的公共void(Bundle savedInstanceState){
    //TODO自动生成的方法存根
    super.onCreate(savedInstanceState);
    arrayList=getArguments().getStringArrayList(“数据”);
    }
    
    现在可以将arraylist设置为adapter

    祝你好运

    public void updateData(字符串[]newData){
    
    public void updateData(String[] newData) {
    
     this.listAdapter.clear();
     for(int i = 0; i < newData.length; i++) {
        this.listAdapter.add(newData[i]);
     }
     this.listAdapter.notifyDataSetChanged();
    }
    
    // call this method in  onPostExecute() method . By calling listAdapter.notifyDataSetChanged(); this adapter is updated with the data which comes from JSON object . 
    
    这个.listAdapter.clear(); for(int i=0;i

    希望它能帮助你:)

    是的,你的最后一句话。在
    片段
    中创建一个公共方法来填充
    列表视图
    ,并在
    异步任务
    onPostExecute()
    方法中调用它。@MikeM。那么,这种公共方法将是怎样的呢?我是Android的初学者,通过结合多个教程来实现这一点,所以如果你能编写示例代码,那将非常有用。谢谢你好,你能给我一个示例代码来更新我的片段吗?对于案例3,我应该将asynctask放在片段或活动中吗?我需要在多个片段中多次使用此数据,这就是我将其放入“活动”中的原因。@Harts我添加了示例。是的,你是对的,在你的例子中执行
    AsyncTask
    的更好的地方是活动。所以,我尝试了这段代码,但它给了我java.lang.NullPointerException知道哪里出了问题吗?我更新了我的描述以反映这些变化。请告诉我,我尝试了这个,它在适配器上给了我nullpointerexception.clear()知道怎么了吗?检查我更新的描述中的错误this,因为需要获取片段实例调用
    this.mSermonFragment=(SermonsFragment)getFragmentManager()在活动
    onCreate
    中,并将对
    updateListView()
    的调用留在
    onPostExecute()
    中。我如何知道我的片段id是什么?我在哪里可以得到它?我确实尝试过这样的东西,this.mSermonFragment=(布道片段)getFragmentManager().findframentbyid(android.R.id.list);但它仍然不起作用。抛出同样的错误好的。。。这是另一个场景xD。这里您需要获得一个由视图寻呼机管理的片段。在这种情况下,Android避免了获取片段实例的可能性(因此您需要以“肮脏的方式”获取它)。我将更新我的帖子以反映新的情况。同时,您可以在中阅读有关从片段管理器获取视图寻呼机片段的内容
      mAdapter = new TabsPagerAdapter(getFragmentManager());
    
      mAdapter = new TabsPagerAdapter(getFragmentManager(),ArrayLListgotfromAsyctask);
    
    ArrayList<String> arrayList = new ArrayList<String>();
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        arrayList = getArguments().getStringArrayList("data");
    }
    
    public void updateData(String[] newData) {
    
     this.listAdapter.clear();
     for(int i = 0; i < newData.length; i++) {
        this.listAdapter.add(newData[i]);
     }
     this.listAdapter.notifyDataSetChanged();
    }
    
    // call this method in  onPostExecute() method . By calling listAdapter.notifyDataSetChanged(); this adapter is updated with the data which comes from JSON object .