从 AsyncTask 更新 setListAdapter

Posted

技术标签:

【中文标题】从 AsyncTask 更新 setListAdapter【英文标题】:updating setListAdapter from AsyncTask 【发布时间】:2015-11-24 19:57:20 【问题描述】:

我正在使用这个Tutorial 和它的sourcecodes 在android 中制作listview。我已经使用本教程实现了,但在更新setListAdapter 期间,我无法动态更新listview。 我经历了许多 *** 问题,他们给出了adapter.notifyDataSetChanged() 作为解决方案。但我无法在 AsyncTask 中实现它。

ItemListFragment.java

public class ItemListFragment extends ListFragment 

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    View v = super.onCreateView(inflater, container, savedInstanceState);
    setListAdapter(new ItemAdapter(getActivity(), setArray(getActivity())));
    return v;


public ArrayList<Item> setArray(Context context)

    ArrayList<Item> items = new ArrayList<Item>();
    Realm realm = Realm.getInstance(context);
    RealmResults<Books> bs = realm.where(Books.class).findAll();
    for (int i = 0; i < bs.size(); i++) 
        Bitmap url = BitmapFactory.decodeFile(bs.get(i).getCover());
        String title = bs.get(i).getName();
        String description = bs.get(i).getAuthor();
        Item item = new Item(url, title, description);
        items.add(item);
    
    realm.close();
    return items;


ItemAdapter.java

public class ItemAdapter extends ArrayAdapter<Item> 

public ItemAdapter(Context context, List<Item> items) 
    super(context, 0, items);


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

    ItemView itemView = (ItemView) convertView;
    if (null == itemView)
    
        itemView = ItemView.inflate(parent);
    
    itemView.setItem(getItem(position));
    return itemView;


MainActivity.java

public class MainActivity extends AppCompatActivity 
@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_list);
    if (BuildConfig.DEBUG)
        ViewServer.get(this).addWindow(this);


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


@Override
public boolean onOptionsItemSelected(MenuItem item) 
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) 
        return true;
    
    else if (id == R.id.update) 
        Update update = new Update(getApplicationContext(), MainActivity.this);
        update.execute();
        return true;
    

    return super.onOptionsItemSelected(item);


@Override
protected void onDestroy() 
    super.onDestroy();
    if (BuildConfig.DEBUG)
        ViewServer.get(this).removeWindow(this);


@Override
protected void onResume() 
    super.onResume();
    if (BuildConfig.DEBUG)
        ViewServer.get(this).setFocusedWindow(this);


Update.java

public class Update extends AsyncTask<Void,Void,Void>

private Context context;
public Activity activity;

 public Update(Context context, Activity activity)

    this.context = context;
    this.activity = activity;


    @Override
protected Void doInBackground(Void... params) 
    ServerAddress = context.getString(R.string.ServerAddress);
    StringExtras = context.getString(R.string.CheckBook);
    Realm realm = null;
    try 
        URL url = new URL(ServerAddress + StringExtras);
        HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
        httpURLConnection.setRequestMethod("GET");
        httpURLConnection.setRequestProperty("Content-length", "0");
        httpURLConnection.setUseCaches(false);
        httpURLConnection.setAllowUserInteraction(false);
        httpURLConnection.setConnectTimeout(1000);
        httpURLConnection.setReadTimeout(1000);
        httpURLConnection.connect();

        int responseCode = httpURLConnection.getResponseCode();
        Log.i("Response Code",responseCode+"");

        BufferedReader br = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
        String InputLine;
        StringBuilder response = new StringBuilder();

        while ((InputLine = br.readLine()) != null)
        
            response.append(InputLine);
        
        br.close();
        httpURLConnection.disconnect();

        Log.i("Response Data", response.toString());

        GsonBuilder gsonBuilder = new GsonBuilder();
        Gson gson = gsonBuilder.create();

        JSONArray array = new JSONArray(response.toString());
        //booksList = Arrays.asList(books);
        //JSONArray jsonArray = object.getJSONArray("cover");

        realm = Realm.getInstance(context);
        for (int i=0; i< array.length(); i++ ) 
            JSONObject object = array.getJSONObject(i);
            Books books = gson.fromJson(object.toString(), Books.class);
            Publish(books, realm);
        
    
    catch (Exception e) 
        e.printStackTrace();
    
    finally 
        if (realm != null)
            realm.close();
        
    
    return null;


@Override
protected void onPostExecute(Void aVoid) 
    super.onPostExecute(aVoid);
    //i want to call the setarray that contains my database data which has been updated on `doinbackground` and update the listview accordingly.
//The below codes are just the codes that i have tried but what should i do to update the listview.
activity.runOnUiThread(new Runnable() 
        @TargetApi(Build.VERSION_CODES.HONEYCOMB)
        @Override
        public void run() 
            ItemListFragment activity1 = new ItemListFragment();
            ArrayList<Item> arrayList = activity1.setArray(context);
            List<Item> list = new ArrayList<Item>();
            int i = 0;
            for (Item item : arrayList)
            
                list.add(arrayList.get(i));
                i++;
            
            activity1.arrayAdapter.addAll(list);
            activity1.arrayAdapter.notifyDataSetChanged();
        
    );

   

我正在尝试从执行后更新列表视图。那么,如何通过它更新视图。

来自 AsyncTask 的错误

只是以防万一你需要,但这不是问题

8-30 16:31:47.976    1167-1167/? E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.NullPointerException
        at np.com.thefourthgeneration.Update$1.run(Update.java:124)
        at android.app.Activity.runOnUiThread(Activity.java:4673)
        at np.com.thefourthgeneration.Update.onPostExecute(Update.java:108)
        at np.com.thefourthgeneration.Update.onPostExecute(Update.java:34)
        at android.os.AsyncTask.finish(AsyncTask.java:631)
        at android.os.AsyncTask.access$600(AsyncTask.java:177)
        at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:5103)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:525)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
        at dalvik.system.NativeStart.main(Native Method)

【问题讨论】:

你不需要在 onPostExecute 方法中编写 runOnUiThread,因为 onPostExecute 运行在主线程上。只需在 onPostExecute 中调用 notifyDataSetChanged。 notifDataSetChanged() 不适合你吗? 您要创建 ItemListFragment 的新实例是为了什么?几次创建 ArrayList?在哪里放置类更新 - 在活动中? Whats the problem - you cant 清除适配器,或者无法更新它或重新出现一些错误?提供更多代码并具体说明问题。 我会建议您阅读更多有关 android 后台服务的信息。 developer.android.com/reference/android/os/AsyncTask.html @umerk44 是的 notifyDataSetChanged() 方法不起作用。 【参考方案1】:

布局/活动列表

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_
        android:layout_/>
</LinearLayout>

layout/list_fragment

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

    <ListView
        android:id="@+id/listView"
        android:layout_
        android:layout_/>
</LinearLayout>

MainActivity

public class MainActivity extends AppCompatActivity

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

        FragmentManager fm = getFragmentManager();

        itemListFragment = (ItemListFragment) fm.findFragmentByTag(ItemListFragment.class.getSimpleName());
        if (itemListFragment == null) 
            itemListFragment = new ItemListFragment();
            FragmentTransaction fragmentTransaction = fm.beginTransaction();
            fragmentTransaction.replace(R.id.content_frame, itemListFragment, ItemListFragment.class.getSimpleName());
            fragmentTransaction.commit();
        
        if (BuildConfig.DEBUG) 
            ViewServer.get(this).addWindow(this);
        
    

    @Override
    protected void onDestroy() 
        super.onDestroy();
        if (BuildConfig.DEBUG) 
            ViewServer.get(this).removeWindow(this);
        
    

    @Override
    protected void onResume() 
        super.onResume();
        if (BuildConfig.DEBUG) 
            ViewServer.get(this).setFocusedWindow(this);
        
    

ItemListFragment

public class ItemListFragment extends Fragment

    private ListView listView;
    private ItemAdapter itemAdapter;
    private ArrayList<Item> itemArrayList = new ArrayList<>();

    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
        setHasOptionsMenu(true);
    

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
        View view = inflater.inflate(R.layout.list_fragment, container, false);
        itemAdapter = new ItemAdapter(getActivity(), itemArrayList);
        listView = (ListView) view.findViewById(R.id.listView);
        listView.setAdapter(itemAdapter);
        return view;
    

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) 
        inflater.inflate(R.menu.menu_main, menu);
    

    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
        switch (item.getItemId()) 
            case R.id.action_settings:
                return true;
            case R.id.update:
                new Update(getActivity()).execute();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        

    

    public class Update extends AsyncTask<Void, Void, Void>
    
        private Context context;

        public Update(Context context) 
            this.context = context;
        

        @Override
        protected Void doInBackground(Void... params) 
            ServerAddress = context.getString(R.string.ServerAddress);
            StringExtras = context.getString(R.string.CheckBook);
            Realm realm = null;
            try 
                URL url = new URL(ServerAddress + StringExtras);
                HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
                httpURLConnection.setRequestMethod("GET");
                httpURLConnection.setRequestProperty("Content-length", "0");
                httpURLConnection.setUseCaches(false);
                httpURLConnection.setAllowUserInteraction(false);
                httpURLConnection.setConnectTimeout(1000);
                httpURLConnection.setReadTimeout(1000);
                httpURLConnection.connect();

                int responseCode = httpURLConnection.getResponseCode();
                Log.i("Response Code", responseCode + "");

                BufferedReader br = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
                String InputLine;
                StringBuilder response = new StringBuilder();

                while ((InputLine = br.readLine()) != null) 
                    response.append(InputLine);
                
                br.close();
                httpURLConnection.disconnect();

                Log.i("Response Data", response.toString());

                GsonBuilder gsonBuilder = new GsonBuilder();
                Gson gson = gsonBuilder.create();

                JSONArray array = new JSONArray(response.toString());
                //booksList = Arrays.asList(books);
                //JSONArray jsonArray = object.getJSONArray("cover");

                realm = Realm.getInstance(context);
                for (int i = 0; i < array.length(); i++) 
                    JSONObject object = array.getJSONObject(i);
                    Books books = gson.fromJson(object.toString(), Books.class);
                    Publish(books, realm);
                
             catch (Exception e) 
                e.printStackTrace();
             finally 
                if (realm != null) 
                    realm.close();
                
            
            return null;
        

        @Override
        protected void onPostExecute(Void aVoid) 
            itemArrayList.clear();
            itemArrayList.addAll(getArray(context));
            itemAdapter.notifyDataSetChanged();
        

        public ArrayList<Item> getArray(Context context) 
            ArrayList<Item> items = new ArrayList<Item>();
            Realm realm = Realm.getInstance(context);
            RealmResults<Books> bs = realm.where(Books.class).findAll();
            for (int i = 0; i < bs.size(); i++) 
                Bitmap url = BitmapFactory.decodeFile(bs.get(i).getCover());
                String title = bs.get(i).getName();
                String description = bs.get(i).getAuthor();
                Item item = new Item(url, title, description);
                items.add(item);
            
            realm.close();
            return items;
        

    

    public class ItemAdapter extends ArrayAdapter<Item>
    

        public ItemAdapter(Context context, List<Item> items) 
            super(context, 0, items);
        

        public View getView(int position, View convertView, ViewGroup parent) 
            ItemView itemView = (ItemView) convertView;
            if (null == itemView) 
                itemView = ItemView.inflate(parent);
            
            itemView.setItem(getItem(position));
            return itemView;
        
    

它不是 100% 的工作代码,因为我不完全理解所有结构(如 Realm)并且我不测试它,但它是主要思想。

【讨论】:

您是如何访问itemArrayListclass ItemListFragmentprivate 的,您能解释一下吗? @ParadiN itemArrayList 它是 ItemListFragment 的私有成员,并且 ItemListFragment 具有 itemArrayList 的完全访问权限。我将所有代码移动到片段中 - 更新和适配器类放置在 ItemListFragment 中,并且还可以访问外部类(ItemListFragment)的私有成员。所以你不需要引用 Activity 或其他东西——所有工作都在 ItemListFragment 中执行。如果您需要访问其他片段中的 itemArrayList - 您可以通过 Activity 传输它 (itemArrayList)。 @Paladin 你试过这个代码吗?你试着去理解它吗?对你有帮助吗?如果您真的需要,我编写此代码来帮助您。不适合你,只是看着这个然后说“哦,无论如何......” 我有点忙于做其他事情,所以我没有尝试过。我明天会尽力回复你。

以上是关于从 AsyncTask 更新 setListAdapter的主要内容,如果未能解决你的问题,请参考以下文章

从两个不同的 AsyncTask 更新一个 ListView

从 AsyncTask 更新视图

重新创建活动时如何从 AsyncTask 更新 TextView

从 AsyncTask 滞后 UI 更新 ProgressBar

从 AsyncTask 更新 Activity 中的进度对话框

在 Android 中,如何从 AsyncTask 更改 TextView? [复制]