我有一个MainActivity
,它在ActionBar
上有两个选项卡。我对该活动的主要布局是一个空的FrameLayout
。第一个选项卡包含ProgressBar
,第二个选项卡包含开始下载文件的Button
。这是SettingsTab
:
public class SettingsTab extends Fragment {
private Button downloadButton;
private ImagesTab imagesTab;
private static String fileDir = "sdcard/AndroidCourse/";
public void downloadImages(String url,int limit,String imageExtension)
{
try {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectAll()
.build());
Document doc = Jsoup.connect(url).get();
StringBuilder sb = new StringBuilder("img[src$=.");
sb.append(imageExtension);
sb.append("]");
Elements images = doc.select(sb.toString());
ArrayList<String> urls = new ArrayList<String>();
for(Element image : images) {
if(urls.size() == limit) {
break;
}
urls.add(image.attr("src"));
}
Log.e("urls", String.valueOf(urls.size()));
imagesTab.downloadStarted(urls);
} catch (IOException e) {
Log.e("SettingsTab", e.getMessage());
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.settings_tab, null);
downloadButton = (Button) view.findViewById(R.id.startButton);
imagesTab = new ImagesTab();
downloadButton.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View v) {
downloadImages("http://www.google.com",5,"jpg");
}
});
return view;
}
}
和ImagesTab
:
public class ImagesTab extends Fragment {
ProgressBar downloadProgressBar;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.images_tab, null);
downloadProgressBar = (ProgressBar) view.findViewById(R.id.downloadProgressBar);
//downloadProgressBar.setVisibility(View.INVISIBLE);
return view;
}
public void downloadStarted(ArrayList<String> urls)
{
//downloadProgressBar.setVisibility(View.VISIBLE);
Intent intent = new Intent(getActivity(), DownloadService.class);
intent.putExtra("urls", urls);
intent.putExtra("receiver", new DownloadReceiver(new Handler()));
getActivity().startService(intent);
Toast.makeText(getActivity(), "Service started!" + urls.size(), Toast.LENGTH_SHORT).show();
}
private class DownloadReceiver extends ResultReceiver{
public DownloadReceiver(Handler handler) {
super(handler);
}
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
if (resultCode == DownloadService.UPDATE_PROGRESS) {
int progress = resultData.getInt("progress");
downloadProgressBar.setProgress(progress);
if (progress == 100) {
downloadProgressBar.setVisibility(View.INVISIBLE);
}
}
}
}
}
当我单击StartDownloadButton
时,应用程序崩溃,出现以下异常:
11-26 03:55:55.765: E/AndroidRuntime(21200): FATAL EXCEPTION: main
11-26 03:55:55.765: E/AndroidRuntime(21200): java.lang.NullPointerException
11-26 03:55:55.765: E/AndroidRuntime(21200): at android.content.ComponentName.<init>(ComponentName.java:75)
11-26 03:55:55.765: E/AndroidRuntime(21200): at android.content.Intent.<init>(Intent.java:3227)
11-26 03:55:55.765: E/AndroidRuntime(21200): at com.example.lista2.ImagesTab.downloadStarted(ImagesTab.java:32)
11-26 03:55:55.765: E/AndroidRuntime(21200): at com.example.lista2.SettingsTab.downloadImages(SettingsTab.java:55)
11-26 03:55:55.765: E/AndroidRuntime(21200): at com.example.lista2.SettingsTab$1.onClick(SettingsTab.java:72)
有人知道如何在应用程序的不同部分更改ProgressBar
的进度吗?
代码中的主要问题,以及NullPointerException
的原因是行:
imagesTab = new ImagesTab();
在其中实例化一个新的ImagesTab
Fragment
。问题是这个新的Fragment
实例没有绑定到Activity
(它在"空中"),所以它的getActivity()
方法返回null
。getActivity()
方法中的这个null
值传递给在downloadStarted()
方法中构建的Intent
,后者将抛出NulPointerException
。与其像您那样实例化ImgesTab
,不如通过使用getFragmentManager()
并基于其标记搜索片段来获得对父活动中已经(很可能)存在的另一个片段的引用。
其次,更新ProgressBar
似乎更像是一个应用程序设计问题。例如,为什么在一个选项卡中有启动下载的Button
,而在另一个选项卡上有显示下载进度的ProgressBar
?此外,您似乎使用Service
进行下载,因此与其让选项卡进行通信,不如让下载文件的Service
和所需的选项卡片段(与ProgressBar
)进行通信。这可以通过使Service
在特定下载级别上成为发送广播,并使您的Activity
(包含两个选项卡片段)动态注册BroadcastReceiver
来实现。当Service
发送广播(例如10%)时,Activity
的BroadcastReceiver
将接收它(如果它是活动的),然后如果Fragment
在那一刻可见,它将从所需的Fragment
更新ProgressBar
。